『自定义View实战』—— 仿ios图标下载view
字数统计:
1,198 字
|
阅读时长:
5 分
| 本文总阅读量: 次
在工作中难免遇到自定义 View
的相关需求,本身这方面比较薄弱,因此做个记录,也是自己学习和成长的积累。自定义View实战.
前言
最近项目需要接入环信客服 SDK
,我配合这同事完成,其中我负责文件下载这部分。
因为时间比较紧张,8 天的时间完成 环信客服模块 的接入,就直接用了环信提供的 UI
控件,但是一些细节的部分, UI
还是会给出设计图,按照设计图完成最终效果。
UI
那边直接让我参考 IOS
的实现效果:
最终效果
源码请看 DownloadLoadingView
功能分析
面对这样的需要应该怎么实现呢?其实实现的方式可能不止我想的这种,我就讲述一下我是如何处理的。
首先,可以分成三部分:
- 半透明的背景
- 全透明的环
- 实心全透明的弧
那怎么实现背景半透明,而圆环和弧又是全透明的。顿时有个想法,要是两张图片重叠的部分能被抠出掉,也就是变成全透明,那岂不是非常容易就实现了。
圆环和弧既然是盖在了背景上,理当直接变成透明。那 Android
有对应处理的 API
吗?答案是肯定的。 setXfermode() 用于设置图像的过度模式,其中 PorterDuff.Mode.CLEAR 为清除模式则可以实现上述的效果。
具体实现
一系列的初始化
1 2 3 4 5 6 7 8 9 10 11 12 13
| 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); }
|
记得需要关闭硬件加速,不然会没有效果。
绘制背景
1 2 3 4
| paint.setColor(mBackgroundColor); paint.setStyle(Paint.Style.FILL); RectF round = new RectF(0, 0, getWidth(), getHeight()); canvas.drawRoundRect(round, mRoundRadius, mRoundRadius, paint);
|
设置背景颜色,样式为填充,绘制圆角矩形
绘制圆环
1 2 3 4 5 6
| paint.setColor(Color.RED); paint.setStrokeWidth(mStrokeWidth);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); paint.setStyle(Paint.Style.STROKE); canvas.drawCircle(getWidth() / 2, getHeight() / 2, mRadius, paint);
|
圆环的颜色可以随意设置,毕竟最后会被抠除掉,
设置 PorterDuff.Mode.CLEAR
类型模式绘制圆环
绘制圆
1 2 3 4 5 6
| 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);
paint.setXfermode(null);
|
根据当前的进度绘制相对应的弧,并且结束的时候将 Xfermode
模式置为 null
。
这样效果就结束了,贼简单。完整的代码请看 DownloadLoadingView
拓展
文中提到了 PorterDuff.Mode
,里面存储了大量的枚举,当我们需要处理图像的时候就会用到,但是对每种类型并没有特别的了解。每次使用的时候都需要查资料,然后确定到底需要使用哪种模式。
1 2 3 4 5 6 7 8
| public Xfermode setXfermode(Xfermode xfermode) { long xfermodeNative = 0; if (xfermode != null) xfermodeNative = xfermode.native_instance; native_setXfermode(mNativePaint, xfermodeNative); mXfermode = xfermode; return xfermode;。 }
|
具体的模式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| public enum Mode { CLEAR (0), SRC (1), DST (2), SRC_OVER (3), DST_OVER (4), SRC_IN (5), DST_IN (6), SRC_OUT (7), DST_OUT (8), SRC_ATOP (9), DST_ATOP (10), XOR (11), DARKEN (12), LIGHTEN (13), MULTIPLY (14), SCREEN (15), ADD (16), OVERLAY (17); Mode(int nativeInt) { this.nativeInt = nativeInt; }
public final int nativeInt; }
|
注释中已经说明了该模式到的透明度计算和颜色的计算方式,首先我们要了解一下基本的概念:
1 2 3 4
| Sa:全称为Source alpha,表示源图的Alpha通道; Sc:全称为Source color,表示源图的颜色; Da:全称为Destination alpha,表示目标图的Alpha通道; Dc:全称为Destination color,表示目标图的颜色.
|
来看一下权威的展示图:
我觉得 各个击破搞明白 PorterDuff.Mode 这篇文章写的特别好,不是很懂的小伙伴可以看一下,在这里也表示一下感谢。
#rewardButton {
background-color: #ea6f5a;
}
.btn-pay {
margin-bottom: 20px;
padding: 8px 25px;
font-size: 16px;
color: #fff;
background-color: #ea6f5a;
}
.btn {
display: inline-block;
margin-bottom: 0;
font-weight: 400;
text-align: center;
vertical-align: middle;
touch-action: manipulation;
cursor: pointer;
background-image: none;
border: 1px solid transparent;
white-space: nowrap;
padding: 6px 12px;
font-size: 14px;
line-height: 1.42857;
border-radius: 4px;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
#QR img{
height: 200px;
height: 200px;
margin: 20px;
}