安卓设置菊花动画_Android 加载菊花图 自定义

本来想找一个ios的菊花加载图旋转一下搞定这个的,但是发现使用图片后由于图片的不对称导致动画时有抖动现象,不能忍,于是搜了下自定义菊花图,额,然后就没有然后了,都不是想要的,于是开始了苦逼的自定义View...

先来张效果图:

菊花图.png

再来张动画效果图:

嗯是的我动起来了.gif

看图说话:

1、12条颜色线,带圆角

2、动画起来后12个颜色跟着变化

需要解决的问题:

1、12个颜色,也太多了吧!!!!我可不想吸这么多次,有毒的!(嗯,我为吸管代言)

于是愉快的决定了只是用两种颜色,即开始颜色和结束颜色,其余使用渐变获取。(额,好吧,我是懒了!)

2、动画

什么,动画是问题吗?一个旋转搞定了!嗯,你大佬,你来,反正我做不来!!

由于旋转动画是转动的,难以实现颜色跟着变化的效果,所以我使用了ValueAnimator,

嗯,是的,你猜对了,既然使用了ValueAnimator,就要调用 invalidate(); 或 postInvalidate(); 来实现重绘。

嗯,看起来还是挺简单的,来试试吧:

先定义一下属性:

/**

* 线圆角及宽度

*/

private int mLineBold;

/**

* 线条开始颜色 默认白色

*/

private int mStartColor = Color.parseColor("#FFFFFF");

/**

* 线条结束颜色 默认灰色

*/

private int mEndColor = Color.parseColor("#9B9B9B");

/**

* view的宽度 高度

*/

private int mWidth;

/**

* view的高度

*/

private int mHeight;

/**

* 线条长度

*/

private int mLineLength;

/**

* 线条个数 默认12条

*/

private int mLineCount = 12;

/**

* 背景画笔

*/

private Paint mBgPaint;

/**

* 渐变颜色

*/

private int[] mColors;

/**

* 动画是否已开启

*/

private boolean isAnimationStart;

/**

* 开始index

*/

private int mStartIndex;

/**

* 动画

*/

private ValueAnimator mValueAnimator;

>>>>>>>>>>>>>>> 然后继续 >>>>>>>>>>>>>>>>>

1.第一步:

自定义属性:

// 由于考虑到后续可能使用更多数量的线,所以索性加了个线个数的属性

2.第二步,初始化:

public ChrysanthemumView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

loadAttrs(context, attrs);

initPaint();

initColor();

}

/**

* 加载自定义的属性

*/

private void loadAttrs(Context context, AttributeSet attrs) {

TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.ChrysanthemumView);

mStartColor = array.getColor(R.styleable.ChrysanthemumView_startColor, mStartColor);

mEndColor = array.getColor(R.styleable.ChrysanthemumView_endColor, mEndColor);

mLineCount = array.getInt(R.styleable.ChrysanthemumView_lineCount, mLineCount);

//TypedArray回收

array.recycle();

}

/**

* 初始化画笔

*/

private void initPaint() {

mBgPaint = new Paint();

//使得画笔更加圆滑

mBgPaint.setAntiAlias(true);

mBgPaint.setStrokeJoin(Paint.Join.ROUND);

mBgPaint.setStrokeCap(Paint.Cap.ROUND);

}

3.第三步,解决颜色的问题:

/**

* 初始化颜色

*/

private void initColor() {

// 渐变色计算类

ArgbEvaluator argbEvaluator = new ArgbEvaluator();

// 初始化对应空间

mColors = new int[mLineCount];

// 获取对应的线颜色 此处由于是白色起头 黑色结尾所以需要反过来计算 即线的数量到0的数量递减 对应的ValueAnimator 是从0到线的数量-1递增

for (int i = mLineCount; i > 0; i--) {

float alpha = (float) i / mLineCount;

mColors[mLineCount - i] = (int) argbEvaluator.evaluate(alpha, mStartColor, mEndColor);

}

}

4.第四步,解决尺寸的问题:

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

// 获取view的宽度 默认40dp

mWidth = getViewSize(dp2px(getContext(), 40), widthMeasureSpec);

// 获取view的高度 默认40dp

mHeight = getViewSize(dp2px(getContext(), 40), heightMeasureSpec);

// 使宽高保持一致

mHeight = mWidth = Math.min(mWidth, mHeight);

// 获取线的长度

mLineLength = mWidth / 6;

// 获取线圆角及宽度

mLineBold = mWidth / mLineCount;

// 设置线的圆角及宽度

mBgPaint.setStrokeWidth(mLineBold);

setMeasuredDimension(mWidth,mHeight);

}

/**

* 测量模式 表示意思

* UNSPECIFIED 父容器没有对当前View有任何限制,当前View可以任意取尺寸

* EXACTLY 当前的尺寸就是当前View应该取的尺寸

* AT_MOST 当前尺寸是当前View能取的最大尺寸

*

* @param defaultSize 默认大小

* @param measureSpec 包含测量模式和宽高信息

* @return 返回View的宽高大小

*/

private int getViewSize(int defaultSize, int measureSpec) {

int viewSize = defaultSize;

//获取测量模式

int mode = MeasureSpec.getMode(measureSpec);

//获取大小

int size = MeasureSpec.getSize(measureSpec);

switch (mode) {

case MeasureSpec.UNSPECIFIED:

//如果没有指定大小,就设置为默认大小

viewSize = defaultSize;

break;

case MeasureSpec.AT_MOST:

//如果测量模式是最大取值为size

//我们将大小取最大值,你也可以取其他值

viewSize = size;

break;

case MeasureSpec.EXACTLY:

//如果是固定的大小,那就不要去改变它

viewSize = size;

break;

default:

}

return viewSize;

}

5.第五步,绘制:

@Override

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

// 获取半径

int r = mWidth / 2;

// 绘制前先旋转一个角度,使最顶上开始位置颜色与开始颜色匹配

canvas.rotate(360f / mLineCount, r, r);

for (int i = 0; i < mLineCount; i++) {

// 获取颜色下标

int index = (mStartIndex + i) % mLineCount;

// 设置颜色

mBgPaint.setColor(mColors[index]);

// 绘制线条 mLineBold >> 1 == mLineBold / 2 使居中显示

canvas.drawLine(r, mLineBold >> 1, r, (mLineBold >> 1) + mLineLength, mBgPaint);

// 旋转角度

canvas.rotate(360f / mLineCount, r, r);

}

}

6.第六步,动起来!!!!:

/**

* 开始动画

*

* @param duration 动画时间

*/

public void startAnimation(int duration) {

Log.d(TAG, "startAnimation: " + mStartIndex);

if (mValueAnimator == null) {

mValueAnimator = ValueAnimator.ofInt(mLineCount, 0);

mValueAnimator.setDuration(duration);

mValueAnimator.setTarget(0);

mValueAnimator.setRepeatCount(-1);

mValueAnimator.setInterpolator(new LinearInterpolator());

mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator animation) {

// 此处会回调3次 需要去除后面的两次回调

if (mStartIndex != (int) animation.getAnimatedValue()) {

mStartIndex = (int) animation.getAnimatedValue();

Log.d(TAG, "onAnimationUpdate: " + mStartIndex);

invalidate();

}

}

});

}

mValueAnimator.start();

isAnimationStart = true;

}

完成了!!!

额,少了东西了。

/**

* 结束动画

*/

public void stopAnimation() {

Log.d(TAG, "stopAnimation: " + mStartIndex);

if (mValueAnimator != null) {

mValueAnimator.cancel();

isAnimationStart = false;

}

}

不行,还不够!

/**

* 防止内存溢出 未结束动画并退出页面时,需使用此函数,或手动释放此view

*/

public void detachView() {

if (mValueAnimator != null) {

mValueAnimator.cancel();

mValueAnimator = null;

isAnimationStart = false;

}

}

所有源码:

/**

* @author : Kingsley

* info: 菊花图

* @date : 2019/4/30 10:12

*/

public class ChrysanthemumView extends View {

private static final String TAG = "ChrysanthemumView";

/**

* 线圆角及宽度

*/

private int mLineBold;

/**

* 线条开始颜色 默认白色

*/

private int mStartColor = Color.parseColor("#FFFFFF");

/**

* 线条结束颜色 默认灰色

*/

private int mEndColor = Color.parseColor("#9B9B9B");

/**

* view的宽度 高度

*/

private int mWidth;

/**

* view的高度

*/

private int mHeight;

/**

* 线条长度

*/

private int mLineLength;

/**

* 线条个数 默认12条

*/

private int mLineCount = 12;

/**

* 背景画笔

*/

private Paint mBgPaint;

/**

* 渐变颜色

*/

private int[] mColors;

/**

* 动画是否已开启

*/

private boolean isAnimationStart;

/**

* 开始index

*/

private int mStartIndex;

/**

* 动画

*/

private ValueAnimator mValueAnimator;

public ChrysanthemumView(Context context) {

this(context, null);

}

public ChrysanthemumView(Context context, @Nullable AttributeSet attrs) {

this(context, attrs, 0);

}

public ChrysanthemumView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

loadAttrs(context, attrs);

initPaint();

initColor();

}

/**

* 初始化颜色

*/

private void initColor() {

// 渐变色计算类

ArgbEvaluator argbEvaluator = new ArgbEvaluator();

// 初始化对应空间

mColors = new int[mLineCount];

// 获取对应的线颜色 此处由于是白色起头 黑色结尾所以需要反过来计算 即线的数量到0的数量递减 对应的ValueAnimator 是从0到线的数量-1递增

for (int i = mLineCount; i > 0; i--) {

float alpha = (float) i / mLineCount;

mColors[mLineCount - i] = (int) argbEvaluator.evaluate(alpha, mStartColor, mEndColor);

}

}

/**

* 加载自定义的属性

*/

private void loadAttrs(Context context, AttributeSet attrs) {

TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.ChrysanthemumView);

mStartColor = array.getColor(R.styleable.ChrysanthemumView_startColor, mStartColor);

mEndColor = array.getColor(R.styleable.ChrysanthemumView_endColor, mEndColor);

mLineCount = array.getInt(R.styleable.ChrysanthemumView_lineCount, mLineCount);

//TypedArray回收

array.recycle();

}

/**

* 初始化画笔

*/

private void initPaint() {

mBgPaint = new Paint();

//使得画笔更加圆滑

mBgPaint.setAntiAlias(true);

mBgPaint.setStrokeJoin(Paint.Join.ROUND);

mBgPaint.setStrokeCap(Paint.Cap.ROUND);

}

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

// 获取view的宽度 默认40dp

mWidth = getViewSize(dp2px(getContext(), 40), widthMeasureSpec);

// 获取view的高度 默认40dp

mHeight = getViewSize(dp2px(getContext(), 40), heightMeasureSpec);

// 使宽高保持一致

mHeight = mWidth = Math.min(mWidth, mHeight);

// 获取线的长度

mLineLength = mWidth / 6;

// 获取线圆角及宽度

mLineBold = mWidth / mLineCount;

// 设置线的圆角及宽度

mBgPaint.setStrokeWidth(mLineBold);

setMeasuredDimension(mWidth,mHeight);

}

/**

* 测量模式 表示意思

* UNSPECIFIED 父容器没有对当前View有任何限制,当前View可以任意取尺寸

* EXACTLY 当前的尺寸就是当前View应该取的尺寸

* AT_MOST 当前尺寸是当前View能取的最大尺寸

*

* @param defaultSize 默认大小

* @param measureSpec 包含测量模式和宽高信息

* @return 返回View的宽高大小

*/

private int getViewSize(int defaultSize, int measureSpec) {

int viewSize = defaultSize;

//获取测量模式

int mode = MeasureSpec.getMode(measureSpec);

//获取大小

int size = MeasureSpec.getSize(measureSpec);

switch (mode) {

case MeasureSpec.UNSPECIFIED:

//如果没有指定大小,就设置为默认大小

viewSize = defaultSize;

break;

case MeasureSpec.AT_MOST:

//如果测量模式是最大取值为size

//我们将大小取最大值,你也可以取其他值

viewSize = size;

break;

case MeasureSpec.EXACTLY:

//如果是固定的大小,那就不要去改变它

viewSize = size;

break;

default:

}

return viewSize;

}

@Override

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

// 获取半径

int r = mWidth / 2;

// 绘制前先旋转一个角度,使最顶上开始位置颜色与开始颜色匹配

canvas.rotate(360f / mLineCount, r, r);

for (int i = 0; i < mLineCount; i++) {

// 获取颜色下标

int index = (mStartIndex + i) % mLineCount;

// 设置颜色

mBgPaint.setColor(mColors[index]);

// 绘制线条 mLineBold >> 1 == mLineBold / 2 使居中显示

canvas.drawLine(r, mLineBold >> 1, r, (mLineBold >> 1) + mLineLength, mBgPaint);

// 旋转角度

canvas.rotate(360f / mLineCount, r, r);

}

}

/**

* 开始动画

*

* @param duration 动画时间

*/

public void startAnimation(int duration) {

Log.d(TAG, "startAnimation: " + mStartIndex);

if (mValueAnimator == null) {

mValueAnimator = ValueAnimator.ofInt(mLineCount, 0);

mValueAnimator.setDuration(duration);

mValueAnimator.setTarget(0);

mValueAnimator.setRepeatCount(-1);

mValueAnimator.setInterpolator(new LinearInterpolator());

mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator animation) {

// 此处会回调3次 需要去除后面的两次回调

if (mStartIndex != (int) animation.getAnimatedValue()) {

mStartIndex = (int) animation.getAnimatedValue();

Log.d(TAG, "onAnimationUpdate: " + mStartIndex);

invalidate();

}

}

});

}

mValueAnimator.start();

isAnimationStart = true;

}

/**

* 开始动画 时间为1800毫秒一次

*/

public void startAnimation() {

startAnimation(1800);

}

/**

* 结束动画

*/

public void stopAnimation() {

Log.d(TAG, "stopAnimation: " + mStartIndex);

if (mValueAnimator != null) {

mValueAnimator.cancel();

isAnimationStart = false;

}

}

/**

* 是否在动画中

*

* @return 是为 true 否则 false

*/

public boolean isAnimationStart() {

return isAnimationStart;

}

/**

* dp转px

*

* @param context context

* @param dpVal dpVal

* @return px

*/

public static int dp2px(Context context, float dpVal) {

return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,

dpVal, context.getResources().getDisplayMetrics());

}

/**

* 防止内存溢出 未结束动画并退出页面时,需使用此函数,或手动释放此view

*/

public void detachView() {

if (mValueAnimator != null) {

mValueAnimator.cancel();

mValueAnimator = null;

isAnimationStart = false;

}

}

}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值