我们平时使用TextView往往让它作为一个显示文字的容器,但TextView的功能并不局限于此。在未来的几天里,我将会记录一些TextView的一些高级应用。
    今天就来聊聊淡入淡出的效果。淡入淡出的文字显示效果,其实很多地方都用到过,比如我们常去的新闻网站,里面忽闪忽闪的文字,就是这种,许多朋友刚看到这个的时候会想,不就是淡入淡出嘛,Android的动画里面早就有了。然而你要是这么想,我只能说:搜羊搜森剖。
    因为不知道插入视频,所以就不上视频了。我直接贴代码吧。
public class MutableForegroundColorSpan extends CharacterStyle implements
        UpdateAppearance {

    public static final String TAG = "MutableForegroundColorSpan";

    private int mColor;

    @Override
    public void updateDrawState(TextPaint tp) {
        tp.setColor(mColor);
    }

    public int getColor() {
        return mColor;
    }

    public void setColor(int color) {
        this.mColor = color;
    }
}
    这是一个实体类,用于储存文字的颜色以及更新动画状态。紧接着,我把主要的部分也贴上去,具体是怎么实现的,我最后再解释。
public class MarqueeText extends TextView {
    private String mTextString;
    private SpannableString mSpannableString;

    private double[] mAlphas;
    private MutableForegroundColorSpan[] mSpans;
    private boolean mIsVisible;
    private boolean mIsTextResetting = false;
    private int mDuration = 2500;

    ValueAnimator animator;
    ValueAnimator.AnimatorUpdateListener listener = new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator valueAnimator) {
            Float percent = (Float)valueAnimator.getAnimatedValue();
            resetSpannableString(mIsVisible ? percent : 2.0f - percent);
        }
    };

    public MarqueeText(Context context) {
        super(context);
        init();
    }

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

    private void init(){
        this.mIsVisible = false;
        animator = ValueAnimator.ofFloat(0.0f, 2.0f);
        animator.addUpdateListener(listener);
        animator.setDuration(mDuration);
    }

    public void toggle(){
        if (mIsVisible) {
            hide();
        } else {
            show();
        }
    }

    public void show(){
        mIsVisible = true;
        animator.start();
    }

    public void hide(){
        mIsVisible = false;
        animator.start();
    }

    public void setIsVisible(boolean isVisible){
        mIsVisible = isVisible;
        resetSpannableString(isVisible == true ? 2.0f : 0.0f);
    }

    public boolean getIsVisible(){
        return mIsVisible;
    }

    private void resetSpannableString(double percent){
        mIsTextResetting = true;

        int color = getCurrentTextColor();
        for (int i = 0; i < this.mTextString.length(); i++) {
            MutableForegroundColorSpan span = mSpans[i];
            span.setColor(Color.argb(clamp(mAlphas[i] + percent), Color.red(color), Color.green(color), Color.blue(color)));
        }

        setText(mSpannableString);

        mIsTextResetting = false;
    }

    private void resetAlphas(int length){
        mAlphas = new double[length];
        for(int i=0; i < mAlphas.length; i++){
            mAlphas[i] = Math.random()-1;
        }
    }

    private void resetIfNeeded(){
        if (!mIsTextResetting){
            mTextString = getText().toString();
            mSpannableString = new SpannableString(this.mTextString);
            mSpans = new MutableForegroundColorSpan[this.mTextString.length()];
            for (int i = 0; i < this.mTextString.length(); i++) {
                MutableForegroundColorSpan span = new MutableForegroundColorSpan();
                mSpannableString.setSpan(span, i, i+1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                mSpans[i] = span;
            }
            resetAlphas(mTextString.length());
            resetSpannableString(mIsVisible ? 2.0f : 0);
        }
    }

    public void setText(String text) {
        super.setText(text);
        resetIfNeeded();
    }

    @Override
    public void setText(CharSequence text, TextView.BufferType type) {
        super.setText(text, type);
        resetIfNeeded();
    }

    private int clamp(double f){
        return (int)(255*Math.min(Math.max(f, 0), 1));
    }

    public void setDuration(int duration){
        this.mDuration = duration;
        animator.setDuration(duration);
    }
}
    我们看到代码,这是一个自定义的TextView,另外,我们这里插入一个知识点:ValueAnimator,属性动画的一部分,关于属性动画,我准备在下几篇文章里面进行详细介绍。

ValueAnimator是属性动画的核心部分,它本身不提供任何动画效果,而更像是数值发生器,用来产生具有一定规律的数字,从而让调用者来控制动画的实现过程。它一般性用法如下:

    ValueAnimator animator;
    ValueAnimator.AnimatorUpdateListener listener = new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator valueAnimator) {
            Float percent = (Float) valueAnimator.getAnimatedValue();
            resetSpannableString(mIsVisible ? percent : 2.0f - percent);
        }
    };
    通常情况下,ValueAnimator 的AnimatorUpdateListener中监听数值的变换,从而完成动画的交换。

    截止目前,java代码的部分也就差不多了。就像其他的Textview拓展的使用一样,我们直接把自己的TextView全称放在XML布局文件里面。开始动画方法就是调用它的start()方法,好了,以上就是关于textview淡入淡出效果的全部实现过程了。
Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐