`

环形动画

阅读更多

今天貌似生病了……直接来代码

 

自定义View代码

package com.lizw.circular.wave;


import com.lizw.circular.R;
import com.lizw.circular.R.attr;
import com.lizw.circular.R.drawable;
import com.lizw.circular.R.styleable;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.View;


/**
 * 
 * @author Troy Lee
 *
 */
public class CircularView extends View {

	//背景圆所在的区域
    private final RectF mCircleBounds = new RectF();

//    //thumb所在举行
//    private final RectF mSquareRect = new RectF();
    //底层大圆的画笔
    private Paint mBackgroundColorPaint = null;
    //底层大圆边宽
    private int mCircleStrokeWidth = 10;
    private int mGravity = Gravity.CENTER;
    //Horizontal的内边界技术依赖于mGravity
    private int mHorizontalInset = 0;
    //Vertical的内边界技术依赖于mGravity
    private int mVerticalInset = 0;
    //所有属性设置完成为true,此时在Layout View时候将不会发生错误
    private boolean mIsInitializing = true;
    //thumb是否可见
    private boolean mIsThumbEnabled = true;
    //thumb沿着底层圆转的进度
    private float mProgress = 0.0f;
    //thumb沿着底层圆转前的路径颜色
    private int mProgressBackgroundColor;
    //thumb沿着底层圆转后留下的路径颜色
    private int mProgressColor;
    //thumb沿着底层圆转所用的画笔
    private Paint mProgressColorPaint;
    //底层大圆的半径
    private float mRadius;
    //thumb的画笔
    private Paint mThumbColorPaint = null;
    //thumb的坐标 x
    private float mThumbPosX;
    //thumb的坐 y
    private float mThumbPosY;
    //thumb的半径
    private int mThumbRadius = 20;
    //我们用自己坐标系统的变化偏移量X
    private float mTranslationOffsetX;
    //我们用自己坐标系统的变化偏移量Y
    private float mTranslationOffsetY;

    /**
     * Instantiates a new holo circular progress bar.
     *
     * @param context the context
     */
    public CircularView(final Context context) {
        this(context, null);
    }

    /**
     * Instantiates a new holo circular progress bar.
     *
     * @param context the context
     * @param attrs   the attrs
     */
    public CircularView(final Context context, final AttributeSet attrs) {
        this(context, attrs, R.attr.circularProgressBarStyle);
    }

    /**
     * Instantiates a new holo circular progress bar.
     *
     * @param context  the context
     * @param attrs    the attrs
     * @param defStyle the def style
     */
    public CircularView(final Context context, final AttributeSet attrs,
            final int defStyle) {
        super(context, attrs, defStyle);

        // load the styled attributes and set their properties
        final TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.CircularView,defStyle, 0);
        if (attributes != null) {
            try {
                setProgressColor(attributes.getColor(R.styleable.CircularView_progress_color, Color.CYAN));
                setProgressBackgroundColor(attributes.getColor(R.styleable.CircularView_progress_background_color,Color.GREEN));
                setProgress(attributes.getFloat(R.styleable.CircularView_progress, 0.0f));
                setWheelSize((int) attributes.getDimension(R.styleable.CircularView_stroke_width, 10));
                setThumbEnabled(attributes.getBoolean(R.styleable.CircularView_thumb_visible, true));

                mGravity = attributes.getInt(R.styleable.CircularView_android_gravity,Gravity.CENTER);
            } finally {
                // make sure recycle is always called.
                attributes.recycle();
            }
        }

        mThumbRadius = mCircleStrokeWidth * 2;
        mBackgroundColorPaint = new Paint();
        mThumbColorPaint = new Paint();
        updateBackgroundColor();
        updateProgressColor();
        // the view has now all properties and can be drawn
        mIsInitializing = false;

    }
    private Bitmap ballBitmap;

    @Override
    protected void onDraw(final Canvas canvas) {

        // All of our positions are using our internal coordinate system.
        // Instead of translating
        // them we let Canvas do the work for us.
        canvas.translate(mTranslationOffsetX, mTranslationOffsetY);

        final float progressRotation = getCurrentRotation();

//        // draw the background
        canvas.drawArc(mCircleBounds, 270, 360, false,mBackgroundColorPaint);

        if (isThumbEnabled()) {
        	// 根据进度画thumb图标转的路径
        	canvas.drawArc(mCircleBounds, 270, progressRotation, false,mProgressColorPaint);
        	//save()作用:在save()方法之前的全都保存,在save()方法之后,restore()方法之前的都清空。
        	canvas.save();
            // 将thumb图标初始位置放到0度
            canvas.rotate(progressRotation - 90);
//            // 将小方形图标正向旋转45度
//            canvas.rotate(45, mThumbPosX, mThumbPosY);
//            mSquareRect.left = mThumbPosX - mThumbRadius / 3;
//            mSquareRect.right = mThumbPosX + mThumbRadius / 3;
//            mSquareRect.top = mThumbPosY - mThumbRadius / 3;
//            mSquareRect.bottom = mThumbPosY + mThumbRadius / 3;
//            canvas.drawRect(mSquareRect, mThumbColorPaint);
            //设置thumb图标为小球
            ballBitmap = BitmapFactory.decodeStream(getResources().openRawResource(R.drawable.ic_detectiontrack));
            canvas.drawBitmap(ballBitmap, mThumbPosX-ballBitmap.getWidth()/2f, mThumbPosY - ballBitmap.getHeight()/2f, mThumbColorPaint);
            canvas.restore();
        }
    }

    @Override
    protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
        final int height = getDefaultSize(getSuggestedMinimumHeight() + getPaddingTop() + getPaddingBottom() ,heightMeasureSpec);
        final int width = getDefaultSize(getSuggestedMinimumWidth() + getPaddingLeft() + getPaddingRight(), widthMeasureSpec);

        //所要画出圆形的目标直径
        final int diameter;
        if (heightMeasureSpec == MeasureSpec.UNSPECIFIED) {
            // ScrollView
            diameter = width;
            computeInsets(0, 0);
        } else if (widthMeasureSpec == MeasureSpec.UNSPECIFIED) {
            // HorizontalScrollView
            diameter = height;
            computeInsets(0, 0);
        } else {
            // Default
            diameter = Math.min(width, height);
            computeInsets(width - diameter, height - diameter);
        }

        setMeasuredDimension(diameter, diameter);

        
        final float halfDiameter = diameter * 0.5f;

        // 所画圆形的边宽
        final float drawedWith;
        if (isThumbEnabled()) {
            drawedWith = mThumbRadius * (5f / 6f);
        } else {
            drawedWith = mCircleStrokeWidth / 2f;
        }

        // 所要画圆形的半径;-10.5f 是为了更好的融入到RectF中,起到padding的作用
        mRadius = halfDiameter - drawedWith - 10.5f;

        mCircleBounds.set(-mRadius, -mRadius, mRadius, mRadius);
        

        mThumbPosX = (float) (mRadius * Math.cos(0));
        mThumbPosY = (float) (mRadius * Math.sin(0));

        mTranslationOffsetX = halfDiameter + mHorizontalInset;
        mTranslationOffsetY = halfDiameter + mVerticalInset;

    }


    public int getCircleStrokeWidth() {
        return mCircleStrokeWidth;
    }


    /**
     * gives the current progress of the ProgressBar. Value between 0..1 if you set the progress to
     * >1 you'll get progress % 1 as return value
     *
     * @return the progress
     */
    public float getProgress() {
        return mProgress;
    }

    /**
     * Gets the progress color.
     *
     * @return the progress color
     */
    public int getProgressColor() {
        return mProgressColor;
    }

    /**
     * @return true if the marker is visible
     */
    public boolean isThumbEnabled() {
        return mIsThumbEnabled;
    }

	/**
	 * Sets the progress.
	 * 
	 * @param progress
	 *            the new progress
	 */
	public void setProgress(final float progress) {

		if (progress >= 1.0f) {
			mProgress = 1.0f;
		} else {
			mProgress = progress % 1.0f;
		}

//		Log.e("", "progress is : " + progress + " ,mProgress is : " + mProgress);

		if (!mIsInitializing) {
			invalidate();
		}
	}

    /**
     * Sets the progress background color.
     *
     * @param color the new progress background color
     */
    public void setProgressBackgroundColor(final int color) {
        mProgressBackgroundColor = color;
        updateBackgroundColor();
    }

    /**
     * Sets the progress color.
     *
     * @param color the new progress color
     */
    public void setProgressColor(final int color) {
        mProgressColor = color;
        updateProgressColor();
    }

    /**
     * shows or hides the thumb of the progress bar
     *
     * @param enabled true to show the thumb
     */
    public void setThumbEnabled(final boolean enabled) {
        mIsThumbEnabled = enabled;
    }

    /**
     * Sets the wheel size.
     *
     * @param dimension the new wheel size
     */
    public void setWheelSize(final int dimension) {
        mCircleStrokeWidth = dimension;

        // update the paints
        updateBackgroundColor();
        updateProgressColor();
    }

    /**
     * Compute insets.
     *
     * <pre>
     *  ______________________
     * |_________dx/2_________|
     * |......| /'''''\|......|
     * |-dx/2-|| View ||-dx/2-|
     * |______| \_____/|______|
     * |________ dx/2_________|
     * </pre>
     *
     * @param dx the dx the horizontal unfilled space
     * @param dy the dy the horizontal unfilled space
     */
    @SuppressLint("NewApi")
    private void computeInsets(final int dx, final int dy) {
        int absoluteGravity = mGravity;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            absoluteGravity = Gravity.getAbsoluteGravity(mGravity, getLayoutDirection());
        }

        switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
            case Gravity.LEFT:
                mHorizontalInset = 0;
                break;
            case Gravity.RIGHT:
                mHorizontalInset = dx;
                break;
            case Gravity.CENTER_HORIZONTAL:
            default:
                mHorizontalInset = dx / 2;
                break;
        }
        switch (absoluteGravity & Gravity.VERTICAL_GRAVITY_MASK) {
            case Gravity.TOP:
                mVerticalInset = 0;
                break;
            case Gravity.BOTTOM:
                mVerticalInset = dy;
                break;
            case Gravity.CENTER_VERTICAL:
            default:
                mVerticalInset = dy / 2;
                break;
        }
    }

    /**
     * Gets the current rotation.
     *
     * @return the current rotation
     */
    private float getCurrentRotation() {
        return 360f * mProgress;
    }


    /**
     * updates the paint of the background
     */
    private void updateBackgroundColor() {
        mBackgroundColorPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mBackgroundColorPaint.setColor(mProgressBackgroundColor);
        mBackgroundColorPaint.setStyle(Paint.Style.STROKE);
        mBackgroundColorPaint.setStrokeWidth(mCircleStrokeWidth);

        invalidate();
    }


    /**
     * updates the paint of the progress and the thumb to give them a new visual style
     */
    private void updateProgressColor() {
        mProgressColorPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mProgressColorPaint.setColor(mProgressColor);
        mProgressColorPaint.setStyle(Paint.Style.STROKE);
        mProgressColorPaint.setStrokeWidth(mCircleStrokeWidth);

        mThumbColorPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mThumbColorPaint.setColor(mProgressColor);
        mThumbColorPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        mThumbColorPaint.setStrokeWidth(mCircleStrokeWidth);

        invalidate();
    }


}

 

 Activity代码

package com.lizw.circular;


import com.lizw.circular.wave.CircularView;

import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;


/**
 * Troy Lee
 */
public class CircularActivity extends Activity {

    private static final String TAG = CircularActivity.class.getSimpleName();


    /**
     * The Switch button.
     */

    private CircularView circularView;
    private ObjectAnimator objAnimator;


    /*
     * (non-Javadoc)
     *
     * @see android.app.Activity#onCreate(android.os.Bundle)
     */
    @Override
    protected void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_home);
        circularView = (CircularView) findViewById(R.id.circularView);
    }
    
    
    public void startAnimate(View view) {
    	animate(circularView,new AnimatorListener() {

    		 @Override
             public void onAnimationCancel(final Animator animation) {
             	circularView.setProgress(0.0f);
             }

             @Override
             public void onAnimationEnd(final Animator animation) {
             	circularView.setProgress(1.0f);
             }

             @Override
             public void onAnimationRepeat(final Animator animation) {
             }

             @Override
             public void onAnimationStart(final Animator animation) {
             	circularView.setProgress(0.0f);
             }
        });
    	
    	
//    	new Handler().postDelayed(new Runnable() {
//			
//			@Override
//			public void run() {
//				// TODO Auto-generated method stub
//				if(objAnimator != null){
//					objAnimator.cancel();
//					
//					circularView.setProgress(0.0f);
//				}
//			}
//		}, 3000);
    	
    }
    
    
    /**
     * Animate.
     *
     * @param progressBar the progress bar
     * @param listener    the listener
     */
    private void animate(final CircularView circularView,final AnimatorListener listener) {
        final float progress = 1.00f;
        int duration = 5000;
        circularView.setProgress(0.0f);
        animate(circularView, listener, progress, duration);
    }

    private void animate(final CircularView circularView, final AnimatorListener listener,final float progress, final int duration) {

    	objAnimator = ObjectAnimator.ofFloat(circularView, "progress", progress);
        objAnimator.setDuration(duration);

        objAnimator.addListener(new AnimatorListener() {

            @Override
            public void onAnimationCancel(final Animator animation) {
            	circularView.setProgress(0.0f);
            }

            @Override
            public void onAnimationEnd(final Animator animation) {
            	circularView.setProgress(1.0f);
            }

            @Override
            public void onAnimationRepeat(final Animator animation) {
            }

            @Override
            public void onAnimationStart(final Animator animation) {
            	circularView.setProgress(0.0f);
            }
        });
        if (listener != null) {
        	objAnimator.addListener(listener);
        }
       
        objAnimator.addUpdateListener(new AnimatorUpdateListener() {

        	float count = 0.0f;
            @Override
            public void onAnimationUpdate(final ValueAnimator animation) {
            	count=0.01f;
            	circularView.setProgress(count);
            }
        });
//        circularView.setMarkerProgress(progress);
        objAnimator.start();
        
        
    }

}

 attr.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <declare-styleable name="CircularView">
        <attr name="stroke_width" format="dimension" />
        <attr name="progress" format="float" />
        <attr name="progress_color" format="color" />
        <attr name="progress_background_color" format="color" />
        <attr name="thumb_visible" format="boolean" />
        <attr name="android:gravity" />
        
    
    </declare-styleable>

    <attr name="circularStyle" format="reference" />

</resources>

 styles.xml

<resources xmlns:android="http://schemas.android.com/apk/res/android">
    
    <style name="Circular">
        <item name="android:layout_height">wrap_content</item>
        <item name="android:layout_width">match_parent</item>
        <item name="stroke_width">5dp</item>
        <item name="progress" format="float">0</item>
        <item name="progress_color">#46A4EC</item>
        <item name="progress_background_color">#adff2f</item>
        <item name="thumb_visible">true</item>
    </style>
    
    <style name="CircularLight">
        <item name="android:layout_height">wrap_content</item>
        <item name="android:layout_width">match_parent</item>
        <item name="stroke_width">5dp</item>
        <item name="progress" format="float">0</item>
        <item name="progress_color">#46A4EC</item>
        <item name="progress_background_color">#adff2f</item>
        <item name="thumb_visible">true</item>
    </style>
</resources>

 themes.xml

<resources>
    <!-- Application theme. -->
    <style name="AppTheme" parent="android:Theme.Holo">
        <item name="circularStyle">@style/Circular</item>
    </style>
    
    <style name="AppThemeLight" parent="android:Theme.Holo.Light">
        <item name="circularStyle">@style/CircularLight</item>
    </style>
</resources>

 activity_home.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/com.lizw.circular"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center_horizontal"
    android:orientation="vertical" >

    <com.lizw.circular.wave.CircularView
        android:id="@+id/circularView"
        android:layout_marginTop="20dp"
        android:layout_width="match_parent"
        android:layout_height="300dp"
        app:progress="0" />
    
    <Button 
        android:layout_marginTop="20dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="startAnimate"
        android:text="试试动画"/>

</LinearLayout>

 运行效果



 

 

  • 大小: 324.3 KB
  • 大小: 78.5 KB
  • 大小: 4.4 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics