想做一個讓文字有類似金屬光澤效果的動畫。效果如下:
分享一下實現思路,使用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