Android实现纯图片分享到qq,怎样做QQ上酷炫的人?看!Android仿QQ 发送图片时加载效果...

7123f7d49d5c21ba729b5bc8efd49582.png

之前看到qq 的图片发送效果很酷炫,很吸引人,不过现在这个效果好像没有了。

试了几次,决定试试实现。大致想了下,实现效果还不错需要实现的效果一图胜千言,看图如下:

499b6aeb60cdac5faf5e5aca383416ca.gif

怎样实现呢?

首先从图中看分两部分,一部分是进度条带光晕得效果。第二部分是圆圈扩散到整个图片,到显示完整图片的过程。接下来一步一步跟着代码分析实现。1、绘制的范围包括图片显示都在圆角矩形内,所以首先要裁剪

canvas到圆角矩形。

val path = Path()

canvas.save()

path.addRoundRect(RectF(0f, 0f, width.toFloat(), height.toFloat())

, round, round, Path.Direction.CW)

canvas.clipPath(path)

先保存画布,

save()到最后要

canvas.restore()。因为显示图片,可以有两种选择,第一种:自己绘制图片,通过

drawable得方式。第二种:继承ImageView 同时还可以获得ImageView提供的各种属性,

scaleType之类。本质上ImageView也是通Drawable实现。IamgeView还帮我们处理了测量的狂傲,所以有什么理由不选择继承呢。然后绘制图片只有简单一行代码,再裁剪画布之后:

super.onDraw(canvas)

2、绘制背景

可以看到效果图,图片在黑色半透明的下方。并且在最后显示出来。着一点都是跟canvas绘制背景相关的。不多说,先设置画笔。

private var paint: Paint = Paint()

paint.isAntiAlias = true

paint.color = getColor(R.color.bantouming)

背景怎么绘制,直接通过

canvas.drawPaint方法即可实现。把

paint的颜色绘制到整个画布。并且再图片后边绘制,所以在上方。

canvas.drawPaint(paint)

3、绘制进度

这里根据每一阶段状态的不同,通过三个状态值区分:

companion object {          private const val READY = 1

private const val PROGRESS = 2

private const val FINISH = 3

}

为了方便的绘制,并且整个view是对称的。所以坐标点移动到view中心,非常有利于实现。

canvas.save()

canvas.translate(width / 2f, height / 2f)

当然最后别忘了

canvas.restore() 。在中间都好说了。先看百分比的实现。主要是drawText()的x,y比较不好掌握,不过搞明白基线之类的,就没问题了。先看百分比的

paint

private val textPaint by lazy {

Paint().apply {

isAntiAlias = true

style = Paint.Style.STROKE

textSize = dp2px(16f).toFloat()

color = getColor(R.color.main_gray)

}

}

接下来绘制,这行代码可能比较长。需要优化,到这里就先别吐槽。有点偷懒。可以看到根据文字的宽,高。来绘制的。高这里需要额外注意

textPaint.textHeight().div(2) - textPaint.descent()

需要减去textPiat.descent(),如果不减绘制会偏下。

val text = "${progress}%"

canvas.drawText(text, 0 - textPaint.measureText(text).div(2), textPaint.textHeight().div(2) - textPaint.descent(), textPaint)

4、绘制光晕

这算是实现比较疑难的地方。要注意3个地方:

1.光晕的实现

2.呼吸效果

3.

PorterDuffXmode 使用。

先看呼吸效果如何实现。可能简单的想到的是通过圆环实现。但这样挺麻烦的,如果通过两个圆叠加,并设置

paint.xfermode(PorterDuff.Mode.DST_OUT)``,可实现把内部圆裁剪掉。关于怎么使用,请看之前的关于xfermode的文章。光晕的实现需要依赖shader

,这里通过RadilGradient

实现。具体用法也可看之前文章。设置shader`

paint.setShader(RadialGradient(0f, 0f, outRadius

, intArrayOf(Color.TRANSPARENT, Color.WHITE, Color.WHITE, Color.TRANSPARENT)

, floatArrayOf(0.1f, 0.4f, 0.8f, 1f), Shader.TileMode.CLAMP))

接下来的呼吸效果通过动画设置大圆半径的变化来实现。

canvas.drawCircle(0f, 0f, innRaduus + (outRadius - innRaduus) * animatorValue, paint)

完整代码如下

canvas.drawCircle(0f, 0f, innRaduus + (outRadius - innRaduus) * animatorValue, paint)

paint.setXfermode(PorterDuffXfermode(PorterDuff.Mode.DST_OUT))

paint.setShader(null)

paint.color = Color.WHITE

canvas.drawCircle(0f, 0f, innRaduus, paint)

paint.setXfermode(null)

如果仅仅是这样那么绘制出来中间喝一个黑洞。因为背景是透明的。所以这时候在绘制之前需要

canvas.savlayer。如下

val sc = canvas.saveLayer(-outRadius, -outRadius, outRadius, outRadius, paint, Canvas.ALL_SAVE_FLAG)

保存的范围包括大圆小圆最后要

restore

canvas.restoreToCount(sc)

再加上

animatorValue 从0到1的动画就完成PROGRES阶段的动画了。

5、绘制FINISH,揭露图片效果

同样这里也需要使用

PorterDuff.Mode.DST_OUT,不过这里需要的是对整个圆角画布范围进行操作。DST 是

canvas.drawPaint绘制的背景。

SRC 是一整个圆角矩形对角线的一半为最大半径,从

PROGRES 状态大圆的半径的范围,到最大范围的动画变化。如下:

val sc = canvas.saveLayer(-width.div(2f), -height.div(2f), width.div(2f), height.div(2f), paint, Canvas.ALL_SAVE_FLAG)

canvas.drawPaint(paint)

val maxRadius = Math.sqrt(Math.pow(width.toDouble(), 2.0) + Math.pow(height.toDouble(), 2.0)).div(2)

paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.DST_OUT)

paint.color = Color.WHITE

canvas.drawCircle(0f, 0f, (outRadius + (maxRadius - outRadius) * finishAnimValue).toFloat(), paint)

paint.xfermode = null

canvas.restoreToCount(sc)

动画的使用与交替。这一点比较简单的

ValueAnimator的使用,设置属性,

Listener即可。

用上了这个,你会成为qq上发图片最酷炫的崽,咱们程序们还是有很多有趣的事的,

当然。我们要学的东西有很多,多会一点技能,就多一层保障。

毕竟,要想不被环境淘汰就只有不断提升自己,从来都是我们去适应环境,而不是环境来适应我们!

附上我的Android核心技术大纲,获取相关内容来我的GitHub一起玩耍:

fe31067546114084508a05f024cb0b15.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值