Android加载动画系列——BatteryLoading
小编在逛掘金社区的时候,一不小心看到了一篇讲加载动画的文章,于是点进去看了看,被这些炫酷的加载动画深深地吸引了,于是小编觉得有必要自己动手记录一下这些炫酷的脚在动画,顺便丰富一下自己的学习笔记。
项目原地址:https://github.com/ldoublem/LoadingView
让我们先来看看效果图:
在此我就不做过多的分析,直接上源码。
1、BatteryLoading.java源码如下:
public class BatteryLoading extends View { private float mWidth = 0f; private float mHeight = 0f; private float mBatteryWidth; private float mBatteryHigh; private float mPadding = 0f; private float mBodyCorner = 0f; private float mBatterySpace = 0f; private Paint mPaint, mPaintHead, mPaintValue; private BatteryOrientation mBatteryOrientation = BatteryOrientation.HORIZONTAL; RectF rectFBody = null; RectF rectHead = null; public enum BatteryOrientation { VERTICAL, HORIZONTAL } private boolean mShowNum = false; public BatteryLoading(Context context) { this(context, null); } public BatteryLoading(Context context, AttributeSet attrs) { this(context, attrs, 0); } public BatteryLoading(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initPaint(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); if (getMeasuredWidth() > getHeight()) { mWidth = getMeasuredHeight(); mHeight = getMeasuredHeight() * 0.8f; } else { mWidth = getMeasuredWidth(); mHeight = getMeasuredWidth() * 0.8f; } } private void drawHead(Canvas canvas) { float mHeadWidth = mHeight / 6; rectHead = new RectF( mWidth - mPadding - mHeadWidth, mWidth / 2 - mHeadWidth / 2, mWidth - mPadding, mWidth / 2 + mHeadWidth / 2); canvas.drawArc(rectHead, -70, 140 , false, mPaintHead); } private void drawBody(Canvas canvas) { float mHeadWidth = mHeight / 6; float x = (float) ((mHeadWidth / 2) * Math.cos(-70 * Math.PI / 180f)); rectFBody = new RectF(); rectFBody.top = mWidth / 2 - mHeight / 4 + mPadding; rectFBody.bottom = mWidth / 2 + mHeight / 4 - mPadding; rectFBody.left = mPadding; rectFBody.right = mWidth - mPadding - x - x - mBatterySpace; canvas.drawRoundRect(rectFBody, mBodyCorner, mBodyCorner, mPaint); } private void drawValue(Canvas canvas) { RectF rectFBatteryValueFill = new RectF(); rectFBatteryValueFill.top = rectFBody.top + mBatterySpace; rectFBatteryValueFill.bottom = rectFBody.bottom - mBatterySpace; rectFBatteryValueFill.left = mPadding + mBatterySpace; rectFBatteryValueFill.right = rectFBody.right - mBatterySpace; RectF rectFBatteryValue = new RectF(); rectFBatteryValue.top = rectFBatteryValueFill.top; rectFBatteryValue.bottom = rectFBatteryValueFill.bottom; rectFBatteryValue.left = rectFBatteryValueFill.left; rectFBatteryValue.right = rectFBatteryValueFill.right * mAnimatedValue; canvas.drawRoundRect(rectFBatteryValue, 1, 1, mPaintValue); } private void drawLogo(Canvas canvas) { mPaintHead.setTextSize(mHeight / 6); if (!mShowNum) { Path path = new Path(); path.moveTo(mWidth / 2 - mHeight / 6, mWidth / 2 - dip2px(1.5f)); path.lineTo(mWidth / 2 + dip2px(2f), mWidth / 2 + mHeight / 12); path.lineTo(mWidth / 2 + dip2px(1f), mWidth / 2); path.close(); canvas.drawPath(path, mPaintHead); Path path2 = new Path(); path2.moveTo(mWidth / 2 - dip2px(2f), mWidth / 2 - mHeight / 12); path2.lineTo(mWidth / 2 + mHeight / 6, mWidth / 2 + dip2px(1.5f)); path2.lineTo(mWidth / 2 - dip2px(1f), mWidth / 2); path2.close(); canvas.drawPath(path2, mPaintHead); } else { String text = String.valueOf((int) (mAnimatedValue * 100)) + "%"; if (mBatteryOrientation == BatteryOrientation.VERTICAL) { Path p = new Path(); p.moveTo(mWidth / 2, 0); p.lineTo(mWidth / 2, mWidth); canvas.drawTextOnPath(text, p, mWidth / 2 - getFontLength(mPaintHead, text) / 2, mWidth / 2 - mHeight / 2 - getFontHeight(mPaintHead, text) / 2, mPaintHead); } else { canvas.drawText(text, mWidth / 2 - getFontLength(mPaintHead, text) / 2, mWidth / 2 + getFontHeight(mPaintHead, text) / 2, mPaintHead); } } } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (mBatteryOrientation == BatteryOrientation.VERTICAL) canvas.rotate(270, mWidth / 2, mWidth / 2); else canvas.rotate(0, mWidth / 2, mWidth / 2); canvas.save(); drawHead(canvas); drawBody(canvas); drawValue(canvas); drawLogo(canvas); canvas.restore(); } private void initPaint() { mBatteryHigh = dip2px(20); mPadding = dip2px(2); mBodyCorner = dip2px(1); mBatterySpace = dip2px(1); mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setStyle(Paint.Style.STROKE); mPaint.setColor(Color.WHITE); mPaintHead = new Paint(); mPaintHead.setAntiAlias(true); mPaintHead.setStyle(Paint.Style.FILL); mPaintHead.setColor(Color.WHITE); mPaintValue = new Paint(); mPaintValue.setAntiAlias(true); mPaintValue.setStyle(Paint.Style.FILL); mPaintValue.setColor(Color.rgb(67, 213, 81)); } public void startAnim() { stopAnim(); startViewAnim(0f, 1f, 5000); } public void setValue(int value)//0-100 { this.mAnimatedValue = value * 1.f / 100; invalidate(); } public void setShowNum(boolean show) { this.mShowNum = show; invalidate(); } public void setBatteryOrientation(BatteryOrientation batteryOrientation) { this.mBatteryOrientation = batteryOrientation; invalidate(); } private ValueAnimator valueAnimator; private float mAnimatedValue = 0f; public void stopAnim() { if (valueAnimator != null) { clearAnimation(); valueAnimator.setRepeatCount(0); valueAnimator.cancel(); valueAnimator.end(); mAnimatedValue = 0f; postInvalidate(); } } private ValueAnimator startViewAnim(float startF, final float endF, long time) { valueAnimator = ValueAnimator.ofFloat(startF, endF); valueAnimator.setDuration(time); valueAnimator.setInterpolator(new LinearInterpolator()); valueAnimator.setRepeatCount(ValueAnimator.INFINITE);//无限循环 valueAnimator.setRepeatMode(ValueAnimator.RESTART); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { mAnimatedValue = (float) valueAnimator.getAnimatedValue(); invalidate(); } }); valueAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); } @Override public void onAnimationStart(Animator animation) { super.onAnimationStart(animation); } @Override public void onAnimationRepeat(Animator animation) { super.onAnimationRepeat(animation); } }); if (!valueAnimator.isRunning()) { valueAnimator.start(); } return valueAnimator; } public int dip2px(float dpValue) { final float scale = getContext().getResources().getDisplayMetrics().density; return (int) (dpValue * scale + 0.5f); } public float getFontLength(Paint paint, String str) { Rect rect = new Rect(); paint.getTextBounds(str, 0, str.length(), rect); return rect.width(); } public float getFontHeight(Paint paint, String str) { Rect rect = new Rect(); paint.getTextBounds(str, 0, str.length(), rect); return rect.height(); } }
为了考虑到电池的放置方式,提供了包含VERTICAL, HORIZONTAL两个方向的枚举变量。另外,为了切合时间,我们可以通过setShowNum(boolean)来设置是否显示百分比。
2、接下来就是如何使用的问题,首先我们需要在layout中引用自定义的动画控件,如下所示:
3、 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/darker_gray" android:gravity="center" android:orientation="vertical"> <com.cyril.loadinganim.BatteryLoading android:id="@+id/battery" android:layout_width="65dp" android:layout_height="65dp" /> <com.cyril.loadinganim.BatteryLoading android:id="@+id/battery2" android:layout_width="65dp" android:layout_height="65dp" /> </LinearLayout>
4、然后在相关的Activity中实现动画的播放和停止,使用事例如下:
batteryLoading = (BatteryLoading) findViewById(R.id.battery); batteryLoading.setValue(50); batteryLoading.setShowNum(true); batteryLoading.setBatteryOrientation(BatteryLoading.BatteryOrientation.VERTICAL); batteryLoading.startAnim(); batteryLoading1 = (BatteryLoading) findViewById(R.id.battery2); batteryLoading1.setValue(50); batteryLoading1.setShowNum(false); batteryLoading1.setBatteryOrientation(BatteryLoading.BatteryOrientation.HORIZONTAL); batteryLoading1.startAnim();
事例代码中,分别演示了,控件的水平放置和垂直放置,以及显示百分比和不显示百分比的情况。
5、 最后小编双手奉上源码的下载地址:http://download.csdn.net/detail/zhimingshangyan/9570386