Android 字体渐变色--LinearGradient

2022-07-24  本文已影响0人  逃离_102

说明

Android开发过程中,对TextView操作是无时不刻的操作,字体颜色控制又是这里最常见的操作之一。常见的布局文件直接设置字体颜色,或者普通的setColor方法就不介绍了,这里记录一下渐变色LinearGradient的一些基础用法。

LinearGradient常用构造函数

LinearGradient通常用于控制TextView字体中的渐变颜色,主要有2个构造方法:
1,LinearGradient(float x0, float y0, float x1, float y1,@ColorInt int color0, @ColorInt int color1,@NonNull TileMode tile);
2,LinearGradient(float x0, float y0, float x1, float y1, @NonNull @ColorInt int[] colors,@Nullable float[] positions, @NonNull TileMode tile)

LinearGradient常用构造函数,参数说明

参数说明:
x0:表示渐变的起始点x坐标;
y0:表示渐变的起始点y坐标;
x1:表示渐变的终点x坐标;
y1:表示渐变的终点y坐标;
colors:表示渐变的颜色数组;
positions:用来指定颜色数组的相对位置;
color0: 表示渐变开始颜色;
color1: 表示渐变结束颜色;
tile:表示平铺方式

Shader.TileMode说明

Shader.TileMode有3种参数可供选择,分别为CLAMP、REPEAT和MIRROR:
1,CLAMP:如果渲染器超出原始边界范围,则会复制边缘颜色对超出范围的区域进行着色;
2,REPEAT:在横向和纵向上以平铺的形式重复渲染位图;
3,MIRROR:在横向和纵向上以镜像的方式重复渲染位图

其他注意说明

注意:通常,参数positions设为null,表示颜色数组以斜坡线的形式均匀分布

用法示例1

继承 TextView,重写 onLayout 方法后设置 Shader,也可再ondraw中处理

public class GradientTextView1 extends AppCompatTextView {
    private int mStartColor;
    private int mEndColor;
    private boolean mBold;

    public GradientTextView1(@NonNull Context context) {
        this(context, null);
    }

    public GradientTextView1(@NonNull Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public GradientTextView1(@NonNull Context context, @Nullable AttributeSet attrs,
                             int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs);
    }

    private void init(@NonNull Context context, @Nullable AttributeSet attrs) {
        TypedArray typedArray =
                context.obtainStyledAttributes(attrs, R.styleable.GradientTextView);
        if (typedArray == null) {
            return;
        }

        mBold = typedArray.getBoolean(R.styleable.GradientTextView_gradient_bold,
                                      false);
        mStartColor =
                typedArray.getColor(R.styleable.GradientTextView_gradient_start_color,
                                    getResources().getColor(R.color.primary_color));
        mEndColor =
                typedArray.getColor(R.styleable.GradientTextView_gradient_end_color,
                                    getResources().getColor(R.color.accent_color));
        typedArray.recycle();
        if (mBold) {
            getPaint().setFakeBoldText(true);
        }
    }

    @SuppressLint("DrawAllocation")
    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        if (changed) {
            getPaint().setShader(new LinearGradient(0, 0, getWidth(), getHeight(),
                    mStartColor,
                    mEndColor,
                    Shader.TileMode.CLAMP));
        }
    }  
}

用法示例2

自定一个工具方法,在代码中动态改变

public class TextViewUtil {
    public static void setTextColorGradient(TextView textView, @ColorRes int startColor, @ColorRes int endColor) {
        if (textView == null || textView.getContext() == null) {
            return;
        }
        Context context = textView.getContext();
        @ColorInt final int sc = context.getResources().getColor(startColor);
        @ColorInt final int ec = context.getResources().getColor(endColor);
        final float x = textView.getPaint().getTextSize() * textView.getText().length();
        LinearGradient gradient = new LinearGradient(0, 0, x, 0, sc, ec, Shader.TileMode.CLAMP);
        textView.getPaint().setShader(gradient);
        textView.invalidate();
    }

    public static void setTextColorGradient(TextView textView, int[] colors, float[] positions) {
        if (textView == null || textView.getContext() == null) {
            return;
        }
        
        String text = textView.getText().toString();
        // 方法1:getTextBounds
        Rect rect = new Rect();
        textView.getPaint().getTextBounds(text, 0, text.length(), rect);
        // 方法2:measureText
//        float measuredWidth = textView.getPaint().measureText(text);
        float textWidth = rect.width();
        LinearGradient linearGradient = new LinearGradient(0, 0, textWidth, 0,
                colors,
                positions,
                Shader.TileMode.REPEAT);
        textView.getPaint().setShader(linearGradient);
        textView.invalidate();
    }


    public static void clearTextColorGradient(TextView textView) {
        textView.getPaint().setShader(null);
        textView.invalidate();
    }

用法示例3

借鉴Span做法,自定义一个Span;也可直接写个Span,在代码中再去用

<declare-styleable name="GradientTextView">
    <attr name="gradient_text" format="string" />
    <attr name="gradient_bold" format="boolean" />
    <attr name="gradient_start_color" format="color" />
    <attr name="gradient_end_color" format="color" />
</declare-styleable>

public class GradientTextView extends AppCompatTextView {
    private String mGradientText;
    private int mStartColor;
    private int mEndColor;
    private boolean mBold;

    public GradientTextView(@NonNull Context context) {
        this(context, null);
    }

    public GradientTextView(@NonNull Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public GradientTextView(@NonNull Context context, @Nullable AttributeSet attrs,
                                  int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs);
    }

    private void init(@NonNull Context context, @Nullable AttributeSet attrs) {
        TypedArray typedArray =
                context.obtainStyledAttributes(attrs, R.styleable.GradientTextView);
        if (typedArray == null) {
            return;
        }
        mGradientText =
                typedArray.getString(R.styleable.GradientTextView_gradient_text);
        mBold = typedArray.getBoolean(R.styleable.GradientTextView_gradient_bold,
                                      false);
        mStartColor =
                typedArray.getColor(R.styleable.GradientTextView_gradient_start_color,
                                    getResources().getColor(R.color.primary_color));
        mEndColor =
                typedArray.getColor(R.styleable.GradientTextView_gradient_end_color,
                                    getResources().getColor(R.color.accent_color));
        typedArray.recycle();
        setGradientText(mGradientText);
        if (mBold) {
            getPaint().setFakeBoldText(true);
        }
    }

    public void setGradientText(String text) {
        if (text == null || text.length() == 0) {
            return;
        }
        SpannableString spannableString = new SpannableString(text);
        GradientFontSpan gradientFontSpan = new GradientFontSpan(mStartColor, mEndColor);
        spannableString.setSpan(gradientFontSpan, 0, text.length(),
                                Spanned.SPAN_INCLUSIVE_INCLUSIVE);
        setText(spannableString);
        invalidate();
    }

    public static class GradientFontSpan extends ReplacementSpan {
        private int mSize;
        private int mStartColor;
        private int mEndColor;

        public GradientFontSpan(int startColor, int endColor) {
            mStartColor = startColor;
            mEndColor = endColor;
        }

        public GradientFontSpan(Context context) {
            mStartColor = context.getResources().getColor(R.color.primary_color);
            mEndColor = context.getResources().getColor(R.color.accent_color);
        }

        @Override
        public int getSize(@NonNull Paint paint, CharSequence text, int start, int end,
                           @Nullable Paint.FontMetricsInt fm) {
            mSize = Math.round(paint.measureText(text, start, end));
            Paint.FontMetricsInt metrics = paint.getFontMetricsInt();
            if (fm != null) {
                fm.top = metrics.top;
                fm.ascent = metrics.ascent;
                fm.descent = metrics.descent;
                fm.bottom = metrics.bottom;
            }
            return mSize;
        }

        @Override
        public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, float x,
                         int top, int y, int bottom, @NonNull Paint paint) {
            LinearGradient gradient = new LinearGradient(0, 0, mSize, 0, mEndColor, mStartColor,
                                                         Shader.TileMode.CLAMP);
            paint.setShader(gradient);
            canvas.drawText(text, start, end, x, y, paint);
        }
    }
}

就说到这了,有什么不对的地方,欢迎指正,有什么没说全的,欢迎讨论留言

上一篇下一篇

猜你喜欢

热点阅读