效果图:
直接上代码啦:
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