Android自定义View贝塞尔曲线最佳实现

来源:互联网 发布:linux mount命令nfs 编辑:程序博客网 时间:2024/04/28 13:12

先看一下效果图


主要是通过贝塞尔曲线去控制绳子的绘制,就直接上代码了


package yuekong.com.progressview;import android.animation.Animator;import android.animation.AnimatorSet;import android.animation.ValueAnimator;import android.content.Context;import android.graphics.Canvas;import android.graphics.Paint;import android.graphics.Path;import android.util.AttributeSet;import android.util.TypedValue;import android.view.SurfaceHolder;import android.view.SurfaceView;import android.view.animation.DecelerateInterpolator;/** * Created by Zhongqi.Shao on 2017/1/17. */public class ProgressView extends SurfaceView implements SurfaceHolder.Callback {    private final int STATE_DOWN = 1;    private final int STATE_UP = 2;    private Context mContext;    private Path mPath;    //中间绳子的Paint    private Paint mPaint;    private Paint mCirclePaint;    //向下运动    private ValueAnimator mDownAnimator;    //向上运动    private ValueAnimator mUpAnimator;    //从上至下 自由落体运动    private ValueAnimator mFreeAnimator;    private AnimatorSet mAnimationSet;    private boolean isAnimationShowing = false;    //中间绳子的高度    private float mLineHeigth;    //中间绳子的宽度    private float mLineWidth;    //向下运动的距离    private float mDownDistance = 0f;    //向上运动的距离    private float mUpDistance = 0f;    //自由落体运动的距离    private float mFreeDistance = 0f;    private int mState = STATE_DOWN;    private boolean mIsBounced = false;    public ProgressView(Context context) {        this(context, null);        mContext = context;    }    public ProgressView(Context context, AttributeSet attrs) {        this(context, attrs, 0);        mContext = context;    }    public ProgressView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        mContext = context;        init();    }    private void init() {        mLineHeigth = dp2px(3);        mLineWidth = dp2px(100);        mPaint = new Paint();        mPaint.setAntiAlias(true);        mPaint.setStyle(Paint.Style.STROKE);        mPaint.setStrokeWidth(mLineHeigth);        //圆形线帽        mPaint.setStrokeCap(Paint.Cap.ROUND);        mPaint.setColor(getContext().getResources().getColor(R.color.auto_yellow));        mCirclePaint = new Paint();        mCirclePaint.setAntiAlias(true);        mCirclePaint.setColor(mContext.getResources().getColor(R.color.black));        mCirclePaint.setStyle(Paint.Style.FILL);        mPath = new Path();        SurfaceHolder holder = getHolder();        holder.addCallback(this);        initAnimator();    }    private void initAnimator() {        mDownAnimator = ValueAnimator.ofFloat(0, 1);        mDownAnimator.setDuration(500);        mDownAnimator.setInterpolator(new DecelerateInterpolator());        mDownAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {            @Override            public void onAnimationUpdate(ValueAnimator valueAnimator) {                mDownDistance = (float) valueAnimator.getAnimatedValue() * 50;                postInvalidate();            }        });        mDownAnimator.addListener(new Animator.AnimatorListener() {            @Override            public void onAnimationStart(Animator animator) {                mState = STATE_DOWN;            }            @Override            public void onAnimationEnd(Animator animator) {            }            @Override            public void onAnimationCancel(Animator animator) {            }            @Override            public void onAnimationRepeat(Animator animator) {            }        });        mUpAnimator = ValueAnimator.ofFloat(0, 1);        mUpAnimator.setDuration(900);        mUpAnimator.setInterpolator(new DecelerateInterpolator());        mUpAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {            @Override            public void onAnimationUpdate(ValueAnimator valueAnimator) {                mUpDistance = (float) valueAnimator.getAnimatedValue() * 50;                if (mUpDistance >= 50) {                    //进入自由落体                    mIsBounced = true;                    if (!mFreeAnimator.isRunning()) {                        mFreeAnimator.start();                    }                }                postInvalidate();            }        });        mUpAnimator.addListener(new Animator.AnimatorListener() {            @Override            public void onAnimationStart(Animator animator) {                mState = STATE_UP;            }            @Override            public void onAnimationEnd(Animator animator) {            }            @Override            public void onAnimationCancel(Animator animator) {            }            @Override            public void onAnimationRepeat(Animator animator) {            }        });        mFreeAnimator = ValueAnimator.ofFloat(0, 6.8f);        mFreeAnimator.setDuration(900);        mFreeAnimator.setInterpolator(new DecelerateInterpolator());        mFreeAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {            @Override            public void onAnimationUpdate(ValueAnimator valueAnimator) {                float t = (float) valueAnimator.getAnimatedValue();                mFreeDistance = 34 * t - 5 * t * t;                postInvalidate();            }        });        mFreeAnimator.addListener(new Animator.AnimatorListener() {            @Override            public void onAnimationStart(Animator animator) {                mIsBounced = true;            }            @Override            public void onAnimationEnd(Animator animator) {                isAnimationShowing = false;                //执行第二次动画                startAllAnimator();            }            @Override            public void onAnimationCancel(Animator animator) {            }            @Override            public void onAnimationRepeat(Animator animator) {            }        });        mAnimationSet = new AnimatorSet();        mAnimationSet.play(mDownAnimator).before(mUpAnimator);        mAnimationSet.addListener(new Animator.AnimatorListener() {            @Override            public void onAnimationStart(Animator animator) {                isAnimationShowing = true;            }            @Override            public void onAnimationEnd(Animator animator) {            }            @Override            public void onAnimationCancel(Animator animator) {            }            @Override            public void onAnimationRepeat(Animator animator) {            }        });    }    public void startAllAnimator() {        if (isAnimationShowing) {            return;        }        if (mAnimationSet.isRunning()) {            mAnimationSet.end();            mAnimationSet.cancel();        }        mIsBounced = false;        mAnimationSet.start();    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        /*        * 中间绳子分成左右两个二阶贝塞尔曲线绘制        * */        mPath.reset();        mPath.moveTo(getWidth() / 2 - mLineWidth / 2, getHeight() / 2);        if (mState == STATE_DOWN) {            //向下运动            //左边的贝塞尔            mPath.quadTo((float) (getWidth() / 2 - mLineWidth / 2 + mLineWidth * 0.375), getHeight() / 2 + mDownDistance, getWidth() / 2, getHeight() / 2 + mDownDistance);            //右边的贝塞尔            mPath.quadTo((float) (getWidth() / 2 + mLineWidth / 2 - mLineWidth * 0.375), getHeight() / 2 + mDownDistance, getWidth() / 2 + mLineWidth / 2, getHeight() / 2);            canvas.drawPath(mPath, mPaint);            //绘制小球            canvas.drawCircle(getWidth() / 2, getHeight() / 2 + mDownDistance - 10, 10, mCirclePaint);        } else if (mState == STATE_UP) {            //向上运动            //左边的贝塞尔            mPath.quadTo((float) (getWidth() / 2 - mLineWidth / 2 + mLineWidth * 0.375), getHeight() / 2 + (50 - mUpDistance), getWidth() / 2, getHeight() / 2 + (50 - mUpDistance));            //右边的贝塞尔            mPath.quadTo((float) (getWidth() / 2 + mLineWidth / 2 - mLineWidth * 0.375), getHeight() / 2 + (50 - mUpDistance), getWidth() / 2 + mLineWidth / 2, getHeight() / 2);            canvas.drawPath(mPath, mPaint);            //第三种状态  最大运动长度设置为50 半径为10            if (!mIsBounced) {                //正常向上运动                canvas.drawCircle(getWidth() / 2, getHeight() / 2 + (50 - mUpDistance) - 10, 10, mCirclePaint);            } else {                //自由落体状态                canvas.drawCircle(getWidth() / 2, getHeight() / 2 - mFreeDistance - 10, 10, mCirclePaint);            }        }        //绘制两边固定的小圆        //两边小球的颜色        canvas.drawCircle(getWidth() / 2 - mLineWidth / 2, getHeight() / 2, 10, mCirclePaint);        canvas.drawCircle(getWidth() / 2 + mLineWidth / 2, getHeight() / 2, 10, mCirclePaint);    }    @Override    public void surfaceCreated(SurfaceHolder surfaceHolder) {        //锁住画布        Canvas canvas = surfaceHolder.lockCanvas();        //开始绘制        draw(canvas);        surfaceHolder.unlockCanvasAndPost(canvas);    }    @Override    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {    }    @Override    public void surfaceDestroyed(SurfaceHolder surfaceHolder) {    }    private int dp2px(int dp) {        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics());    }    private int sp2px(int sp) {        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, getResources().getDisplayMetrics());    }}





0 0
原创粉丝点击