本文來自網易雲社區android
做者:孫有軍git
產品中有一個需求,要求TextView的文字有一個高亮的效果,高亮的同時有跑馬燈效果!github
原本想在網上找一個現成的用用,好比Facebook出的Shimmer,還有不少,可是都感受代碼太多,所以擼了一個簡單版的,talk is cheap,show me you code。canvas
咱們知道TextView的文字的顏色是由Paint根據Color控制的,咱們能夠設置Paint的Shader來實現該效果,這樣在TextView繪製的時候Paint會從對應的Shader獲取color來實現繪製。既然TextView要高亮,說明文字顏色不一致,這裏咱們能夠設置一線性漸變shader,這樣就能夠設置不一樣部分的文字不一樣顏色。至於跑馬燈那就一直水平改變Shader就能夠實現。app
雖然是簡單的,仍是要通用,好比顏色能夠自定義,方向能夠設置,是否自動開始,這裏咱們先定義幾個屬性:ide
<declare-styleable name="ShimmerTextView"> <attr name="auto_start" format="boolean"></attr> <attr name="start_color" format="reference|color"></attr> <attr name="end_color" format="reference|color"></attr> <attr name="direction" format="boolean"></attr></declare-styleable>
這裏咱們分別控制了是否自動開始,開始顏色,結束顏色,方向 post
這裏咱們實現一個繼承自AppCompatTextView的自定義TextView。動畫
public class ShimmerTextView extends android.support.v7.widget.AppCompatTextView { public static final int OFFSET_ONE_TIME = 15; private Paint paint; private LinearGradient gradient; private Matrix matrix; private int w, h; private boolean horizontal; private boolean autoStart; private int startColor; private int endColor; private static final int DEFAULT_START_COLOR = 0xFFFF50ED; private static final int DEFAULT_END_COLOR = 0xFF3455FF; private float offset = 0; private ValueAnimator animator; public ShimmerTextView(Context context) { super(context); init(context, null); } public ShimmerTextView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); init(context, attrs); } public ShimmerTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context, attrs); } private void init(Context context, AttributeSet attrs) { paint = getPaint(); matrix = new Matrix(); TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.ShimmerTextView); autoStart = array.getBoolean(R.styleable.ShimmerTextView_auto_start, false); startColor = array.getColor(R.styleable.ShimmerTextView_start_color, DEFAULT_START_COLOR); endColor = array.getColor(R.styleable.ShimmerTextView_end_color, DEFAULT_END_COLOR); horizontal = array.getBoolean(R.styleable.ShimmerTextView_direction, true); array.recycle(); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); this.w = w; this.h = h; setGradient(); } private void setGradient() { if (horizontal) { gradient = new LinearGradient(0, 0, w, 0, new int[]{startColor, endColor, startColor}, new float[]{0, 0.5f, 1.0f}, Shader.TileMode.CLAMP); } else { gradient = new LinearGradient(0, 0, 0, h, new int[]{startColor, endColor, startColor}, new float[]{0, 0.5f, 1.0f}, Shader.TileMode.CLAMP); } paint.setShader(gradient); invalidate(); if (autoStart) { play(); } } public void play() { ValueAnimator animator = getAnimator(); if (animator.isRunning()) { return; } animator.start(); } @NonNull private ValueAnimator getAnimator() { if (animator == null) { animator = ValueAnimator.ofFloat(0.0f, 1.0f); animator.setDuration(500); animator.setRepeatCount(ValueAnimator.INFINITE); animator.setRepeatMode(ValueAnimator.RESTART); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { offset += OFFSET_ONE_TIME; if (horizontal) { if (offset > w) { offset = -w; } } else { if (offset > h) { offset -= h; } } invalidate(); } }); } return animator; } public void stop() { if (animator != null) { animator.cancel(); } } public void reset() { if (animator != null) { animator.cancel(); animator = null; } } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); reset(); } @Override protected void onDraw(Canvas canvas) { matrix.setTranslate(offset, 0); gradient.setLocalMatrix(matrix); super.onDraw(canvas); } }
上面的代碼主要先解析了自定義屬性,以後設置了一個線性漸變來改變文字的顏色,以後採用了ValueAnimator來水平移動線性漸變,同時從新繪製內容。this
ValueAnimator 咱們設置了一直重複動畫,ValueAnimator就是一個數值發生器,其實能夠用Handler與post來實現相同的效果。只要按必定速率改變線性漸變就能夠code
須要注意的是當距離大於整個View的寬度或者高度時,須要從新開始
最後咱們在界面中使用該控件:
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.demo.example.activity.ShimmerViewActivity"> <com.demo.example.widget.ShimmerTextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_marginBottom="8dp" android:layout_marginLeft="8dp" android:layout_marginRight="8dp" android:layout_marginTop="8dp" android:gravity="center" android:text="我愛北京天安門" android:textSize="25sp" app:auto_start="true" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintHorizontal_bias="0.502" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.148"/> </android.support.constraint.ConstraintLayout>
在Activity中設置該控件,運行效果。
網易雲免費體驗館,0成本體驗20+款雲產品!
更多網易研發、產品、運營經驗分享請訪問網易雲社區
相關文章:
【推薦】 網易雲易盾朱浩齊:視聽行業步入強監管和智能時代