Android自定义View阻尼动画&贝塞尔曲线的实现

来源:互联网 发布:java常用api 编辑:程序博客网 时间:2024/04/29 02:41
效果图:
直接上代码啦:
package com.example.administrator.myapplication.customview;import android.animation.Animator;import android.animation.AnimatorSet;import android.animation.ObjectAnimator;import android.animation.PropertyValuesHolder;import android.content.Context;import android.content.res.TypedArray;import android.graphics.Path;import android.graphics.PointF;import android.graphics.drawable.GradientDrawable;import android.util.AttributeSet;import android.util.TypedValue;import android.view.Gravity;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.view.animation.AccelerateDecelerateInterpolator;import android.widget.LinearLayout;import android.widget.RelativeLayout;import com.example.administrator.myapplication.R;import java.util.ArrayList;import java.util.List;/** * Created by Administrator on 2016/9/14. */public class AnimationView extends RelativeLayout {    private final int SMALL_CIRCLE_RADIS = dp2px(20);    private final int LARGE_CIRCLE_RADIS = dp2px(25);    private final int OUT_CIRCLE_RADIS = dp2px(50);    private final int TYPE_SMALL = 0x01;    private final int TYPE_LARGE = 0x02;    private final int TYPE_OUTER = 0x03;    private Context mContext;    //小圆圈颜色    private int mSmallCircleColor;    //大圆圈颜色    private int mLargeCircleColor;    //外圆圈颜色    private int mOutCircleColor;    //动画    private AnimatorSet mAimationSet;    private PropertyValuesHolder mValueScaleX;    private PropertyValuesHolder mValueScaleY;    private PropertyValuesHolder mValuesScale;    //小圆移动路径    private Path mCirclePath;    private LinearLayout mCircleContainer;    private CircleView mOutCircleView;    private CircleView mSmallCircleView;    private CircleView mLargeCircleView;    private List<CircleView> mCircleViews;    //当前默认的位置    private int mFocusPosition;    private int mCount;    public AnimationView(Context context) {        this(context, null);        mContext = context;    }    public AnimationView(Context context, AttributeSet attrs) {        this(context, attrs, 0);        mContext = context;    }    public AnimationView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        mContext = context;        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.AnimationView);        mSmallCircleColor = ta.getColor(R.styleable.AnimationView_smallCircleColor, getResources().getColor(R.color.colorAccent));        mLargeCircleColor = ta.getColor(R.styleable.AnimationView_largeCircleColor, getResources().getColor(R.color.colorPrimary));        mOutCircleColor = ta.getColor(R.styleable.AnimationView_outCircleColor, getResources().getColor(android.R.color.holo_orange_light));        ta.recycle();        //初始化布局        View rootView = LayoutInflater.from(getContext()).inflate(R.layout.bg_animationview, this);        mCircleContainer = (LinearLayout) rootView.findViewById(R.id.ll_container);        mOutCircleView = (CircleView) rootView.findViewById(R.id.out_circle2);        mOutCircleView.setRadis(OUT_CIRCLE_RADIS);        //设置背景大圆颜色        View containerWrapper = rootView.findViewById(R.id.wrapper);        mOutCircleView.setColor(mOutCircleColor);        GradientDrawable shape = (GradientDrawable) containerWrapper.getBackground();        shape.setColor(mOutCircleColor);        mValueScaleX = PropertyValuesHolder.ofFloat("scaleX", 1, 0.8f, 1);        mValueScaleY = PropertyValuesHolder.ofFloat("scaleY", 1, 0.8f, 1);        mValuesScale = PropertyValuesHolder.ofFloat("scaleY", 1, 0.5f, 1);        mCirclePath = new Path();        mCircleViews = new ArrayList<CircleView>();    }    @Override    protected void onLayout(boolean changed, int l, int t, int r, int b) {        super.onLayout(changed, l, t, r, b);        mLargeCircleView = mCircleViews.get(mFocusPosition);        mOutCircleView.setCenter(mLargeCircleView.getCenter());    }    public void setCount(int count, int focus) {        if (count < 2) {            return;        }        if (focus > count || focus < 0) {            return;        }        mFocusPosition = focus;        mCount = count;        /** 1:创建圆         * 2:往linearlayout动态添加圆         * */        mCircleContainer.removeAllViews();        mCircleViews.clear();        //左边放小圆        for (int i = 0; i < focus; i++) {            addSmallCircle();        }        //中间大圆        addLargeCircle();        //右边小圆        for (int i = focus + 1; i < count; i++) {            addSmallCircle();        }    }    private void addLargeCircle() {        CircleView largeCircle = CreateCircle(TYPE_LARGE);        mCircleViews.add(largeCircle);        mCircleContainer.addView(largeCircle);    }    private void addSmallCircle() {        CircleView smallCircle = CreateCircle(TYPE_SMALL);        mCircleViews.add(smallCircle);        mCircleContainer.addView(smallCircle);    }    public void moveRight() {        if (mAimationSet != null && mAimationSet.isRunning()) {            return;        }        move(true);    }    public void moveLeft() {        if (mAimationSet != null && mAimationSet.isRunning()) {            return;        }        move(false);    }    private void move(boolean toRight) {        mLargeCircleView = mCircleViews.get(mFocusPosition);        final int nextPos = getNextPosition(toRight);        if (nextPos < 0) {            return;        }        mSmallCircleView = mCircleViews.get(nextPos);        //计算移动        float largeCircleX = toRight ? mSmallCircleView.getX() - (mLargeCircleView.getWidth() - mSmallCircleView.getWidth()) : mSmallCircleView.getX();        float smallCircleX = toRight ? mLargeCircleView.getX() : mLargeCircleView.getX() + (mLargeCircleView.getWidth() - mSmallCircleView.getWidth());        float outCircleX = toRight ? mSmallCircleView.getX() - (mOutCircleView.getWidth() - mSmallCircleView.getWidth()) : mSmallCircleView.getX();        //l argeCircleView动画 X平移 XY缩放        PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("X", mLargeCircleView.getX(), largeCircleX);        ObjectAnimator largeCircleAnim = ObjectAnimator.ofPropertyValuesHolder(mLargeCircleView, pvhX, mValueScaleX, mValueScaleY);        //2 outCircleView动画 X平移 XY缩放        pvhX = PropertyValuesHolder.ofFloat("X", mOutCircleView.getX(), outCircleX);        ObjectAnimator outCircleAnim = ObjectAnimator.ofPropertyValuesHolder(mOutCircleView, pvhX, mValueScaleX, mValueScaleY);        //3 smallCircleView动画 XY缩放 Path移动        PointF center = mSmallCircleView.getCenter();        PointF endCenter = new PointF(center.x - (mSmallCircleView.getX() - smallCircleX), center.y);        mCirclePath.reset();        mCirclePath.moveTo(center.x, center.y);        //贝塞尔曲线        mCirclePath.quadTo((center.x + endCenter.x) / 2, (center.y + endCenter.y) / 2 + 1.5f * dp2px(30), endCenter.x, endCenter.y);        ObjectAnimator smallCircleAnim = ObjectAnimator.ofObject(mSmallCircleView, "Center", null, mCirclePath);        ObjectAnimator smallCircleAnim2 = ObjectAnimator.ofPropertyValuesHolder(mSmallCircleView, mValuesScale);        mAimationSet = new AnimatorSet();        mAimationSet.play(largeCircleAnim).with(outCircleAnim).with(smallCircleAnim).with(smallCircleAnim2);        mAimationSet.setInterpolator(new AccelerateDecelerateInterpolator());        mAimationSet.setDuration(1000);        mAimationSet.addListener(new Animator.AnimatorListener() {            @Override            public void onAnimationStart(Animator animation) {            }            @Override            public void onAnimationEnd(Animator animation) {                swapCircle(mFocusPosition, nextPos);                mFocusPosition = nextPos;            }            @Override            public void onAnimationCancel(Animator animation) {            }            @Override            public void onAnimationRepeat(Animator animation) {            }        });        mAimationSet.start();    }    void swapCircle(int position1, int position2) {        CircleView tmp = mCircleViews.get(position1);        mCircleViews.set(position1, mCircleViews.get(position2));        mCircleViews.set(position2, tmp);    }    private int getNextPosition(boolean toRight) {        int next = mFocusPosition;        if (toRight) {            next = next + 1;        } else {            next = next - 1;        }        if (next < 0 || next >= mCount) {            next = -1;        }        return next;    }    private CircleView CreateCircle(int type) {        CircleView circle = new CircleView(mContext);        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);        params.weight = 1;        params.gravity = Gravity.CENTER_VERTICAL;        switch (type) {            case TYPE_SMALL:                params.height = params.width = SMALL_CIRCLE_RADIS * 2;                circle.setColor(mSmallCircleColor);                circle.setRadis(SMALL_CIRCLE_RADIS);                break;            case TYPE_LARGE:                params.height = params.width = LARGE_CIRCLE_RADIS * 2;                circle.setColor(mLargeCircleColor);                circle.setRadis(LARGE_CIRCLE_RADIS);                break;            case TYPE_OUTER:                params.height = params.width = OUT_CIRCLE_RADIS * 2;                circle.setColor(mOutCircleColor);                circle.setRadis(OUT_CIRCLE_RADIS);                break;            default:                break;        }        circle.setLayoutParams(params);        return circle;    }    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());    }}


package com.example.administrator.myapplication.customview;import android.content.Context;import android.graphics.Canvas;import android.graphics.Paint;import android.graphics.PointF;import android.util.AttributeSet;import android.view.View;/** * Created by Administrator on 2016/9/14. */public class CircleView extends View {    private Context mContext;    private int mCircleColor;    private float mCircleRadis;    private float mCenterX;    private float mCenterY;    private int mWidth;    private int mHeight;    private Paint mCirclePaint;    public CircleView(Context context) {        this(context, null);        mContext = context;    }    public CircleView(Context context, AttributeSet attrs) {        this(context, attrs, 0);        mContext = context;    }    public CircleView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        mContext = context;        initPaint();    }    private void initPaint() {        mCirclePaint = new Paint();        mCirclePaint.setAntiAlias(true);        mCirclePaint.setStyle(Paint.Style.FILL_AND_STROKE);        mCirclePaint.setStrokeWidth(1);        mCirclePaint.setColor(mCircleColor);    }    @Override    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {        super.onLayout(changed, left, top, right, bottom);        mCenterX = (right - left) / 2;        mCenterY = (bottom - top) / 2;        mCircleRadis = Math.min(mCenterX, mCenterY);    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        canvas.drawCircle(mCenterX, mCenterY, mCircleRadis - 5, mCirclePaint);    }    public void setColor(int color) {        mCirclePaint.setColor(color);        invalidate();    }    public void setRadis(float radis) {        mCircleRadis = radis;        invalidate();    }    //那中心点    public PointF getCenter() {        return new PointF(getX() + getWidth() / 2, getY() + getHeight() / 2);    }    public void setCenter(float cx, float cy) {        setX(cx - getWidth() / 2);        setY(cy - getHeight() / 2);    }    public void setCenter(PointF point) {        setCenter(point.x, point.y);        postInvalidate();    }    public float getRadis() {        return mCircleRadis;    }}


                                             
0 0
原创粉丝点击