ShimmerTextView

来源:互联网 发布:g92的编程实例 编辑:程序博客网 时间:2024/06/05 06:52

       产品中有一个需求,要求TextView的文字有一个高亮的效果,高亮的同时有跑马灯效果!

       本来想在网上找一个现成的用用,比如Facebook出的Shimmer,还有很多,但是都感觉代码太多,因此撸了一个简单版的,talk is cheap,show me you code

实现

       我们知道TextView的文字的颜色是由Paint根据Color控制的,我们可以设置Paint的Shader来实现该效果,这样在TextView绘制的时候Paint会从对应的Shader获取color来实现绘制。既然TextView要高亮,说明文字颜色不一致,这里我们可以设置一线性渐变shader,这样就可以设置不同部分的文字不同颜色。至于跑马灯那就一直水平改变Shader就可以实现。

属性定义

       虽然是简单的,还是要通用,比如颜色可以自定义,方向可以设置,是否自动开始,这里我们先定义几个属性:

<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>

这里我们分别控制了是否自动开始,开始颜色,结束颜色,方向

代码实现

       这里我们实现一个继承自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来水平移动线性渐变,同时重新绘制内容。

ValueAnimator 我们设置了一直重复动画,ValueAnimator就是一个数值发生器,其实可以用Handler与post来实现相同的效果。只要按一定速率改变线性渐变就可以

  • 需要注意的是当距离大于整个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中设置该控件,运行效果。

这里写图片描述

       截图效果有点糊

代码

       最后附上代码地址Code

原创粉丝点击