Android酷炫加载进度动画
概述
详细
一、概述
本自定义动画进度酷炫View,是加载进度动画的自定义View,继承于ImageView来实现,主要实现蒙层加载进度的加载进度效果。
支持水平左右加载和垂直上下加载四个方向,同时也支持自定义蒙层进度颜色。
直接看下面的效果图吧。
二、效果图
废话不说,先来看看效果图吧~~
三、实现原理方案
1、自定义View-XCLoadingImageView,继承ImageVIew来实现,这样就不用自己再处理drawable和测量的工作内容。
2、根据蒙层颜色创建一个蒙层bitmap,然后根据这个bitmap来创建一个ClipDrawable,最后利用ClipDrawable的level属性
来裁剪显示区域进度,从而达到加载进度的效果。
3、最后利用属性动画技术或ClipDrawable的setLevel()方法来达到进度的效果。
四、自定义加载进度效果XCLoadingImageView的具体实现
1、初始化需要用到的数据变量以及画笔以及属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | private Paint mImagePaint; private int mImageHeight, mImageWidth; private boolean mIsAutoStart = false ; private int mMaskColor = Color.TRANSPARENT; private ClipDrawable mClipDrawable; private Drawable mMaskDrawable; private int maskHeight; private int mProgress; private ObjectAnimator mAnimator; private long mAnimDuration = 2500 ; private float mScaleX, mScaleY; private int mGravity = Gravity.BOTTOM; private int mOrientaion = ClipDrawable.VERTICAL; private int mMaskOrientation = MaskOrientation.BottomToTop; //Loading oriention public static final class MaskOrientation { public static final int LeftToRight = 1 ; public static final int RightToLeft = 2 ; public static final int TopToBottom = 3 ; public static final int BottomToTop = 4 ; } /** * initial attributes */ private void initAttrs(Context context, AttributeSet attrs) { if (attrs == null ) { return ; } TypedArray t = context.obtainStyledAttributes(attrs, R.styleable.XCLoadingImageView); mMaskColor = t.getColor(R.styleable.XCLoadingImageView_mask_color, mMaskColor); mIsAutoStart = t.getBoolean(R.styleable.XCLoadingImageView_auto_start_anim, mIsAutoStart); setMaskColor(mMaskColor); t.recycle(); } /** * initial paint */ private void init() { if (mImagePaint == null ) { mImagePaint = new Paint(Paint.ANTI_ALIAS_FLAG); mImagePaint.setXfermode( new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP)); } } |
2、初始化蒙层Bitmap以及创建加载进度用的ClipDrawable
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | private void initMaskBitmap( int maskColor) { Drawable drawable = getDrawable(); if (drawable == null ) { return ; } Bitmap bgBmp = ((BitmapDrawable) drawable).getBitmap(); mImageWidth = drawable.getIntrinsicWidth(); mImageHeight = drawable.getIntrinsicHeight(); Bitmap fgBmp = Bitmap.createBitmap(mImageWidth, mImageHeight, Bitmap.Config.ARGB_8888); Canvas fgCanvas = new Canvas(fgBmp); fgCanvas.drawColor(maskColor); Bitmap bitmap = combineBitmap(bgBmp, fgBmp); mMaskDrawable = new BitmapDrawable( null , bitmap); mClipDrawable = new ClipDrawable(mMaskDrawable, mGravity, mOrientaion); } |
3、合并蒙层Bitmap和ImageView的src的drawable为新的Bitmap
1 2 3 4 5 6 7 8 9 10 | /** * combine tow bitmap to one bitmap */ private Bitmap combineBitmap(Bitmap bg, Bitmap fg) { Bitmap bmp = Bitmap.createBitmap(mImageWidth, mImageHeight, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bmp); canvas.drawBitmap(bg, 0 , 0 , null ); canvas.drawBitmap(fg, 0 , 0 , mImagePaint); return bmp; } |
4、重写ImageVIew的onDraw()方法来把创建的ClipDrawable绘制到Canvas上
1 2 3 4 5 6 7 8 9 | @Override protected void onDraw(Canvas canvas) { super .onDraw(canvas); canvas.save(); canvas.scale(mScaleX, mScaleY); mClipDrawable.setBounds(getDrawable().getBounds()); mClipDrawable.draw(canvas); canvas.restore(); } |
5、弹通过属性动画或者setLevel,并调用postInvalidate()来重绘,从而达到进度刷新的效果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | private void initAnim() { stopAnim(); mAnimator = ObjectAnimator.ofInt(mClipDrawable, "level" , 0 , 10000 ); mAnimator.setDuration(mAnimDuration); mAnimator.setRepeatCount(ValueAnimator.INFINITE); mAnimator.setRepeatMode(ValueAnimator.RESTART); mAnimator.addUpdateListener( new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { postInvalidate(); } }); if (mIsAutoStart) { mAnimator.start(); } } public void setProgress( int progress){ mProgress = progress; mClipDrawable.setLevel(mProgress * 100 ); postInvalidate(); } |
五、如何使用该自定义LoadingView控件
1、使用该自定义LoadingView非常简单,和使用普通ImageView差不对哦,只需设置下方向和蒙层颜色即可
1 2 3 4 5 6 7 8 9 10 11 12 | public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.activity_main); XCLoadingImageView imageView2 = (XCLoadingImageView) findViewById(R.id.img2); imageView2.setMaskOrientation(XCLoadingImageView.MaskOrientation.LeftToRight); imageView2.setProgress( 50 ); } } |
六、项目结构目录截图
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· 使用C#创建一个MCP客户端
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· Windows编程----内核对象竟然如此简单?