2.自定义控件——loding小球

来源:互联网 发布:网络教育有学位证吗 编辑:程序博客网 时间:2024/06/04 23:21

以下为参照博客    http://blog.csdn.net/guimianhao9833/article/details/74858472 


首先看下效果图:

步骤:
1.继承view,并需要三个构造函数。
public MyView(Context context) {    //注意不要默认实现,记得修改。    this(context, null);}public MyView(Context context, AttributeSet attrs) {    //注意不要默认实现,记得修改。    this(context, attrs, 0);}public MyView(Context context, AttributeSet attrs, int defStyleAttr) {    super(context, attrs, defStyleAttr);    //初始化工作    init(context, attrs);}
初始化工作init:
                    1)在attrs.xml中定义控件需要的属性
<?xml version="1.0" encoding="utf-8"?><resources>    <declare-styleable name="MyView">        <attr name="color" format="color"/>        <attr name="text" format="string"/>    </declare-styleable></resources>
                    2)自定义控件一般都需要定义相关的属性,我们获取它并对它进行相关的设置;
                       由效果图可知,这个自定义控件需要定义一个画笔用来画图形路径;
                        需要定义一个画笔用来画文字;
                        需要Path用来定义闭合波浪路径;
                        为了实现控件无线循环的动画效果,需要对其进行相关的监听动作并实时刷新。
private void init(Context context, AttributeSet attrs) {    //1.定义需要的属性    TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MyView);    //颜色和文字    color = a.getColor(R.styleable.MyView_color, Color.rgb(238,121,66));    text = a.getString(R.styleable.MyView_text);    //记得调用这个方法回收    a.recycle();    //2.1定义图形及路径填充画笔的相关值(抗锯齿、填充、防抖动)    mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);    mPaint.setStyle(Paint.Style.FILL);    mPaint.setColor(color);    mPaint.setDither(true);    //2.2定义文字画笔的相关值(抗锯齿、白色、粗体)    textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);    textPaint.setColor(Color.WHITE);    textPaint.setTypeface(Typeface.DEFAULT_BOLD);    //2.3定义闭合波浪路径    path = new Path();    //3.实现无线循环的动画效果    //ValueAnimator定时器,属性动画ObjectAnimator就是它的一个子类    ValueAnimator animator = ValueAnimator.ofFloat(0, 1);    //让动画无限重复,每次从头开始,一个周期1000毫秒    animator.setDuration(1000);    animator.setRepeatCount(ValueAnimator.INFINITE);    animator.setRepeatMode(ValueAnimator.RESTART);    //补上一个线性插值器,使得动画流畅    animator.setInterpolator(new LinearInterpolator());    //监听获得过程值,实时进行刷新    animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {        @Override        public void onAnimationUpdate(ValueAnimator animation) {            currentPercent = animation.getAnimatedFraction();            //刷新            invalidate();        }    });    //动画开始    animator.start();}
 2.onDraw方法,重中之重!
绘制流程:

 
1)绘制底部蓝色的文字
2)绘制闭合的波浪路径,颜色为蓝色
3)绘制白色的文字
4)根据已有的波浪路径去裁剪文字,使得文字上半部门为蓝色,文字下半部门为白色
      (因为先绘制在下部,后绘制的在上部)
5)在已有的画布canvas上画一个圆,也就是裁剪成圆形
@Overrideprotected void onDraw(Canvas canvas) {    //super.onDraw(canvas);    //1.画底部蓝色的字    textPaint.setColor(color);    drawCenterText(canvas, textPaint, "");    //2.画上层白色的字    textPaint.setColor(Color.WHITE);    //3.生成闭合波浪路径    path = getActionPath(currentPercent);    //4.剪裁文字    canvas.clipPath(path);    //5.剪裁成圆形(SRC 源像素)    canvas.drawCircle(mWidth / 2, mHeight / 2, mWidth / 2, mPaint);    mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));    //6.画波浪(DST 目标像素)    canvas.drawPath(path, mPaint);    mPaint.setXfermode(null);    drawCenterText(canvas, textPaint, "");}
生成闭合的波浪路径的方法getActionPath:
                这个波浪可以由二阶贝塞尔曲线。如下的例子,起点为(100,100),然后移动相对于起点的两个位置变化为(150,0),(200,100)。
Path path=new Path();path.moveTo(100,100);path.rQuadTo(50,-100,100,0);
            图解:

 
1)画两个周期的波浪
2)画右侧的直线
3)画下边的直线
private Path getActionPath(float percent) {    Path path = new Path();    int x = -mWidth;    //1.当前x点坐标(根据动画进度水平推移,一个动画周期推移的距离为一个mWidth    x += percent * mWidth;    //2.波形的起点    path.moveTo(x, mHeight / 2);    //控制点的相对宽度    int kongzhiWidth = mWidth / 4;    //控制点的相对高度=mHeight的二十分之3    int kongzhiHeight = mHeight / 20 * 3;    //3.画第一个周期,一个周期为一上一下    path.rQuadTo(kongzhiWidth, kongzhiHeight, kongzhiWidth * 2, 0);    path.rQuadTo(kongzhiWidth, -kongzhiHeight, kongzhiWidth * 2, 0);    //画第二个周期,如此循环下去    path.rQuadTo(kongzhiWidth, kongzhiHeight, kongzhiWidth * 2, 0);    path.rQuadTo(kongzhiWidth, -kongzhiHeight, kongzhiWidth * 2, 0);    //4.画右侧的直线    path.lineTo(x + mWidth * 2, mHeight);    //5.画下边的直线    path.lineTo(x, mHeight);    //自动闭合补出左边的直线    path.close();    return path;}
   画中间的文字drawCenterText:
private void drawCenterText(Canvas canvas, Paint textPaint, String text) {    //画一个规定位置的矩形    Rect rect = new Rect(0, 0, mWidth, mHeight);    //由于默认是位于左边的,所以这样设置到中间来。    textPaint.setTextAlign(Paint.Align.CENTER);    Paint.FontMetrics fontMetrics = textPaint.getFontMetrics();    float top = fontMetrics.top;    float bottom = fontMetrics.bottom;    int centerY = (int) (rect.centerY() - top / 2 - bottom / 2);    canvas.drawText(text, rect.centerX(), centerY, textPaint);}
3.onMeasure方法
@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {    int widthSize = MeasureSpec.getSize(widthMeasureSpec);    int widthMode = MeasureSpec.getMode(widthMeasureSpec);    int heightSize = MeasureSpec.getSize(heightMeasureSpec);    int heightMode = MeasureSpec.getMode(heightMeasureSpec);    if (widthMode == MeasureSpec.EXACTLY) {        mWidth = widthSize;    }    if (heightMode == MeasureSpec.EXACTLY) {        mHeight = heightSize;    }    setMeasuredDimension(mWidth, mHeight);    textSize = mWidth / 2;    textPaint.setTextSize(textSize);}
自定义控件,要好好学哦。
阅读全文
0 0
原创粉丝点击