Android开发之自定义加载动画详解
一、前言
在移动APP的开发中,由于数据的加载速度不可控,我们通常会使用加载动画来占位,让用户知道数据正在努力获取中,以此来提升用户体验。在Android开发中,我们可以通过自定义View来创建各种各样的加载动画,本篇攻略将详细讲解如何自定义加载动画。
二、核心步骤
2.1 绘制动画
自定义加载动画的第一步是绘制动画。需要在View的onDraw()
方法中完成绘制。这里我们以绘制小球旋转的动画为例。
public class BallRotationView extends View {
private Paint mPaint;
private int mWidth, mHeight;
private float mRadius = 20; // 小球半径
private float mDegrees; // 小球旋转角度
private float[] mPositions = new float[8]; // 8个小球的旋转初始角度
private AnimatorSet mAnimatorSet;
public BallRotationView(Context context) {
this(context, null);
}
public BallRotationView(Context context, AttributeSet attrs) {
super(context, attrs);
initPaint();
initPositions();
initAnimator();
}
private void initPaint() {
mPaint = new Paint();
mPaint.setColor(Color.RED);
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.FILL);
}
private void initPositions() {
for (int i = 0; i < 8; i++) {
mPositions[i] = i * 45;
}
}
private void initAnimator() {
ObjectAnimator degreeAnimator = ObjectAnimator.ofFloat(this, "degrees", 0, 360);
degreeAnimator.setDuration(1000);
degreeAnimator.setInterpolator(new LinearInterpolator());
degreeAnimator.setRepeatCount(ValueAnimator.INFINITE);
mAnimatorSet = new AnimatorSet();
mAnimatorSet.playTogether(degreeAnimator);
mAnimatorSet.start();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.save();
canvas.translate(mWidth / 2, mHeight / 2);
for (int i = 0; i < 8; i++) {
canvas.rotate(mPositions[i] + mDegrees);
canvas.drawCircle(0, mWidth / 2 - mRadius * 2, mRadius, mPaint);
}
canvas.restore();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mWidth = MeasureSpec.getSize(widthMeasureSpec);
mHeight = MeasureSpec.getSize(heightMeasureSpec);
}
public void setDegrees(float degrees) {
mDegrees = degrees;
invalidate();
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
mAnimatorSet.cancel();
}
}
2.2 循环动画
接下来,我们需要实现动画的循环播放。可以通过AnimatorSet来实现多个Animator的组合。
ObjectAnimator degreeAnimator = ObjectAnimator.ofFloat(this, "degrees", 0, 360);
degreeAnimator.setDuration(1000);
degreeAnimator.setInterpolator(new LinearInterpolator());
degreeAnimator.setRepeatCount(ValueAnimator.INFINITE);
mAnimatorSet = new AnimatorSet();
mAnimatorSet.playTogether(degreeAnimator);
mAnimatorSet.start();
2.3 动画控制
当View被移除屏幕时,停止动画,释放所有资源。可以在onDetachedFromWindow()
方法中实现。
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
mAnimatorSet.cancel();
}
三、示例说明
3.1 示例一:小球旋转动画
我们可以使用自定义的BallRotationView实现小球旋转动画效果。代码如下:
<com.example.myapplication.BallRotationView
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_gravity="center_horizontal" />
3.2 示例二:微信小程序的加载动画
我们可以根据微信小程序的加载动画示意图来自定义仿微信小程序的加载动画,代码如下:
public class WxLoadingView extends View {
private Paint mPaint;
private int mWidth, mHeight;
private float mRadius;
private float mScale; // 尺寸变化比例
private int mCount = 3; // 圆点个数
private int mCurrentIndex = 0; // 当前动画圆点序号
private int mDuration = 300; // 动画时长
private boolean mIsAnimatorRunning = false;
private ValueAnimator mAnimator;
public WxLoadingView(Context context) {
this(context, null);
}
public WxLoadingView(Context context, AttributeSet attrs) {
super(context, attrs);
initPaint();
startAnimation();
}
private void initPaint() {
mPaint = new Paint();
mPaint.setColor(Color.parseColor("#1296db"));
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.FILL);
}
private void startAnimation() {
mAnimator = ValueAnimator.ofFloat(1, 0.2f, 1);
mAnimator.setDuration(mDuration);
mAnimator.setRepeatCount(ValueAnimator.INFINITE);
mAnimator.setRepeatMode(ValueAnimator.RESTART);
mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mScale = (float) animation.getAnimatedValue();
invalidate();
}
});
mIsAnimatorRunning = true;
mAnimator.start();
}
private void stopAnimation() {
if (mAnimator != null && mAnimator.isRunning()) {
mAnimator.cancel();
mIsAnimatorRunning = false;
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
float x = (float) (mWidth / 2);
float y = (float) (mHeight / 2);
float space = mRadius / 2;
for (int i = 0; i < mCount; i++) {
canvas.save();
float translateX = x + (i - (mCount - 1) / 2f) * space * mScale;
float translateY = y;
canvas.translate(translateX, translateY);
float scale = mCurrentIndex == i ? 1 : 0.5f;
canvas.scale(scale, scale);
canvas.drawCircle(0, 0, mRadius * mScale, mPaint);
canvas.restore();
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mWidth = MeasureSpec.getSize(widthMeasureSpec);
mHeight = MeasureSpec.getSize(heightMeasureSpec);
mRadius = mHeight / 5;
}
public boolean isAnimatorRunning() {
return mIsAnimatorRunning;
}
public void show() {
if (!isAnimatorRunning()) {
startAnimation();
}
setVisibility(VISIBLE);
}
public void hide() {
stopAnimation();
setVisibility(GONE);
}
public void setCurrentIndex(int currentIndex) {
this.mCurrentIndex = currentIndex;
invalidate();
}
}
我们可以使用自定义的WxLoadingView实现仿微信小程序的加载动画效果。代码如下:
<com.example.myapplication.WxLoadingView
android:id="@+id/loading_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="24dp" />
四、总结
通过自定义View的方式,我们可以轻松实现各种各样的加载动画效果。不仅能提升用户的体验,也能让APP的界面更具有个性化。希望本篇攻略对您有所帮助。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Android开发之自定义加载动画详解 - Python技术站