http://blog.csdn.net/L_wwbs/article/details/53408830
本篇通过自定义View模拟一个物理现象——竖直平面内小球在最低点以一定初速度在重力作用下绕圆环做变速圆周运动的效果(从最低点减速到0时上升到最高点再加速到初始速度时回到最低点)。可以用于加载等待等场景,下面按照自定义View的步骤具体说明一下。
1、定义属性
为了能在布局文件中使用我们的自定义控件,定制其属性,我们需要自定义一些控件的属性,以供更灵活的使用此控件。
- <?xml version="1.0" encoding="utf-8"?>
- <resources>
- <attr name="ringColor" format="color"></attr>
- <attr name="ringWidth" format="dimension"></attr>
- <attr name="globuleColor" format="color"></attr>
- <attr name="globuleRadius" format="dimension"></attr>
- <attr name="cycleTime" format="float"></attr>
- <declare-styleable name="AccelerateCircularView">
- <attr name="ringColor" />
- <attr name="ringWidth" />
- <attr name="globuleColor" />
- <attr name="globuleRadius" />
- <attr name="cycleTime" />
- </declare-styleable>
- </resources>
-
2、获取属性
自定义属性完成后,我们需要在自定义View的构造方法中逐一获取这些属性。- public AccelerateCircularView(Context context) {
- this(context, null);
- }
- public AccelerateCircularView(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
- public AccelerateCircularView(Context context, AttributeSet attrs,
- int defStyle) {
- super(context, attrs, defStyle);
- TypedArray attrsArray = context.getTheme().obtainStyledAttributes(
- attrs, R.styleable.AccelerateCircularView, defStyle, 0);
- mRingColor = attrsArray.getColor(
- R.styleable.AccelerateCircularView_ringColor, Color.GRAY);
- mGlobuleColor = attrsArray.getColor(
- R.styleable.AccelerateCircularView_globuleColor, Color.BLUE);
- mRingWidth = attrsArray.getDimension(
- R.styleable.AccelerateCircularView_ringWidth, TypedValue
- .applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1,
- getResources().getDisplayMetrics()));
- mGlobuleRadius = attrsArray.getDimension(
- R.styleable.AccelerateCircularView_globuleRadius, TypedValue
- .applyDimension(TypedValue.COMPLEX_UNIT_DIP, 6,
- getResources().getDisplayMetrics()));
- mCycleTime = attrsArray.getFloat(
- R.styleable.AccelerateCircularView_cycleTime, 3000);
- attrsArray.recycle();
- mPaint = new Paint();
- }
2、重写onMeasure
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- int mWidth , mHeight ;
- int widthMode = MeasureSpec.getMode(widthMeasureSpec);
- int widthSize = MeasureSpec.getSize(widthMeasureSpec);
- int heightMode = MeasureSpec.getMode(heightMeasureSpec);
- int heightSize = MeasureSpec.getSize(heightMeasureSpec);
- if (widthMode == MeasureSpec.EXACTLY) {
- mWidth = widthSize;
- } else {
- mWidth = 169;
- if (widthMode == MeasureSpec.AT_MOST) {
- mWidth = Math.min(mWidth, widthSize);
- }
- }
- if (heightMode == MeasureSpec.EXACTLY) {
- mHeight = heightSize;
- } else {
- mHeight = 169;
- if (heightMode == MeasureSpec.AT_MOST) {
- mHeight = Math.min(mWidth, heightSize);
- }
- }
- setMeasuredDimension(mWidth, mHeight);
- }
3、重写onDraw
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- int central = Math.min(getWidth(), getHeight()) / 2;
- mRingRadius = central - mGlobuleRadius;
- if (mGlobuleRadius < mRingWidth / 2) { // 小球嵌在环里
- mRingRadius = central - mRingWidth / 2;
- }
- mPaint.setStrokeWidth(mRingWidth);
- mPaint.setStyle(Style.STROKE);
- mPaint.setAntiAlias(true);
- mPaint.setColor(mRingColor);
- canvas.drawCircle(central, central, mRingRadius, mPaint);// 绘制圆环
- mPaint.setStyle(Style.FILL);
- mPaint.setAntiAlias(true);
- mPaint.setColor(mGlobuleColor);
- if (currentAngle == -1) {
- startCirMotion();
- }
- drawGlobule(canvas, central);// 绘制小球
- }
- /**
- * 绘制小球,起始位置为圆环最低点
- *
- * @param canvas
- * @param central
- */
- private void drawGlobule(Canvas canvas, float central) {
- float cx = central + (float) (mRingRadius * Math.cos(currentAngle));
- float cy = (float) (central + mRingRadius * Math.sin(currentAngle));
- canvas.drawCircle(cx, cy, mGlobuleRadius, mPaint);
- }
4、定义动画
- /**
- * 旋转小球
- */
- private void startCirMotion() {
- ValueAnimator animator = ValueAnimator.ofFloat(90f, 450f);//起始位置在最低点
- animator.setDuration((long) mCycleTime).setRepeatCount(
- ValueAnimator.INFINITE);
- animator.addUpdateListener(new AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- Float angle = (Float) animation.getAnimatedValue();
- currentAngle = angle * Math.PI / 180;
- invalidate();
- }
- });
- // animator.setInterpolator(new LinearInterpolator());// 匀速旋转
- // 自定义开始减速到0后加速到初始值的Interpolator
- animator.setInterpolator(new TimeInterpolator() {
- @Override
- public float getInterpolation(float input) {
- float output;
- if (input < 0.5) {
- output = (float) Math.sin(input * Math.PI) / 2;// 先加速
- } else {
- output = 1 - (float) Math.sin(input * Math.PI) / 2;// 后减速,最高点(中间)速度为0
- }
- return output;
- }
- });
- animator.start();
- }
http://blog.csdn.net/chjr1000/article/details/41823505http://blog.csdn.net/lmj623565791/article/details/45460089