Android鬼點子-不用百行程式碼,讓文字閃閃發光

我是綠色大米呀發表於2019-03-04

想做一個讓文字有類似金屬光澤效果的動畫。效果如下:

圖1
分享一下實現思路,使用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

大兄弟,都看到這裡了,不點個贊嘛?評論666,有彩蛋!

Android鬼點子-不用百行程式碼,讓文字閃閃發光

相關文章