Android实现仿iOS图标下载View动画效果

原文:安卓巴士

前言

最近项目需要接入环信客服 SDK ,我配合这同事完成,其中我负责文件下载这部分。

因为时间比较紧张,8 天的时间完成环信客服模块的接入,就直接用了环信提供的 UI 控件,但是一些细节的部分, UI 还是会给出设计图,按照设计图完成最终效果。

UI那边直接让我参考 IOS的实现效果:

UI效果

最终效果

最终效果

完整的代码请看:

https://github.com/xiaweizi/DownloadLoadingView

功能分析

面对这样的需要应该怎么实现呢?其实实现的方式可能不止我想的这种,我就讲述一下我是如何处理的。

预览图

首先,可以分成三部分:

  • 半透明的背景
  • 全透明的环
  • 实心全透明的弧

那怎么实现背景半透明,而圆环和弧又是全透明的。顿时有个想法,要是两张图片重叠的部分能被抠出掉,也就是变成全透明,那岂不是非常容易就实现了。

圆环和弧既然是盖在了背景上,理当直接变成透明。那 Android 有对应处理的 API吗?答案是肯定的。 setXfermode() 用于设置图像的过度模式,其中 PorterDuff.Mode.CLEAR 为清除模式则可以实现上述的效果。

具体实现

一系列的初始化

public DownloadLoadingView(Context context, AttributeSet attrs) {
    super(context, attrs);
    TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.DownloadLoadingView);
    mRadius = typedArray.getDimension(R.styleable.DownloadLoadingView_radius, RADIUS_DEFAULT);
    mStrokeWidth = typedArray.getDimension(R.styleable.DownloadLoadingView_strokeWidth, STROKE_WIDTH_DEFAULT);
    mMaxProgress = typedArray.getInteger(R.styleable.DownloadLoadingView_maxProgress, MAX_PROGRESS_DEFAULT);
    mRoundRadius = typedArray.getDimension(R.styleable.DownloadLoadingView_roundRadius, ROUND_RADIUS_DEFAULT);
    mBackgroundColor = typedArray.getColor(R.styleable.DownloadLoadingView_backgroundColor, getResources().getColor(R.color.bg_default));
    Log.i(TAG, "radius:" + mRadius);
    typedArray.recycle();
    setLayerType(View.LAYER_TYPE_SOFTWARE, null);//关闭硬件加速
    paint = new Paint(Paint.ANTI_ALIAS_FLAG);
}

记得需要关闭硬件加速,不然会没有效果。

绘制背景

paint.setColor(mBackgroundColor);
paint.setStyle(Paint.Style.FILL);
RectF round = new RectF(0, 0, getWidth(), getHeight());
canvas.drawRoundRect(round, mRoundRadius, mRoundRadius, paint);
设置背景颜色,样式为填充,绘制圆角矩形

设置背景颜色,样式为填充,绘制圆角矩形

绘制圆环

paint.setColor(Color.RED);
paint.setStrokeWidth(mStrokeWidth);
// 采用 clear 的方式
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
paint.setStyle(Paint.Style.STROKE);
canvas.drawCircle(getWidth() / 2, getHeight() / 2, mRadius, paint);

圆环的颜色可以随意设置,毕竟最后会被抠除掉,

设置 PorterDuff.Mode.CLEAR 类型模式绘制圆环

绘制圆

paint.setStyle(Paint.Style.FILL);float sweepAngle = 360 * mProgress / mMaxProgress;RectF rectF = new RectF(getWidth() / 2 - mRadius, getHeight() / 2 - mRadius, getWidth() / 2 + mRadius, getHeight() / 2 + mRadius);canvas.drawArc(rectF, -90, sweepAngle, true, paint);// 记得设置为 null 不然会没有效果paint.setXfermode(null);

根据当前的进度绘制相对应的弧,并且结束的时候将 Xfermode 模式置为 null

完整的代码请看:

https://github.com/xiaweizi/DownloadLoadingView

拓展

文中提到了 PorterDuff.Mode,里面存储了大量的枚举,当我们需要处理图像的时候就会用到,但是对每种类型并没有特别的了解。每次使用的时候都需要查资料,然后确定到底需要使用哪种模式。

public Xfermode setXfermode(Xfermode xfermode) {
    long xfermodeNative = 0;
    if (xfermode != null)
        xfermodeNative = xfermode.native_instance;
    native_setXfermode(mNativePaint, xfermodeNative);
    mXfermode = xfermode;
    return xfermode;。
}

具体的模式:

public enum Mode {
    /** [0, 0] */
    CLEAR       (0),
    /** [Sa, Sc] */
    SRC         (1),
    /** [Da, Dc] */
    DST         (2),
    /** [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] */
    SRC_OVER    (3),
    /** [Sa + (1 - Sa)*Da, Rc = Dc + (1 - Da)*Sc] */
    DST_OVER    (4),
    /** [Sa * Da, Sc * Da] */
    SRC_IN      (5),
    /** [Sa * Da, Sa * Dc] */
    DST_IN      (6),
    /** [Sa * (1 - Da), Sc * (1 - Da)] */
    SRC_OUT     (7),
    /** [Da * (1 - Sa), Dc * (1 - Sa)] */
    DST_OUT     (8),
    /** [Da, Sc * Da + (1 - Sa) * Dc] */
    SRC_ATOP    (9),
    /** [Sa, Sa * Dc + Sc * (1 - Da)] */
    DST_ATOP    (10),
    /** [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc] */
    XOR         (11),
    /** [Sa + Da - Sa*Da, Sc*(1 - Da) + Dc*(1 - Sa) + min(Sc, Dc)] */
    DARKEN      (12),
    /** [Sa + Da - Sa*Da, Sc*(1 - Da) + Dc*(1 - Sa) + max(Sc, Dc)] */
    LIGHTEN     (13),
    /** [Sa * Da, Sc * Dc] */
    MULTIPLY    (14),
    /** [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] */
    SCREEN      (15),
    /** Saturate(S + D) */
    ADD         (16),
    OVERLAY     (17);
    Mode(int nativeInt) {
        this.nativeInt = nativeInt;
    }
    /**
     * @hide
     */
    public final int nativeInt;
}

注释中已经说明了该模式到的透明度计算和颜色的计算方式,首先我们要了解一下基本的概念:

Sa:全称为Source alpha,表示源图的Alpha通道;
Sc:全称为Source color,表示源图的颜色;
Da:全称为Destination alpha,表示目标图的Alpha通道;
Dc:全称为Destination color,表示目标图的颜色.

来看一下权威的展示图:

mode预览图

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏运维前线

Jumpserver 1.0 安装脚本

版权声明:本文为木偶人shaon原创文章,转载请注明原文地址,非常感谢。 https://b...

19410
来自专栏机器学习入门

2018“云移杯- 景区口碑评价分值预测

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.n...

8720
来自专栏编程微刊

Vue框架Element UI教程-axios表格分页(九)

今天来写一个分页,表格分页在实际项目中经常用到,之前也写过关与bootstrap table 里面的表格分页,道理都差不多一样的,Element UI也有自己的...

74430
来自专栏每天进步一点点

electron仿制百度网盘客户端2(登录界面制作)

百度网盘客户端的尺寸是: 主界面 w:662px h:442px 顶部header h:75px bg:#EFF2F6

21040
来自专栏运维前线

Best Graphical Git Clients and Git Repository Viewers for Linux

Git is a free and open source distributed version control system for software ...

11210
来自专栏每天进步一点点

使用electron实现百度网盘悬浮窗口功能!

没有使用electron内置的-webkit-app-region: drag 因为使用他那个有很多问题 比如事件无法使用 右键无法使用 以及不能使用手型等!

24240
来自专栏运维前线

CentOS/RHEL 7/6 安装最新Git

版权声明:本文为木偶人shaon原创文章,转载请注明原文地址,非常感谢。 https://b...

22840
来自专栏MudOnTire

Vue项目中出现Loading chunk {n} failed问题的解决方法

最近有个Vue项目中会偶尔出现Loading chunk {n} failed的报错,报错来自于webpack进行code spilt之后某些bundle文件l...

25550
来自专栏机器学习入门

挑战程序竞赛系列(42):4.1模运算的世界(4)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.n...

9230
来自专栏每天进步一点点

内网穿透工具搭建(服务端and客户端)

最近一个项目需要用到将订单发布到第三方平台,之后要是有人购买他们会请求我们这边的接口来改变订单状态等!

14250

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励