Android 仿QQ控件变色的EditText/TextView

本人纯属博客小白,不会使用 Markdown 来编写博客,Android也才入门,可能实现起来存在缺陷,各位看官将就着看,一起交流。


最近QQ空间添加了一个新的功能,说说可以自动变色,看起来还不错的样子,于是打算模仿看看。

它变色有两种形式,一种是整体颜色渐变;另一种是线性渐变,也就是文字的头尾颜色发生变化

现在先说第一种,整体的颜色渐变。(线性渐变使用LinearGradient线性渲染实现,感兴趣可以自己去试试

编程先说思路:

1.既然是类似EditText/TextView,那肯定要画出用户指定的文字

2.既然要颜色渐变,那肯定是不断改变画笔的颜色


如果只是想模仿QQ空间的效果。后面有更简单的方法,前面先说最初的思路,自定义程度也是最高的。


首先,先在自定义view里面开放方法让用户设置需要显示的文字,同时在onDraw里面画出来就行了,大致代码如下:

    public void setText(String text){
        content=text;
    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.save();
        canvas.drawText(content,w,h,mPaint);
        canvas.restore();
    }

第一步,非常简单是不是,但是问题来了,万一用户没有调用setText,那么content就是null,会报空指针异常。那么解决方法有两个。

一个是初始化content="";一个实在drawText前加判断:

if (content==null){
            return;
        }
当然,除了这个之外你们还可以开放其他方法来设置字体、字体大小、字体显示位置等。也可以自定义attr,直接在XML设置就不用使用java代码设置了。


第二步无非是设置颜色,当然也需要开放方法或者定义attr。既然是渐变,我们肯定需要两种颜色。

public void setTextTransitionColor(int startColor,int endColor){
        this.startColor=startColor;
        this.endColor=endColor;
    }

起初我是这么想的,在这两种颜色中变化,直接一个属性动画不就行了么?变化范围就在这两种颜色之间就行了。然后我就这么写了

 private void startTransition() {
        ValueAnimator colorAnim =ValueAnimator.ofInt(startColor,endColor);
        colorAnim.setDuration(repeatTime);
        colorAnim.setRepeatMode(ValueAnimator.REVERSE);
        colorAnim.setRepeatCount(ValueAnimator.INFINITE);
        colorAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mPaint.setColor((Integer) animation.getAnimatedValue());
                invalidate();
            }
        });
        colorAnim.start();
        isAnim=true;
    }

然后...那颜色变化简直就是闪瞎眼啊,就算装有钛合金狗眼也瞎了,根本不是那种缓和的渐变效果,而是快速变化!举个例子,你设置开始颜色值0X000000,结束颜色值0xFFFFFF,那么值就会从0X000000变化到0xFFFFFF,在短短一两秒内,什么颜色都出现了,并不是我们需要的效果。


那么怎么样才能实现渐变?以下就是最主要的颜色渐变算法了。

既然这样子不行,我们仔细想想,QQ空间那颜色的变化的感觉只在设定的两种颜色中变化,就像是现实中把两种颜色按不同的比例进行调和,从1:0--0:1,不就是这种效果么

?那么我们也来“调和”一下好了。

既然要调和,我们用什么来调整两种颜色比例呢?没错,就是透明度。把两种颜色覆盖在一起,通过不断调整深度值,不就达到了我们的效果了么?

首先需要先把用户设定的颜色分解成ARGB,然后通过调整深度值,再把两种颜色相加,就完成了调和的效果,深度从0%-100%,也就是0-->1:

 private void startTransition() {
        ValueAnimator colorAnim =ValueAnimator.ofFloat(0,1);
        colorAnim.setDuration(repeatTime);
        colorAnim.setRepeatMode(ValueAnimator.REVERSE);
        colorAnim.setRepeatCount(ValueAnimator.INFINITE);

        //颜色分解
        sa=Color.alpha(startColor);
        sr=Color.red(startColor);
        sg=Color.green(startColor);
        sb=Color.blue(startColor);

        ea=Color.alpha(endColor);
        er=Color.red(endColor);
        eg=Color.green(endColor);
        eb=Color.blue(endColor);

        colorAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                //随着时间的变化开始颜色的深度 1-->0
                float sv = (float)animation.getAnimatedValue();
                随着时间的变化结束颜色的深度 0-->1
                float  ev= 1f-(float)animation.getAnimatedValue();
                //就是调用 mPaint.setColor(Color.argb(a,r,g,b)),里面的a,r,g,b是调和后的颜色
                //这里需要分别计算颜色深度在想加
                mPaint.setColor(Color.argb((int)(ea*ev+sa*sv),(int)(sr*sv+er*ev),(int)(sg*sv+eg*ev),(int)(sb*sv+eb*ev)));
                invalidate();
            }
        });
        colorAnim.start();
        isAnim=true;
    }

这样就实现了我们想要的效果,效果图:

大家还需要注意的是这两行代码:

colorAnim.setRepeatMode(ValueAnimator.REVERSE);
        colorAnim.setRepeatCount(ValueAnimator.INFINITE);

要让颜色一直渐变下去,需要设置动画重复次数为无限次,

这样还不行,例如你设置的颜色是红,绿  那么变化就是 红-->绿 立马变化红,在重复红-->绿 也就是从绿到红不是渐变的,看起来十分突兀。所以设置重复Mode为反转即可,就是colorAnim.setRepeatMode(ValueAnimator.REVERSE);


那什么时候开启这个动画呢?当然是用户设置颜色之后了,你在用户设定颜色的方法里面电影这个动画的方法就行了:

  public void setTextTransitionColor(int startColor,int endColor){
        this.startColor=startColor;
        this.endColor=endColor;
        startTransition();
    }

那么简单的颜色渐变效果就有了,我之所以说这个自定义程度最高是因为这个View是继承View的,你可以进行其他额外的拓展。

如果你想只是实现QQ空间的效果,并且保留有原生EditText/TextView的属性和方法,更简单的方法就是直接继承EditText/TextView,然后根据我们上面的颜色调和的方法,调用他们的setTextColor就行了,这里以EditText为例:

public class ColorEditText extends AppCompatEditText {
    private int repeatTime;
    private int sa,sr,sg,sb,ea,er,eg,eb;
    public ColorEditText(Context context) {
        super(context);
    }
    public ColorEditText(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    public ColorEditText(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
    public void setTextTransitionColor(int startColor,int endColor){
        sa= Color.alpha(startColor);
        sr=Color.red(startColor);
        sg=Color.green(startColor);
        sb=Color.blue(startColor);
        ea=Color.alpha(endColor);
        er=Color.red(endColor);
        eg=Color.green(endColor);
        eb=Color.blue(endColor);
        startTransition();
    }
    public void setRepeatTime(int repeatTime) {
        this.repeatTime = repeatTime;
    }
    private void startTransition() {
        ValueAnimator colorAnim =ValueAnimator.ofFloat(0,1);
        colorAnim.setDuration(repeatTime);
        colorAnim.setRepeatMode(ValueAnimator.REVERSE);
        colorAnim.setRepeatCount(ValueAnimator.INFINITE);
        colorAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float sv = (float)animation.getAnimatedValue();
                float  ev= 1f-(float)animation.getAnimatedValue();
                setTextColor(Color.argb((int)(ea*ev+sa*sv),(int)(sr*sv+er*ev),(int)(sg*sv+eg*ev),(int)(sb*sv+eb*ev)));
                invalidate();
            }
        });
        colorAnim.start();
    }
}

非常的简单是不是,也可以不用自定义直接在activity实现这个逻辑也行..

大概实现方法就这样的,预览图暂时没有,经过我测试已经完全可以模仿QQ空间的效果了,大家直接去QQ空间看预览图吧..


至于线性变化,有空再说...也不难,比这个还简单,大家感兴趣自己了解一下LinearGradient线性渲染就会了。


至于demo我在github上有,但是没有任何注释,没什么参考价值,大家有问题直接在下方评论就好了。


到此。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值