2010-04-21 76 views

回答

16

似乎無法擴展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); 

然後,我們覆蓋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實現在這一點上很懶惰(它完全忽略測量規範!但只要你保證視圖給出足夠的空間,它應該可以工作。

或者,可以從Canvas繼承並覆蓋onPaint方法。如果這是d一個,那麼不幸的是,繪製文本的錨將始終在底部,因此我們必須將-textPaint.getFontMetricsInt().ascent()添加到我們的y座標中。

+0

嗨,請問您能否在此答案中增加一些代碼?具體來說,BoringLayout的其餘部分擴展布局 謝謝! – ekatz 2011-05-10 18:39:13

+0

我鏈接到BoringLayout,它應該包含在SDK – Casebash 2011-05-10 21:25:29

3

一個簡單但比較有限的解決辦法是使用這些屬性:

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

我已經用它在哪裏,我希望他們淡出如果他們太久文本框。

+0

這是一個很好的黑客攻擊。我不認爲你可以垂直工作?沒有任何android:scrollVertically屬性,據我所見 – Casebash 2010-04-21 23:49:04

+0

對不起,我不知道該怎麼做:( – pgsandstrom 2010-04-22 06:46:27

104
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); 
+5

+1中,使它更簡單,更高效 – 2011-07-08 10:12:16

+1

感謝您提供了一個非常簡單的解決方案:) – 2011-08-12 07:44:54

+1

在我的ICS設備上,這似乎不起作用 - - 它是完全透明的。其他人看到同樣的事情?該視圖不是硬件加速的。 – 2012-03-01 01:14:59

9

我已經卷起了一個包含這兩種方法的庫。您可以使用XML創建GradientTextView,或者使用GradientTextView.setGradient(TextView textView ...)在常規TextView對象上執行該操作。

https://github.com/koush/Widgets

1

這裏是一個很好的方式做到這一點:

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

這裏是多行支持作爲一個班輪。這也適用於按鈕。

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

+0

簡單和卓越的作品! – 2016-03-25 05:31:55

+0

工程,但對於高度,你可能要考慮低於實際線的字母(如y,g,j等),並將lineheight乘以1.10f, 'textView.getLineHeight()* 1.10f'。 – 2018-01-26 11:06:47