Android自定义View之仿微信小视频加载进度条

请尊重个人劳动成果,转载注明出处,谢谢!
http://blog.csdn.net/xiaxiazaizai01/article/details/52442300

自定义View我也写了好几篇了,今天那就再来一篇,主要的技术点在前几篇都详细介绍过,不明真相的吃瓜群众该吐槽小编了,能不能写一些风格尺度相对大点的,哈哈。。。小编目前处于学习阶段,跟大牛比还有很大很大很大。。。你们无形中戳到了小编的痛点,然。。咱也是在一点一点积累的。一直以来小编都有一个疑问始终不明白,为啥每次开头都要说半天废话呢。。估计是小编觉着这样才不会显得太low吧,哈哈,言归正传,今天我们要实现的效果就是仿微信小视频加载时与用户交互的那个圆形加载效果。老规矩,先来张效果图

这里写图片描述

上面已经说过了,其实实现这样的效果并不难,主要的技术点在前面几篇博客中已经详细的说明了,想更好的理解小编的思路,请查看之前的几篇自定义view相关的内容。本篇博客就不再详细注释了,相信只要你看过之前的几篇,这一篇读起来肯定相当轻松,因为本篇相对于之前写的还算简单一点的。

首先创建view

(1)自定义属性

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="CustomCircleLoading">
        <attr name="outer_layout_circle_color" format="color"/>
        <attr name="outer_layout_circle_stroke_width" format="dimension"/>
        <attr name="triangle_color" format="color"/>
        <attr name="radius" format="dimension"/>
    </declare-styleable>
</resources>

(2)获取我们的自定义属性

public CustomCircleLoading(Context context) {
        this(context,null);
    }

    public CustomCircleLoading(Context context, AttributeSet attrs) {
        this(context, attrs,0);
    }

    public CustomCircleLoading(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        //获取自定义属性
        TypedArray array = getContext().obtainStyledAttributes(attrs, R.styleable.CustomCircleLoading);
        int indexCount = array.getIndexCount();
        for(int i = 0;i < indexCount;i++){
            int attr = array.getIndex(i);
            switch (attr){
                case R.styleable.CustomCircleLoading_outer_layout_circle_color:
                    outerCircleColor = array.getColor(attr, OUTER_LAYOUT_CIRCLE_COLOR);
                    break;
                case R.styleable.CustomCircleLoading_outer_layout_circle_stroke_width:
                    outerCircleStrokeWidth = (int) array.getDimension(attr, outerCircleStrokeWidth);
                    break;
                case R.styleable.CustomCircleLoading_triangle_color:
                    mTriangleColor = array.getColor(attr, mTriangleColor);
                    break;
                case R.styleable.CustomCircleLoading_radius:
                    mRadius = (int) array.getDimension(attr, mRadius);
                    break;
            }
        }
        //回收
        array.recycle();

        mDistance = (float) (mRadius * 0.06);
        mTriangleLength = mRadius;
        //设置画笔
        setPaint();
        //画三角形
        mPath = new Path();
        float mFirstPointX = (float) (mRadius - Math.sqrt(3.0) / 4 * mRadius);//勾股定理
        float mNiceFirstPointX = (float) (mFirstPointX + mFirstPointX * 0.2);
        float mFirstPointY = mRadius - mTriangleLength / 2;
        mPath.moveTo(mNiceFirstPointX,mFirstPointY);
        mPath.lineTo(mNiceFirstPointX, mRadius+mTriangleLength / 2);
        mPath.lineTo((float) (mNiceFirstPointX+Math.sqrt(3.0) / 2 * mRadius), mRadius);
        mPath.lineTo(mNiceFirstPointX, mFirstPointY);
    }

测量View,即onMeasure( )

 @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int width;
        int height;
        if(widthMode != MeasureSpec.EXACTLY){
            width = getPaddingLeft() + mRadius*2 + outerCircleStrokeWidth*2 + getPaddingRight();
            widthMeasureSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
        }
        if(heightMode != MeasureSpec.EXACTLY){
            height = getPaddingTop() + mRadius*2 + outerCircleStrokeWidth*2 + getPaddingBottom();
           heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
        }
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

绘制View,即onDraw()

@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        canvas.save();
        canvas.translate(getPaddingLeft(),getPaddingTop());
        //画圆
        canvas.drawCircle(mRadius,mRadius,mRadius,outerCirclePaint);

        if(mStatus == Status.End){
            //画三角形
            canvas.drawPath(mPath, mTrianglePaint);
        }else{//正在进行状态
            //画扇形
            canvas.drawArc(new RectF(0 + mDistance,0 + mDistance,mRadius*2 - mDistance,mRadius*2 - mDistance), -90, 360*mArcAngle, true, mArcPaint);
        }

        canvas.restore();
    }

接下来就是与用户的交互

我们用属性动画来实现模拟扇形的加载数据

public void animatorAngle(){
        setClickable(false);
        ValueAnimator animator = ValueAnimator.ofFloat(0, 1.0f);
        animator.setDuration(6000);
        animator.setInterpolator(new LinearInterpolator());
        animator.setRepeatCount(0);
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mArcAngle = (float) animation.getAnimatedValue();
                //刷新View
                invalidate();
            }
        });
        //开启动画
        animator.start();
        animator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {

            }

            @Override
            public void onAnimationEnd(Animator animation) {
                //动画结束后修改状态变化
                mStatus = Status.End;
                setClickable(true);
            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });
    }

最后是我们的MainActivity去调用

public class MainActivity extends AppCompatActivity {

    private CustomCircleLoading circleLoading;

    private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            if(msg.what == MESSAGE_SUCCESS){
                circleLoading.animatorAngle();
            }
        }
    };
    public static final int MESSAGE_SUCCESS = 2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        circleLoading = (CustomCircleLoading) findViewById(R.id.circleLoading);
        circleLoading.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(circleLoading.getStatus() == CustomCircleLoading.Status.End){
                    circleLoading.setStatus(CustomCircleLoading.Status.Starting);
                    Message message = Message.obtain();
                    message.what = MESSAGE_SUCCESS;
                    handler.sendMessage(message);
                }else{
                    circleLoading.setStatus(CustomCircleLoading.Status.End);
                    handler.removeMessages(MESSAGE_SUCCESS);
                }

            }
        });

    }
}

最后,如果你有什么疑问,欢迎留言,希望能对你有所帮助,有需要源码的,请点击下载源码

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章