Programing

Android에서 그라디언트가있는 텍스트

lottogame 2020. 12. 28. 07:40
반응형

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

5 가지 색상의 그라디언트로 top answer (@Taras)를 사용했지만 문제가 있습니다. textView가 흰색 덮개를 씌운 것처럼 보입니다. 다음은 내 코드와 스크린 샷입니다.

        textView = (TextView) findViewById(R.id.main_tv);
        textView.setText("Tianjin, China".toUpperCase());

        TextPaint paint = textView.getPaint();
        float width = paint.measureText("Tianjin, China");

        Shader textShader = new LinearGradient(0, 0, width, textView.getTextSize(),
                new int[]{
                        Color.parseColor("#F97C3C"),
                        Color.parseColor("#FDB54E"),
                        Color.parseColor("#64B678"),
                        Color.parseColor("#478AEA"),
                        Color.parseColor("#8446CC"),
                }, null, Shader.TileMode.CLAMP);
        textView.getPaint().setShader(textShader);

여기에 이미지 설명 입력

몇 시간 후에 textView.setTextColor()그라디언트의 첫 번째 색상으로 호출해야한다는 것을 알았습니다 . 그런 다음 스크린 샷 :

여기에 이미지 설명 입력

누군가를 돕기를 바랍니다!


그라디언트로 텍스트를 그리기 위해 TextView를 확장 할 수 없습니다. 그러나 캔버스를 만들고 그 위에 그림을 그리면이 효과를 얻을 수 있습니다. 먼저 사용자 정의 UI 요소선언 해야합니다 . 초기에는 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);

그런 다음 onMeasure다음을 재정의합니다 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);
}

우리의 구현은 onDraw이 시점에서 상당히 게으르다 (측정 사양을 완전히 무시합니다!하지만 뷰에 충분한 공간이 제공된다는 것을 보장하는 한 정상적으로 작동합니다.

또는에서 상속 Canvas하고 onPaint메서드를 재정의 할 수 있습니다 . 이렇게하면 안타깝게도 그려지는 텍스트의 앵커가 항상 맨 아래에 있으므로 -textPaint.getFontMetricsInt().ascent()y 좌표 에 추가 해야합니다.


이 두 가지 방법을 모두 포함하는 라이브러리를 롤업했습니다. 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"

너무 길어지면 페이드 아웃되기를 원하는 텍스트 필드에 사용했습니다.


여기에 좋은 방법이 있습니다.

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

참조 URL : https://stackoverflow.com/questions/2680607/text-with-gradient-in-android

반응형