2010-04-21 37 views

Trả lời

16

Có vẻ như không thể mở rộng TextView để vẽ văn bản có độ dốc. Đó là, tuy nhiên, có thể đạt được hiệu ứng này bằng cách tạo ra một canvas và vẽ trên nó. Trước tiên, chúng ta cần phải declare our custom UI element. Trong quá trình bắt đầu, chúng ta cần tạo một lớp con của Layout. Trong trường hợp này, chúng tôi sẽ sử dụng BoringLayout chỉ hỗ trợ văn bản có một dòng.

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

Sau đó chúng tôi ghi đè 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); 
} 

thực hiện của chúng tôi onDraw là vào thời điểm này khá lười biếng (nó hoàn toàn bỏ qua các thông số kỹ thuật đo lường !, nhưng miễn là bạn đảm bảo rằng quan điểm là

Hoặc, có thể kế thừa từ một số Canvas và ghi đè phương pháp onPaint. Nếu điều này là d một, sau đó tiếc là các neo cho văn bản được rút ra sẽ luôn luôn được ở phía dưới vì vậy chúng tôi phải thêm -textPaint.getFontMetricsInt().ascent() vào tọa độ y của chúng tôi.

+0

Xin chào, bạn có thể thêm một số mã khác vào câu trả lời này không? Cụ thể, phần còn lại của bố cục mở rộng BoringLayout cảm ơn! – ekatz

+0

Tôi liên kết đến BoringLayout nên được bao gồm trong SDK – Casebash

3

Một giải pháp đơn giản nhưng phần nào hạn chế sẽ được sử dụng những thuộc tính này:

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

Tôi đã sử dụng nó trên textfields nơi tôi muốn họ mờ dần nếu họ nhận được quá lâu.

+0

Đó là một hack tốt đẹp. Tôi không cho rằng bạn có thể làm cho công việc đó theo chiều dọc? Không có bất kỳ tài sản android: scrollVertically nào xa như tôi có thể thấy – Casebash

+0

Xin lỗi, tôi không biết cách làm điều đó: ( – pgsandstrom

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 để làm cho nó đơn giản và hiệu quả hơn. –

+1

Cảm ơn một giải pháp rất đơn giản :) –

+1

Trên thiết bị ICS của tôi, điều này dường như không hoạt động - - nó hoàn toàn trong suốt.Bất cứ ai khác nhìn thấy cùng một điều? Chế độ xem không được tăng tốc phần cứng. –

9

Tôi đã xây dựng một thư viện bao gồm cả hai phương pháp này. Bạn có thể tạo GradientTextView bằng XML hoặc chỉ sử dụng GradientTextView.setGradient (TextView textView ...) để làm điều đó trên một đối tượng TextView thông thường.

https://github.com/koush/Widgets

1

đây là một cách tốt đẹp để làm điều đó:

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

Ngoài ra, nếu bạn muốn sử dụng một bitmap của gradient, thay vào đó hoặc một thực tế, sử dụng:

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

Dưới đây là hỗ trợ nhiều dòng như một lớp lót. Điều này cũng làm việc cho các nút.

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

+0

đơn giản và hoạt động tuyệt vời !! –

+0

Hoạt động, nhưng đối với chiều cao, bạn có thể muốn đưa vào các chữ cái tài khoản đi bên dưới dòng thực tế (như y, g, j, v.v.) và nhân dòng ánh sáng với 1.10f, ví dụ: 'textView.getLineHeight() * 1.10f'. –

Các vấn đề liên quan