Текст с градиентом в Android - PullRequest
56 голосов
/ 21 апреля 2010

Как бы я расширил TextView, чтобы разрешить рисование текста с эффектом градиента?

Ответы [ 8 ]

124 голосов
/ 23 февраля 2011
TextView secondTextView = new TextView(this);
Shader textShader=new LinearGradient(0, 0, 0, 20,
            new int[]{Color.GREEN,Color.BLUE},
            new float[]{0, 1}, TileMode.CLAMP);
secondTextView.getPaint().setShader(textShader);
20 голосов
/ 12 сентября 2018

Я использовал верхний ответ (@Taras) с градиентом 5 цветов, но есть проблема: textView выглядит так, как будто я наложил на него белую обложку. Вот мой код и скриншот.

        textView = (TextView) findViewById(R.id.main_tv);
        textView.setText("Tianjin, China".toUpperCase());

        TextPaint paint = textView.getPaint();
        float width = paint.measureText("Tianjin, China");

        Shader textShader = new LinearGradient(0, 0, width, textView.getTextSize(),
                new int[]{
                        Color.parseColor("#F97C3C"),
                        Color.parseColor("#FDB54E"),
                        Color.parseColor("#64B678"),
                        Color.parseColor("#478AEA"),
                        Color.parseColor("#8446CC"),
                }, null, Shader.TileMode.CLAMP);
        textView.getPaint().setShader(textShader);

enter image description here

Через много часов я обнаружил, что мне нужно позвонить textView.setTextColor() с первым цветом градиента. Тогда скриншот:

enter image description here

Надеюсь помочь кому-нибудь!

20 голосов
/ 27 апреля 2010

Невозможно расширить TextView для рисования текста с градиентом. Однако этого эффекта можно добиться, создав холст и рисуя на нем. Сначала нам нужно объявить наш элемент пользовательского интерфейса . В начале мы должны создать подкласс Layout . В этом случае мы будем использовать BoringLayout , который поддерживает текст только одной строкой.

Shader textShader=new LinearGradient(0, 0, 0, 20,
    new int[]{bottom,top},
    new float[]{0, 1}, TileMode.CLAMP);//Assumes bottom and top are colors defined above
textPaint.setTextSize(textSize);
textPaint.setShader(textShader);
BoringLayout.Metrics boringMetrics=BoringLayout.isBoring(text, textPaint);
boringLayout=new BoringLayout(text, textPaint, 0, Layout.Alignment.ALIGN_CENTER,
            0.0f, 0.0f, boringMetrics, false);

Затем мы переопределяем onMeasure и onDraw:

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
    setMeasuredDimension((int) textPaint.measureText(text), (int) textPaint.getFontSpacing());
}

@Override
protected void onDraw(Canvas canvas){
    super.onDraw(canvas);
    boringLayout.draw(canvas);
}

Наша реализация onDraw на данный момент довольно ленива (она полностью игнорирует характеристики измерения !, но до тех пор, пока вы гарантируете, что представлению предоставлено достаточно места, все должно работать нормально.

Кроме того, можно было бы наследовать от Canvas и переопределить метод onPaint. Если это будет сделано, то, к сожалению, привязка к рисуемому тексту всегда будет внизу, поэтому мы должны добавить -textPaint.getFontMetricsInt().ascent() к нашей координате y.

10 голосов
/ 18 июня 2011

Я свернул библиотеку, которая включает оба эти метода. Вы можете создать GradientTextView в XML или просто использовать GradientTextView.setGradient (TextView textView ...), чтобы сделать это для обычного объекта TextView.

https://github.com/koush/Widgets

9 голосов
/ 27 февраля 2016

Вот это с многострочной поддержкой в ​​один лайнер. Это должно работать и для кнопок.

Shader shader = new LinearGradient(0,0,0,textView.getLineHeight(),
                                  startColor, endColor, Shader.TileMode.REPEAT);
textView.getPaint().setShader(shader);
3 голосов
/ 21 апреля 2010

Простым, но несколько ограниченным решением было бы использовать эти атрибуты:

android:fadingEdge="horizontal"
android:scrollHorizontally="true"

Я использовал его в текстовых полях, где я хочу, чтобы они исчезали, если они становятся слишком длинными.

1 голос
/ 09 июля 2015

Вот хороший способ сделать это:

/**
 * sets a vertical gradient on the textView's paint, so that on its onDraw method, it will use it.
 *
 * @param viewAlreadyHasSize
 *            set to true only if the textView already has a size
 */
public static void setVerticalGradientOnTextView(final TextView tv, final int positionsAndColorsResId,
        final boolean viewAlreadyHasSize) {
    final String[] positionsAndColors = tv.getContext().getResources().getStringArray(positionsAndColorsResId);
    final int[] colors = new int[positionsAndColors.length];
    float[] positions = new float[positionsAndColors.length];
    for (int i = 0; i < positionsAndColors.length; ++i) {
        final String positionAndColors = positionsAndColors[i];
        final int delimeterPos = positionAndColors.lastIndexOf(':');
        if (delimeterPos == -1 || positions == null) {
            positions = null;
            colors[i] = Color.parseColor(positionAndColors);
        } else {
            positions[i] = Float.parseFloat(positionAndColors.substring(0, delimeterPos));
            String colorStr = positionAndColors.substring(delimeterPos + 1);
            if (colorStr.startsWith("0x"))
                colorStr = '#' + colorStr.substring(2);
            else if (!colorStr.startsWith("#"))
                colorStr = '#' + colorStr;
            colors[i] = Color.parseColor(colorStr);
        }
    }
    setVerticalGradientOnTextView(tv, colors, positions, viewAlreadyHasSize);
}

/**
 * sets a vertical gradient on the textView's paint, so that on its onDraw method, it will use it. <br/>
 *
 * @param colors
 *            the colors to use. at least one should exist.
 * @param tv
 *            the textView to set the gradient on it
 * @param positions
 *            where to put each color (fraction, max is 1). if null, colors are spread evenly .
 * @param viewAlreadyHasSize
 *            set to true only if the textView already has a size
 */
public static void setVerticalGradientOnTextView(final TextView tv, final int[] colors, final float[] positions,
        final boolean viewAlreadyHasSize) {
    final Runnable runnable = new Runnable() {

        @Override
        public void run() {
            final TileMode tile_mode = TileMode.CLAMP;
            final int height = tv.getHeight();
            final LinearGradient lin_grad = new LinearGradient(0, 0, 0, height, colors, positions, tile_mode);
            final Shader shader_gradient = lin_grad;
            tv.getPaint().setShader(shader_gradient);
        }
    };
    if (viewAlreadyHasSize)
        runnable.run();
    else
        runJustBeforeBeingDrawn(tv, runnable);
}

public static void runJustBeforeBeingDrawn(final View view, final Runnable runnable) {
    final OnPreDrawListener preDrawListener = new OnPreDrawListener() {
        @Override
        public boolean onPreDraw() {
            view.getViewTreeObserver().removeOnPreDrawListener(this);
            runnable.run();
            return true;
        }
    };
    view.getViewTreeObserver().addOnPreDrawListener(preDrawListener);
}

Также, если вы хотите использовать растровое изображение градиента вместо реального, используйте:

/**
 * sets an image for the textView <br/>
 * NOTE: this function must be called after you have the view have its height figured out <br/>
 */
public static void setBitmapOnTextView(final TextView tv, final Bitmap bitmap) {
    final TileMode tile_mode = TileMode.CLAMP;
    final int height = tv.getHeight();
    final int width = tv.getWidth();
    final Bitmap temp = Bitmap.createScaledBitmap(bitmap, width, height, true);
    final BitmapShader bitmapShader = new BitmapShader(temp, tile_mode, tile_mode);
    tv.getPaint().setShader(bitmapShader);
}

РЕДАКТИРОВАТЬ: Альтернатива runJustBeforeBeingDrawn: https://stackoverflow.com/a/28136027/878126

0 голосов
/ 12 июля 2011

Вот пример для linearlayout, вы можете использовать этот пример и для textview, и в исходном коде не будет градиентного кодирования, вы получите исходный код и добавите код с самого сайта - http://android -codes-examples.blogspot.com/2011/07/design-linearlayout-or-textview-and-any.html

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...