想做一个让文字有类似金属光泽效果的动画。效果如下:
分享一下实现思路,使用kotlin实现。需求是需要有很好的移植性,可以修改设置光泽颜色,光泽宽度,光泽速度,光泽角度。
最后的结果是只要一行代码即可调用:
start_bt.setOnClickListener {
mTextView.setBling()
}
stop_bt.setOnClickListener {
mTextView.setBling(isStop = true)
}
复制代码
当然,也可以通过一些参数来设置一些效果mTextView.setBling(blingWidth = 80f,angle = 20f,speed = 6f)
这里的mTextView就是一个普通的TextView。我使用的是kotlin的扩展方法,对TextView进行了拓展,方便调用。
想要实现这种效果,我的思路是给paint设置LinearGradient。然后移动LinearGradient的位置就可以了。
第一步就是拿到TextView的paint,在TextView中找到private final TextPaint mTextPaint;
这个mTextPaint就是用来绘制文字的。
但是mTextPaint是一个私有变量,不能访问到,于是我想通过反射拿到mTextPaint。
补充:感谢 @vi1zen 的留言,是有getPaint()
方法可以拿到mTextPaint
!
代码如下:
//也可以使用getPaint()方法拿到mTextPaint
val class1 = Class.forName("android.widget.TextView")
val field = class1.getDeclaredField("mTextPaint")
field.isAccessible = true
var paint = field.get(this) as TextPaint
复制代码
然后给mTextPaint设置LinearGradient:
this.context.runOnUiThread {
paint.shader = lg
this@blingText.postInvalidate()
}
复制代码
这里的lg,就是一个LinearGradient对象,设置完LinearGradient之后,呼叫重绘。
我用到LinearGradient是这样的: LinearGradient(0f + position, 0f, blingWidth + position, angle, textColor, blingColor, Shader.TileMode.MIRROR)
光泽的位置变化是通过position变量实现的,我用到了一个线程,并且把这个线程保存到tag里面。
完整代码如下,可以放置到项目中任意位置:
package top.greendami.blingview
import android.graphics.Color
import android.graphics.LinearGradient
import android.graphics.Shader
import android.text.TextPaint
import android.widget.TextView
import org.jetbrains.anko.runOnUiThread
/**
* Created by GreendaMi on 2018/1/16.
*/
//是否有动画
fun TextView.isBling(): Boolean {
if (this.tag != null) {
var mT = this.tag as Thread
return mT.isAlive
}
return false
}
fun TextView.setBling(textColor: Int = Color.BLACK, blingColor: Int = Color.WHITE, blingWidth: Float = this.textSize, isStop: Boolean = false, speed: Float = 4f,angle :Float = 0f) {
var position = 0f
//如果已经有发光效果
if (this.tag != null) {
var mT = this.tag as Thread
mT.interrupt()
this.tag = null
blingText(null)
}
if (isStop) {
return
}
var mThread = Thread(Runnable {
while (!Thread.currentThread().isInterrupted) {
//下一帧
position += speed
blingText(LinearGradient(0f + position, 0f, blingWidth + position, angle, textColor, blingColor, Shader.TileMode.MIRROR))
try {
//延迟
Thread.sleep(100)
} catch (ex: InterruptedException) {
Thread.currentThread().interrupt()
}
}
})
this.tag = mThread
mThread.start()
}
private fun TextView.blingText( lg: LinearGradient?) {
try {
val class1 = Class.forName("android.widget.TextView")
val field = class1.getDeclaredField("mTextPaint")
field.isAccessible = true
//拿到画笔对象
var paint = field.get(this) as TextPaint
this.context.runOnUiThread {
//设置LinearGradient
paint.shader = lg
//呼叫重绘
this@blingText.postInvalidate()
}
} catch (e: Exception) {
e.printStackTrace()
}
}
复制代码
为了方便我用了anko,implementation "org.jetbrains.anko:anko-commons:0.10.4"
代码github