安卓开发之自定义粒子旋转动画加载控件
2016-09-25 00:08
691 查看
先上效果图:
控件可以根据颜色数组的长度来绘制不同数量的小球。小球旋转同时,距控件中心的距离也跟着不断变化。
还有个小细节就是,小球的颜色也会随着变化(颜色变为后一个小球的颜色)。
定义颜色数组(int数组)
在Java设置控件属性:
控件可以根据颜色数组的长度来绘制不同数量的小球。小球旋转同时,距控件中心的距离也跟着不断变化。
还有个小细节就是,小球的颜色也会随着变化(颜色变为后一个小球的颜色)。
一、自定义控件的属性
定义了小球的半径、小球偏移控件中心的最大距离和最小距离、动画的执行周期(决定旋转的速度)和一个存放各个颜色的数组(int 数组)。<declare-styleable name="CircleLoadingView"> <attr name="radius" format="dimension"/> <attr name="maxOffset" format="dimension"/> <attr name="minOffset" format="dimension"/> <attr name="colors" format="reference"/> <attr name="duration" format="integer"/> </declare-styleable>
二、自定义动画控件
package com.cxmscb.cxm.circleloadingview; import android.animation.Animator; import android.animation.AnimatorSet; import android.animation.ValueAnimator; import android.annotation.TargetApi; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Paint; import android.os.Build; import android.support.v4.view.animation.LinearOutSlowInInterpolator; import android.util.AttributeSet; import android.util.TypedValue; import android.view.View; import android.view.animation.AccelerateDecelerateInterpolator; import android.view.animation.AnticipateInterpolator; import android.view.animation.BounceInterpolator; import android.view.animation.DecelerateInterpolator; import android.view.animation.LinearInterpolator; import java.util.ArrayList; import java.util.Collection; /** * Created by cxm on 2016/9/24. */ public class CircleLoadingView extends View { private int centerX; // 控件x轴的中心 private int centerY; // 控件y轴的中心 private int radius; // 小球的半径 private int[] colors; // 颜色数组 private int maxOffset ; // 小球偏移的最大值 private int minOffset ; // 小球偏移的最小值 private int duration; // 动画执行的时间 private AnimatorSet mAnimationSet; // 保存动画的集合,用于同时启动动画 private Paint mPaint; // 画笔 private int mCanvasAngle; // 画笔目前的角度 private float mOffset; // 小球目前的偏移 public CircleLoadingView(Context context, AttributeSet attrs) { super(context, attrs); init(attrs); // 初始化 } public CircleLoadingView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(attrs); // 初始化 } @TargetApi(Build.VERSION_CODES.LOLLIPOP) public CircleLoadingView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); init(attrs); // 初始化 } private void init(AttributeSet attrs) { TypedArray array = this.getContext().obtainStyledAttributes(attrs,R.styleable.CircleLoadingView); // 获取各个属性值 if(array!=null){ radius = array.getDimensionPixelSize(R.styleable.CircleLoadingView_radius, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,10,getContext().getResources().getDisplayMetrics())); maxOffset = array.getDimensionPixelSize(R.styleable.CircleLoadingView_maxOffset, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,24,getContext().getResources().getDisplayMetrics())); minOffset = array.getDimensionPixelSize(R.styleable.CircleLoadingView_minOffset, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,12,getContext().getResources().getDisplayMetrics())); colors = array.getResources().getIntArray(array.getResourceId(R.styleable.CircleLoadingView_colors,R.array.colors)); duration = array.getDimensionPixelSize(R.styleable.CircleLoadingView_duration,2000); array.recycle(); } // 初始化画笔,去锯齿 mPaint = new Paint(); mPaint.setAntiAlias(true); } @Override protected void onDraw(Canvas canvas) { // 更新视图:一个一个球依次更新视图 for(int i = 0; i<colors.length;i++){ // 更改画笔的颜色 mPaint.setColor(colors[i]); // 根据不同的球来旋转画布 canvas.rotate(mCanvasAngle+i*(360/colors.length),centerX,centerY); // 根据目前的偏移来决定小球的位置 canvas.drawCircle(centerX+mOffset,centerY+mOffset,radius,mPaint); // 还原画布的旋转 canvas.rotate(-(mCanvasAngle+i*(360/colors.length)),centerX,centerY); } } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); // 获取中心的坐标 centerX = w/2; centerY = h/2; // 开启动画 startAnim(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int sizeWidth = MeasureSpec.getSize(widthMeasureSpec); int sizeHeight = MeasureSpec.getSize(heightMeasureSpec); int modeWidth = MeasureSpec.getMode(widthMeasureSpec); int modeHeight = MeasureSpec.getMode(heightMeasureSpec); // 非EXACTLY模式下自定义控件的大小 if(modeWidth == MeasureSpec.AT_MOST || modeWidth == MeasureSpec.UNSPECIFIED ){ sizeWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,100,getContext().getResources().getDisplayMetrics()); sizeWidth += getPaddingLeft()+getPaddingRight(); } if(modeHeight == MeasureSpec.AT_MOST || modeHeight == MeasureSpec.UNSPECIFIED ){ sizeHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,100,getContext().getResources().getDisplayMetrics()); sizeHeight += getPaddingBottom()+getPaddingTop(); } setMeasuredDimension(sizeWidth,sizeHeight); } private void startAnim() { // 生成动画集合的实例 mAnimationSet = new AnimatorSet(); // 用于保存动画 Collection<Animator> animList = new ArrayList<>(); // 使用属性动画生成不断变化的偏移值 // 参数这样设计是为了让当前小球的颜色为后一个小球的颜色 ValueAnimator canvasAnim = new ValueAnimator().ofInt(0, (colors.length+1)*180/colors.length, (colors.length+1)*360/colors.length); canvasAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { mCanvasAngle = (int) animation.getAnimatedValue(); } }); // 设重复次数为1000是为了达到一个“无限”循环播放动画的效果 canvasAnim.setRepeatCount(1000); canvasAnim.setRepeatMode(ValueAnimator.RESTART); // 加入集合 animList.add(canvasAnim); // 使用属性动画生成不断的小球的偏移值 ValueAnimator circleAnim = new ValueAnimator().ofFloat(maxOffset, minOffset, maxOffset); circleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { mOffset = (float) animation.getAnimatedValue(); invalidate(); } }); // 如上 circleAnim.setRepeatCount(1000); circleAnim.setRepeatMode(ValueAnimator.RESTART); animList.add(circleAnim); // 设置动画集合的属性 mAnimationSet.setDuration(duration); mAnimationSet.playTogether(animList); mAnimationSet.setInterpolator(new LinearInterpolator()); // 开始动画 mAnimationSet.start(); } // 初始化动画,为了配合在Java设置各个属性 private void initialAnim(){ if(mAnimationSet!=null){ if(mAnimationSet.isRunning()){ mAnimationSet.end(); } mAnimationSet = null; startAnim(); } } // 设置颜色,颜色数组的长度决定了小球的个数 public void setColors(int [] colors){ this.colors = colors; initialAnim(); } // 设置小球的半径 public void setRadius(int radius){ this.radius = radius; } // 设置小球的偏移 public void setMaxMinSizeLength(int maxOffset,int minOffset){ this.maxOffset = maxOffset; this.minOffset = minOffset; initialAnim(); } // 设置动画执行的时间 public void setDuration(int duration){ this.duration = duration; initialAnim(); } }
三、控件的使用:
xml:<com.cxmscb.cxm.circleloadingview.CircleLoadingView android:id="@+id/clv" android:background="#ffffff" app:radius="6dp" app:maxOffset="22dp" app:minOffset="12dp" app:colors="@array/colors0" android:layout_margin="16dp" android:layout_width="100dp" android:layout_height="100dp" />
定义颜色数组(int数组)
<integer-array name="colors0"> <item>0xB0E6092C</item> <item>0xB0C6114D</item> <item>0xB06CAA94</item> <item>0xB06AC304</item> <item>0xB0868949</item> <item>0xB0E0C9D4</item> </integer-array>
在Java设置控件属性:
public class MainActivity extends AppCompatActivity { CircleLoadingView circleLoadingView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); circleLoadingView = (CircleLoadingView) findViewById(R.id.clv); circleLoadingView.setDuration(4000); circleLoadingView.setRadius((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,10,getResources().getDisplayMetrics())); circleLoadingView.setColors(new int[]{0xB026c8d3,0xB0d6a802}); } }
项目地址: Github
相关文章推荐
- 安卓开发之使用PathMeasure自定义加载动画控件
- 安卓开发之自定义动画控件BatteryView(电池加载动画)
- iOS开发——UI进阶篇(十八)核心动画小例子,转盘(裁剪图片、自定义按钮、旋转)图片折叠、音量震动条、倒影、粒子效果
- android开发过程中自定义动画加载进度条实现过程
- Android自定义加载控件实现数据加载动画
- 【安卓-自定义布局】安卓App开发思路 一步一个脚印(十四)实现Fragment的缓冲视图和数据,防止重复加载
- andbase框架实现上拉加载,下拉刷新和自定义旋转动画的方式
- 安卓开发加载中效果类似progressDialog效果加载动画
- windows phone开发学习--加载时的旋转动画
- APP实用开发—自定义加载动画
- 自定义View时,用到Paint Canvas的一些温故,自定义Loading控件(动画五,“六边形”的旋转跳跃)
- CSS3实现大小不一的粒子旋转加载动画
- 安卓开发中实现页面越界回弹和上下拉的刷新自定义动画的操作(TwinklingRefreshLayout布局的使用)
- windows phone开发学习--加载时的旋转动画
- 自定义View时,用到Paint Canvas的一些温故,自定义Loading控件(动画五,“六边形”的旋转跳跃)
- 安卓开发之实现控件的贝塞尔曲线路径动画
- 安卓开发之自定义带加载进度的按钮ProgressButton
- 安卓开发之自定义SeekBar竖立类(顺时针逆时针旋转90度)
- 安卓ProgressDialog实现自定义Diallog加载动画
- 自定义扇形进度条、异步加载网络图片、Activity疯狂旋转动画