android - 用户界面 - 在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以绘制带有渐变的文本,但是,可以通过创建画布,并且在它上面绘图来实现这种效果,首先我们需要声明我们的自定义UI元素 ,在开始时,我们需要创建一个子类版式 ,在这里,我们将使用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);


}



在这一点上我们的实现相当懒惰(它完全忽略了度量规范,但是,只要你保证视图有足够的空间它应该能正常工作

另外,也可以从Canvas继承,并且重写onPaint方法,如果这样做,那么不幸的是,正在绘制的文本的锚将始终在底部,因此我们必须添加,-textPaint.getFontMetricsInt().ascent() 到我们的坐标。

我已经rolled了一个包含这些方法的库,你可以在XML中创建GradientTextView,或者只使用GradientTextView.setGradient(TextView textView...)在常规的TextView对象上。

https://github.com/koush/Widgets

这里是多行支持。这对于按钮也适用。


Shader shader = new LinearGradient(0,0,0,textView.getLineHeight(),


 startColor, endColor, Shader.TileMode.REPEAT);


textView.getPaint().setShader(shader);



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


android:fadingEdge="horizontal"


android:scrollHorizontally="true"



我把它用在textfield上,如果他们太长的话,我想让它们消失。

下面是一个不错的方法:


/**


 * 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

下面是linearlayout的一个例子,你也可以将此例子用于textview,在源代码中,不存在渐变编码,你得到源代码,并且从该站点本身添加代码- http://android-codes-examples.blogspot.com/2011/07/design-linearlayout-or-textview-and-any.html,

...