studio - Texto con degradado en Android
gradient android generator (7)
¿Cómo ampliaría TextView
para permitir el dibujo de texto con un efecto de degradado?
Aquí está con soporte multilínea como un trazador de líneas. Esto debería funcionar también para los botones.
textView.getPaint().setShader(new LinearGradient(0,0,0,textView.getLineHeight(), startColor, endColor, Shader.TileMode.REPEAT));
Aquí hay un ejemplo de linearlayout, también puede usar este ejemplo para la vista de texto, y en el código fuente no habrá codificación de gradiente, obtendrá el código fuente y agregará el código de ese sitio en sí mismo - http://android-codes-examples.blogspot.com/2011/07/design-linearlayout-or-textview-and-any.html
Aquí hay una buena manera de hacerlo:
/**
* 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);
}
Además, si desea utilizar un mapa de bits del gradiente, en su lugar o uno real, use:
/**
* 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);
}
EDITAR: alternativa para ejecutarJustBeforeBeingDrawn: https://.com/a/28136027/878126
He enrollado una biblioteca que abarca ambos métodos. Puede crear GradientTextView en XML o simplemente usar GradientTextView.setGradient (TextView textView ...) para hacerlo en un objeto TextView normal.
No parece posible extender TextView para dibujar texto con un degradado. Sin embargo, es posible lograr este efecto creando un lienzo y dibujando sobre él. Primero debemos declarar nuestro elemento personalizado de interfaz de usuario . En la iniciación, necesitamos crear una subclase de Layout . En este caso, usaremos BoringLayout que solo admite texto con una sola línea.
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);
Luego reemplazamos onMeasure
y 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);
}
Nuestra implementación de onDraw
es en este punto bastante vago (¡ignora por completo las especificaciones de medición!), Pero siempre que garantice que la vista tenga espacio suficiente, debería funcionar bien.
Alternativamente, sería posible heredar de un Canvas
y anular el método onPaint
. Si esto se hace, desafortunadamente el ancla para el texto que se está dibujando siempre estará en la parte inferior, así que tenemos que agregar -textPaint.getFontMetricsInt().ascent()
a nuestra coordenada y.
Una solución simple pero algo limitada sería usar estos atributos:
android:fadingEdge="horizontal"
android:scrollHorizontally="true"
Lo he usado en campos de texto en los que quiero que desaparezcan si se hacen demasiado largos.
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);