android仿支付宝蚂蚁森林加载动画效果的两种方法

本文详细介绍了一种仿蚂蚁森林加载动画的实现方法,通过自定义View,利用两张图片叠加和PorterDuff.Mode.SRC_IN实现动态着色效果,以及使用ValueAnimator实现动画效果。并提供了两种实现方案,一种是利用两张图片叠加,另一种是利用矩形裁剪有色Logo图片。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一图胜千言

偷过别人能量的小伙伴都熟悉这个加载效果,下面就讲解一下实现过程。

1,自定义view

2,这里要用到蚂蚁森林的图标,如图

通过canvas.drawBitmap()画出图片。

3,通过PorterDuff.Mode.SRC_IN,给图片填充想要的颜色。

4,通过ValueAnimator实现往复动画。

下面从第二步开始讲解。有两种方式可以实现上图效果,如下:

一,方式一

       该方法中,利用两张图片:一张logo图和一张上半部分有颜色、下半部分白色的图片,把第二张图叠加在第一张图上实现着色效果。

1,绘制图标

通过BitmapFactory.decodeResource()获取到资源文件中的图片资源,并获取图片宽高,后面要用到

dstBmp = BitmapFactory.decodeResource(getResources(), R.mipmap.ant_forest);
// 图片宽度的一半
dstWidth = dstBmp.getWidth() / 2;
// 图片高度的一半
dstHeight = dstBmp.getHeight() / 2;

然后通过canvas.drawBitmap()绘制图片

// 画背景色
canvas.drawColor(Color.parseColor("#01507d"));
// 坐标原点移动到屏幕中心
canvas.translate(mWidth / 2, mHeight / 2);
// 绘制图片
canvas.drawBitmap(dstBmp, -dstWidth, -dstHeight, mPaint);

其中dstWidth和dstHeight分别是dstBmp的宽高的一半。

这样就在屏幕中心绘制出了图片。

2,绘制填充色

中间的填充色其实也是一张图片,如图

2.1,同样我们需要先获取到该图片

srcBmp = BitmapFactory.decodeResource(getResources(), R.mipmap.ant_forest_wave);

2.2,并根据上面的dstWidth和dstHeight生成srcRect,也就是srcBmp的显示范围

srcRect = new RectF(-dstWidth, -dstHeight, dstWidth, 3 * dstHeight);

这里为什么Rect的bottom是3*dstHeight? 如图。

红色框以屏幕为中心,宽高分别是2*dstWidth和2*dstHeight,所以绿色框的范围应该是-dstWidth, -dstHeight, dstWidth, 3 * dstHeight。

然后需要根据srcRect绘制srcBmp

canvas.drawBitmap(srcBmp, null, srcRect, mPaint);

2.3,这两个图片都绘制出来了,我们就需要把他们叠加一下,通过PorterDuff.Mode.SRC_IN方式

mXfermode = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);
// 保存当前图层
int saveCount = canvas.saveLayer(dstRect, mPaint, Canvas.ALL_SAVE_FLAG);
// 绘制蚂蚁森林的图片
canvas.drawBitmap(dstBmp, -dstWidth, -dstHeight, mPaint);
mPaint.setXfermode(mXfermode);
// 绘制填充物图片
canvas.drawBitmap(srcBmp, null, srcRect, mPaint);
mPaint.setXfermode(null);
// 恢复上次保存的图层
canvas.restoreToCount(saveCount);

这样就产生了叠加效果。

PorterDuff.Mode的各种效果:

3,让叠加效果动起来

如图,我们只需要不断改变srcBmp的显示区域,定时刷新界面就可以实现加载的动画效果了。

这里用了ValueAnimator从0到2*dstHeight,改变srcRect,然后刷新界面。

if (valueAnimator == null) {
	valueAnimator = ValueAnimator.ofFloat(0.0f, 2 * dstHeight);
	valueAnimator.setRepeatCount(ValueAnimator.INFINITE);
	valueAnimator.setRepeatMode(ValueAnimator.REVERSE);
	valueAnimator.setDuration(2000);
	valueAnimator.setStartDelay(0);
	valueAnimator.setInterpolator(new LinearInterpolator());
	valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
		@Override
		public void onAnimationUpdate(ValueAnimator animation) {
			float value = (float) animation.getAnimatedValue();
			srcRect = new RectF(-dstWidth, -dstHeight - value, dstWidth, 3 * dstHeight - value);
			AliLoadingView.this.invalidate();
		}
	});
	valueAnimator.start();
}

最后别忘了在onDetachedFromWindow()中取消valueAnimator,防止内存泄漏

@Override
protected void onDetachedFromWindow() {
    super.onDetachedFromWindow();
    if (valueAnimator != null) {
        valueAnimator.cancel();
    }
}

       

二,方法二

       这种叠加效果也可以利用矩形去裁剪有色的logo图片来实现,具体如下:

       1,生成目标Bitmap

       根据logo的bitmap-dstBmp,生成一个同样的bitmap,记为:srcBmp。

dstBmp = BitmapFactory.decodeResource(getResources(), R.mipmap.heart);

Bitmap.Config config = Bitmap.Config.ARGB_4444;
srcBmp = Bitmap.createBitmap(dstBmp.getWidth(), dstBmp.getHeight(), config);

       2,设置目标Bitmap的颜色

       通过ColorFilter来设置srcBmp的颜色:

Canvas canvas = new Canvas(srcBmp);

Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColorFilter(new PorterDuffColorFilter(mColor, PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(dstBmp, 0, 0, paint);

       3,生成裁剪矩形

       裁剪矩形是根据当前进度以及图片高度来算的,如下:

public void setProgress(int progress) {
    float rate = progress/100f;
    // 由于canvas做了居中平移,通过(0.5-rate)*dstHeight来计算高度
    mRect = new RectF(-dstWidth/2, (0.5f-rate)*dstHeight, dstWidth/2, dstHeight/2);
    invalidate();
}

       4,绘制

protected void onDraw(Canvas canvas) {
    canvas.translate(mWidth / 2, mHeight / 2);
    // 画原图
    canvas.drawBitmap(dstBmp, -dstWidth, -dstHeight, null);
    // 保存图层
    int saveCount = canvas.saveLayer(dstRect, mPaint, Canvas.ALL_SAVE_FLAG);
    // 画裁剪矩形
    canvas.drawRect(mRect, mPaint);
    // 设置叠加模式
    mPaint.setXfermode(mXfermode);
    // 画目标图
    canvas.drawBitmap(srcBmp,-dstWidth, -dstHeight, mPaint);
    // 还原画笔
    mPaint.setXfermode(null);
    // 还原图层
    canvas.restoreToCount(saveCount);
}

       结果和第一种方法一样,但这种方式更节省内存,因为第一张方式使用了原图3倍的Bitmap,而第二方式使用了原图2倍的Bitmap。

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值