Tekst z gradientem w Androidzie

Jak rozszerzyć TextView, aby umożliwić rysowanie tekstu z efektem gradientu?

Author: Casebash, 2010-04-21

11 answers

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);
 136
Author: Taras,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-03-05 16:30:16

Użyłem górnej odpowiedzi (@Taras) z gradientem 5 kolorów, ale jest problem: textView wygląda tak, że umieściłem na nim białą okładkę. Oto Mój kod i zrzut ekranu.

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

Tutaj wpisz opis obrazka

Po wielu godzinach dowiedziałem się, że muszę zadzwonić textView.setTextColor() z pierwszym kolorem gradientu. Następnie zrzut ekranu:

Tutaj wpisz opis obrazka

Mam nadzieję, że ktoś pomoże!
 54
Author: hanswim,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-12 07:41:52

Nie wydaje się możliwe rozszerzenie TextView o rysowanie tekstu z gradientem. Można jednak osiągnąć ten efekt, tworząc płótno i rysując na nim. Najpierw musimy zadeklarować nasz niestandardowy element UI . W inicjacji musimy utworzyć podklasę Layout. W tym przypadku użyjemy BoringLayout , który obsługuje tylko tekst z pojedynczą linią.

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

Następnie nadpisujemy onMeasure i 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);
}

Nasza implementacja onDraw jest w tym momencie dość leniwy (całkowicie ignoruje specyfikacje pomiarowe!, ale tak długo, Jak gwarantujesz, że widok jest wystarczająco dużo miejsca, powinno działać dobrze.

Alternatywnie, możliwe byłoby dziedziczenie z Canvas i nadpisanie metody onPaint. Jeśli tak się stanie, to niestety kotwica dla rysowanego tekstu będzie zawsze na dole, więc musimy dodać -textPaint.getFontMetricsInt().ascent() do naszej współrzędnej y.

 21
Author: Casebash,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:18:17

Tutaj jest z podporą multiline jako jedną liner. To powinno działać również dla Przycisków.

Shader shader = new LinearGradient(0,0,0,textView.getLineHeight(),
                                  startColor, endColor, Shader.TileMode.REPEAT);
textView.getPaint().setShader(shader);
 13
Author: Dustin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-05-11 17:30:31

Zwinąłem bibliotekę, która obejmuje obie te metody. Możesz utworzyć GradientTextView w XML lub po prostu użyć GradientTextView.setGradient (TextView textView...), aby zrobić to na zwykłym obiekcie TextView.

Https://github.com/koush/Widgets

 10
Author: koush,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-18 00:04:12

Prostym, ale nieco ograniczonym rozwiązaniem byłoby użycie tych atrybutów:

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

Użyłem go na polach tekstowych, gdzie chcę, aby zniknęły, jeśli będą zbyt długie.

 3
Author: pgsandstrom,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-04-21 14:57:50

Oto fajny sposób na to:

/**
 * 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);
}

Również, jeśli chcesz użyć bitmapy gradientu, zamiast tego lub prawdziwej, użyj:

/**
 * 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);
}

EDIT: alternatywa dla runJustBeforeBeingDrawn: https://stackoverflow.com/a/28136027/878126

 1
Author: android developer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-10 10:06:37

Oto mój sposób na rozwiązanie. Zaimplementuj z rozpiętością tekstu. zrzut ekranu

class LinearGradientForegroundSpan extends CharacterStyle implements UpdateAppearance {
    private int startColor;
    private int endColor;
    private int lineHeight;

    public LinearGradientForegroundSpan(int startColor, int endColor, int lineHeight) {
        this.startColor = startColor;
        this.endColor = endColor;
        this.lineHeight = lineHeight;
    }

    @Override
    public void updateDrawState(TextPaint tp) {
        tp.setShader(new LinearGradient(0, 0, 0, lineHeight,
                startColor, endColor, Shader.TileMode.REPEAT));
    }
}

Stylizacja tekstu gradientowego.

    SpannableString gradientText = new SpannableString("Gradient Text");
    gradientText.setSpan(new LinearGradientForegroundSpan(Color.RED, Color.LTGRAY, textView.getLineHeight()),
            0, gradientText.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
    SpannableStringBuilder sb = new SpannableStringBuilder();
    sb.append(gradientText);
    sb.append(" Normal Text");
    textView.setText(sb);
 1
Author: beniozhang,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-05-03 14:34:34

Oto przykład linearlayout, możesz użyć tego przykładu również dla textview, a w kodzie źródłowym nie będzie kodowania gradientowego, otrzymasz kod źródłowy i dodasz kod z samej strony - http://android-codes-examples.blogspot.com/2011/07/design-linearlayout-or-textview-and-any.html

 0
Author: Android,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-07-12 05:23:45

Znalazłem sposób, aby to zrobić bez rozszerzenia klasy TextView.

class MainActivity : AppCompatActivity() {
    private val textGradientOnGlobalLayoutListener = object: ViewTreeObserver.OnGlobalLayoutListener {
        override fun onGlobalLayout() {
            textGradient.paint.shader = LinearGradient(0f, 0f,
                    textGradient.width.toFloat(),
                    textGradient.height.toFloat(),
                    color0, color1, Shader.TileMode.CLAMP)
            textGradient.viewTreeObserver.removeOnGlobalLayoutListener(this)
        }
    }
    private val textGradient by lazy {
        findViewById<TextView>(R.id.text_gradient)
    }
    private val color0 by lazy {
        ContextCompat.getColor(applicationContext, R.color.purple_200)
    }
    private val color1 by lazy {
        ContextCompat.getColor(applicationContext, R.color.teal_200)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        textGradient.viewTreeObserver.addOnGlobalLayoutListener(textGradientOnGlobalLayoutListener)
    }
}
 0
Author: Igor Konyukhov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-12-12 15:36:26

Połączyłem odpowiedzi z tego wątku i zrobiłem lekką bibliotekę. Możesz go używać z implementacją gradle lub po prostu użyć potrzebnych plików, dodając je do swojego źródła.

Https://github.com/veeyaarVR/SuperGradientTextView

 0
Author: VeeyaaR,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2021-01-06 06:07:35