代码之家  ›  专栏  ›  技术社区  ›  Casebash

Android中带渐变的文本

  •  55
  • Casebash  · 技术社区  · 14 年前

    我该怎么延长 TextView 允许使用渐变效果绘制文本?

    8 回复  |  直到 5 年前
        1
  •  117
  •   AskNilesh    5 年前
    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);
    
        2
  •  18
  •   Community Fabien Hure    7 年前

    似乎不可能扩展textView以使用渐变绘制文本。但是,可以通过创建画布并在其上绘制来实现此效果。首先我们需要 declare our custom UI element . 在初始阶段,我们需要创建 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坐标。

        3
  •  10
  •   koush    13 年前

    我已经建立了一个包含这两种方法的库。您可以在XML中创建GradientTextView,或者只使用GradientTextView.setGradient(textView textView…)在常规的textView对象上进行创建。

    https://github.com/koush/Widgets

        4
  •  8
  •   Dustin    8 年前

    在这里,多行支持作为一个线性。这也适用于按钮。

    textView.getPaint().setShader(new LinearGradient(0,0,0,textView.getLineHeight(), startColor, endColor, Shader.TileMode.REPEAT));

        5
  •  8
  •   hanswim    6 年前

    我用了5种颜色的最上面的答案(@taras),但是有一个问题: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

    希望能帮助别人!

        6
  •  3
  •   pgsandstrom    14 年前

    一个简单但有点局限的解决方案是使用这些属性:

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

    我在文本字段中使用它,如果文本字段太长,我希望它们淡出。

        7
  •  1
  •   android developer    6 年前

    这是一个很好的方法:

    /**
     * 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

        8
  •  0
  •   Android    13 年前

    下面是LinearLayout的一个示例,您也可以将这个示例用于textView,并且在源代码中不会有渐变编码,您可以获取源代码并从该站点本身添加代码。- http://android-codes-examples.blogspot.com/2011/07/design-linearlayout-or-textview-and-any.html