天天看點

android 文字Flash特效

需要知道的技術點:

1.着色器

android中的着色器shader是非常有用接口。

例如現在多數的圓角圖檔還有類似flash效果文字都是有着色器功能完成。

着色器為畫筆Paint的成員變量,在畫筆繪制文字或者圖檔的是否起到渲染的作用。可以是邊框形狀渲染,或者顔色,漸變色等渲染。

2.屬性動畫

在漸變色渲染過程中,管道渲染的時間線就是屬性動畫的執行時間線,注意成員變量的值的類型與初始化動畫對象的方法要一緻,否則不會執行。

3.小坑

TileMode的CLAMP指的是如果目前渲染器在控件外部的話,那麼控件剩餘的顔色有顔色數組中最後位置的那個顔色填充,由于目前控件式TextView是以一開始文字顔色由gray填充。

在控件顯示過程中,onSizeChanged方式被調用一次而onLayout方法被調用兩次,是以在onSizeChanged方法中完成了着色器以及動畫的初始化。

移動距離最好設定為動畫執行過程中增量的2倍,避免出現邊界的字顯得沒有高亮,使得全部字都高亮一遍。

—-代碼是基于Shimmer寫的,有問題了再去研究他的代碼去吧。

android 文字Flash特效
private Context context;
private TextPaint paint;
private LinearGradient linearGradient;
private Matrix matrix;
private ObjectAnimator objectAnimator;
private boolean isInvoke = false;
private float gradientX;

public float getGradientX() {
    return gradientX;
}

public void setGradientX(float gradientX) {
    this.gradientX = gradientX;
    System.out.println("setGradientX");
    invalidate();
}

public FlashTextView(Context context, AttributeSet attrs) {
    super(context, attrs);
    init();
}

private void init() {
    paint = getPaint();
    matrix = new Matrix();
}

// 為什麼要在onSizeChanged中實作而不在onLayout中實作?因為onLayout中被調用了兩次,而onSizeChanged中被調用一次,不明白為什麼,但是列印日志确實是這樣。
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);

    objectAnimator = ObjectAnimator.ofFloat(this, "gradientX", 0,
            getWidth());
    objectAnimator.setDuration(1000);
    objectAnimator.setRepeatCount(ObjectAnimator.INFINITE);

    linearGradient = new LinearGradient(-getWidth(), 0, 0, 0, new int[] {
            Color.GRAY, Color.WHITE, Color.GRAY }, new float[] { 0f,
            0.5f, 1f }, TileMode.CLAMP);

    linearGradient.setLocalMatrix(matrix);
    paint.setShader(linearGradient);
}

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    if (!isInvoke) {
        animate.run();
    }

    matrix.setTranslate(2 * gradientX, 0);
    linearGradient.setLocalMatrix(matrix);

}

private Runnable animate = new Runnable() {
    @Override
    public void run() {
        isInvoke = true;
        objectAnimator.start();
    }
};