在Android中使用渐变的文本

我如何扩展TextView以允许使用渐变效果绘制文本?

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

看起来不可能扩展TextView来绘制带有渐变的文本。 但是,可以通过创buildcanvas并在其上绘制来实现这一效果。 首先,我们需要声明我们的自定义用户界面元素 。 在开始,我们需要创build一个布局的子类。 在这种情况下,我们将使用仅支持单行文本的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); 

然后我们覆盖onMeasureonDraw

 @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实现在这一点上是非常懒惰的(它完全忽略了测量规格!但是只要你保证给视图足够的空间,它应该可以工作。

或者,可以从Canvasinheritance,并覆盖onPaint方法。 如果这样做了,那么不幸的是,绘制的文本的锚将始终在底部,所以我们必须添加-textPaint.getFontMetricsInt().ascent()到我们的y坐标。

我已经卷起了一个包含这两种方法的库。 您可以在XML中创buildGradientTextView,或者使用GradientTextView.setGradient(TextView textView …)在常规的TextView对象上执行此操作。

https://github.com/koush/Widgets

一个简单但有限的解决scheme是使用这些属性:

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

我已经在文本框中使用它,如果它们太长,我希望它们淡出。

这里是多行支持作为一个class轮。 这也适用于button。

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

这是一个很好的方法来做到这一点:

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

这里是一个linearlayout的例子,你也可以使用这个例子的textview,在源代码不会是梯度编码,你得到的源代码,并从该网站本身添加代码 – http:// android-codes-examples .blogspot.com / 2011/07 /devise的LinearLayout -或TextView的和- any.html