Nice programing

Android Textview 개요 텍스트

nicepro 2020. 10. 22. 22:47
반응형

Android Textview 개요 텍스트


텍스트가 검은 색 윤곽을 가질 수있는 간단한 방법이 있습니까? 다른 색상의 textview가 있지만 일부 색상이 내 배경에 잘 나타나지 않아서 검은 윤곽선을 쉽게 얻을 수있는 방법이 있는지 아니면 다른 작업을 수행 할 다른 방법이 있는지 궁금합니다. 사용자 정의보기를 만들고 캔버스 등을 만들 필요가 없습니다.


텍스트 뒤에 그림자를 두어 가독성을 높일 수 있습니다. 녹색 텍스트에 50 % 반투명 검은 그림자로 실험 해보십시오. 이를 수행하는 방법에 대한 자세한 내용은 여기에 있습니다. Android-텍스트에 그림자?

실제로 텍스트 주위에 획을 추가하려면 다음과 같이 좀 더 복잡한 작업을 수행해야합니다. Android의 MapView에서 테두리가있는 텍스트를 어떻게 그리나요?


윤곽 효과는 TextView의 그림자를 사용하여 얻을 수 있습니다.

    android:shadowColor="#000000"
    android:shadowDx="1.5"
    android:shadowDy="1.3"
    android:shadowRadius="1.6"
    android:text="CCC"
    android:textAllCaps="true"
    android:textColor="@android:color/white"

그래서 조금 늦었지만 MagicTextView 는 무엇 보다도 텍스트 윤곽선을 수행합니다.

여기에 이미지 설명 입력

<com.qwerjk.better_text.MagicTextView
    xmlns:qwerjk="http://schemas.android.com/apk/res/com.qwerjk.better_text"
    android:textSize="78dp"
    android:textColor="#ff333333"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    qwerjk:strokeColor="#FFff0000"
    qwerjk:strokeJoinStyle="miter"
    qwerjk:strokeWidth="5"
    android:text="Magic" />

참고 : 나는 이것을 만들었고 OP보다 미래의 여행자를 위해 더 많은 것을 게시하고 있습니다. 경계선 스팸이지만 주제와 관련이 있습니다.


프레임 워크는 text-shadow를 지원하지만 text-outline은 지원하지 않습니다. 그러나 트릭이 있습니다. 그림자는 반투명하고 희미 해지는 것입니다. 그림자를 몇 번 다시 그리면 모든 알파가 합산되고 결과가 윤곽선이됩니다.

매우 간단한 구현 TextViewdraw(..)메서드를 확장 하고 재정의합니다 . 추첨이 요청 될 때마다 우리의 서브 클래스는 5-10 개의 그림을 그립니다.

public class OutlineTextView extends TextView {

    // Constructors

    @Override
    public void draw(Canvas canvas) {
        for (int i = 0; i < 5; i++) {
            super.draw(canvas);
        }
    }

}


<OutlineTextView
    android:shadowColor="#000"
    android:shadowRadius="3.0" />

꽤 오래된 질문이지만 여전히 완전한 답을 볼 수 없습니다. 그래서 나는이 문제로 고군분투하는 누군가가 유용하다고 생각하기를 바라 면서이 솔루션을 게시하고 있습니다. 가장 간단하고 효과적인 솔루션은 TextView 클래스의 onDraw 메서드를 재정의하는 것입니다. 필자가 본 대부분의 구현에서는 drawText 메서드를 사용하여 스트로크를 그렸지만 해당 방식은 들어오는 모든 서식 정렬 및 텍스트 줄 바꿈을 고려하지 않습니다. 결과적으로 스트로크와 텍스트가 다른 위치에있는 경우가 많습니다. 다음 접근 방식은 super.onDraw를 사용하여 텍스트의 획과 채우기 부분을 모두 그리므로 나머지 부분에 대해 신경 쓸 필요가 없습니다. 단계는 다음과 같습니다.

  1. TextView 클래스 확장
  2. onDraw 메서드 재정의
  3. 페인트 스타일을 FILL로 설정
  4. 채우기 모드에서 텍스트를 렌더링하려면 Draw에서 부모 클래스를 호출합니다.
  5. 현재 텍스트 색상을 저장합니다.
  6. 현재 텍스트 색상을 획 색상으로 설정
  7. 페인트 스타일을 스트로크로 설정
  8. 획 너비 설정
  9. 그리고 부모 클래스 onDraw를 다시 호출하여 이전에 렌더링 된 텍스트 위에 획을 그립니다.

    package com.example.widgets;
    
    import android.content.Context;
    import android.content.res.TypedArray;
    import android.graphics.Canvas;
    import android.graphics.Paint;
    import android.graphics.Typeface;
    import android.util.AttributeSet;
    import android.widget.Button;
    
    public class StrokedTextView extends Button {
    
        private static final int DEFAULT_STROKE_WIDTH = 0;
    
        // fields
        private int _strokeColor;
        private float _strokeWidth;
    
        // constructors
        public StrokedTextView(Context context) {
            this(context, null, 0);
        }
    
        public StrokedTextView(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public StrokedTextView(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
    
            if(attrs != null) {
                TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.StrokedTextAttrs);
                _strokeColor = a.getColor(R.styleable.StrokedTextAttrs_textStrokeColor,
                        getCurrentTextColor());         
                _strokeWidth = a.getFloat(R.styleable.StrokedTextAttrs_textStrokeWidth,
                        DEFAULT_STROKE_WIDTH);
    
                a.recycle();
            }
            else {          
                _strokeColor = getCurrentTextColor();
                _strokeWidth = DEFAULT_STROKE_WIDTH;
            } 
            //convert values specified in dp in XML layout to
            //px, otherwise stroke width would appear different
            //on different screens
            _strokeWidth = dpToPx(context, _strokeWidth);           
        }    
    
        // getters + setters
        public void setStrokeColor(int color) {
            _strokeColor = color;        
        }
    
        public void setStrokeWidth(int width) {
            _strokeWidth = width;
        }
    
        // overridden methods
        @Override
        protected void onDraw(Canvas canvas) {
            if(_strokeWidth > 0) {
                //set paint to fill mode
                Paint p = getPaint();
                p.setStyle(Paint.Style.FILL);        
                //draw the fill part of text
                super.onDraw(canvas);       
                //save the text color   
                int currentTextColor = getCurrentTextColor();    
                //set paint to stroke mode and specify 
                //stroke color and width        
                p.setStyle(Paint.Style.STROKE);
                p.setStrokeWidth(_strokeWidth);
                setTextColor(_strokeColor);
                //draw text stroke
                super.onDraw(canvas);      
               //revert the color back to the one 
               //initially specified
               setTextColor(currentTextColor);
           } else {
               super.onDraw(canvas);
           }
       }
    
       /**
        * Convenience method to convert density independent pixel(dp) value
        * into device display specific pixel value.
        * @param context Context to access device specific display metrics 
        * @param dp density independent pixel value
        * @return device specific pixel value.
        */
       public static int dpToPx(Context context, float dp)
       {
           final float scale= context.getResources().getDisplayMetrics().density;
           return (int) (dp * scale + 0.5f);
       }            
    }
    

그게 다입니다. 이 클래스는 사용자 정의 XML 특성을 사용하여 XML 레이아웃 파일에서 획 색상 및 너비를 지정할 수 있도록합니다. 따라서 'res'폴더 아래의 'values'하위 폴더에있는 attr.xml 파일에 이러한 속성을 추가해야합니다. attr.xml 파일에 다음을 복사하여 붙여 넣으십시오.

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <declare-styleable name="StrokedTextAttrs">
        <attr name="textStrokeColor" format="color"/>    
        <attr name="textStrokeWidth" format="float"/>
    </declare-styleable>                

</resources>

이 작업을 마치면 XML 레이아웃 파일에서 사용자 정의 StrokedTextView 클래스를 사용하고 획 색상과 너비도 지정할 수 있습니다. 다음은 예입니다.

<com.example.widgets.StrokedTextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Stroked text sample"
    android:textColor="@android:color/white"
    android:textSize="25sp"
    strokeAttrs:textStrokeColor="@android:color/black"
    strokeAttrs:textStrokeWidth="1.7" />

패키지 이름을 프로젝트의 패키지 이름으로 바꾸는 것을 잊지 마십시오. 또한 사용자 정의 XML 속성을 사용하려면 레이아웃 파일에 xmlns 네임 스페이스를 추가하십시오. 레이아웃 파일의 루트 노드에 다음 줄을 추가 할 수 있습니다.

xmlns:strokeAttrs="http://schemas.android.com/apk/res-auto"

나는 이것을하는 방법을 알아 내려고 노력했지만 온라인에서 좋은 가이드를 찾을 수 없었지만 결국 알아 냈습니다. Steve Pomeroy가 제안했듯이 더 많은 작업을 수행해야합니다. 윤곽선이있는 텍스트 효과를 얻으려면 텍스트를 두 번 그립니다. 한 번은 두꺼운 윤곽선으로 한 다음 두 번째는 윤곽선 위에 주 텍스트를 그립니다. 그러나 SDK와 함께 제공되는 코드 샘플 중 하나, 즉 SDK 디렉토리에서 다음 이름 아래에있는 코드 샘플을 매우 쉽게 수정할 수 있으므로 작업이 더 쉬워집니다. "/ samples / android- / ApiDemos / src / com / example / android /apis/view/LabelView.java "입니다. 여기 Android 개발자 웹 사이트에서도 찾을 수 있습니다 .

수행중인 작업에 따라 TextView에서 확장하도록 변경하는 등 해당 코드를 약간만 수정하면됩니다.이 샘플을 발견하기 전에 onMeasure ()를 재정의하는 것을 잊었습니다. Android 개발자 웹 사이트의 "Building Custom Components"가이드에 언급 된대로 onDraw ()를 재정의하는 것 외에 추가로 수행해야합니다), 이것이 제가 문제가 발생한 이유의 일부입니다.

일단 완료하면 내가 한 일을 할 수 있습니다.

public class TextViewOutline extends TextView {

private Paint mTextPaint;
private Paint mTextPaintOutline; //add another paint attribute for your outline
...
//modify initTextViewOutline to setup the outline style
   private void initTextViewOutline() {
       mTextPaint = new Paint();
       mTextPaint.setAntiAlias(true);
       mTextPaint.setTextSize(16);
       mTextPaint.setColor(0xFF000000);
       mTextPaint.setStyle(Paint.Style.FILL);

       mTextPaintOutline = new Paint();
       mTextPaintOutline.setAntiAlias(true);
       mTextPaintOutline.setTextSize(16);
       mTextPaintOutline.setColor(0xFF000000);
       mTextPaintOutline.setStyle(Paint.Style.STROKE);
       mTextPaintOutline.setStrokeWidth(4);

       setPadding(3, 3, 3, 3);
}
...
//make sure to update other methods you've overridden to handle your new paint object
...
//and finally draw the text, mAscent refers to a member attribute which had
//a value assigned to it in the measureHeight and Width methods
   @Override
   protected void onDraw(Canvas canvas) {
       super.onDraw(canvas);
       canvas.drawText(mText, getPaddingLeft(), getPaddingTop() - mAscent, 
           mTextPaintOutline);
       canvas.drawText(mText, getPaddingLeft(), getPaddingTop() - mAscent, mTextPaint);
   }

따라서 윤곽선이있는 텍스트 효과를 얻으려면 텍스트를 두 번 그립니다. 한 번은 두꺼운 윤곽선으로 한 다음 두 번째는 윤곽선 위에 주 텍스트를 그립니다.


MagicTextView의 스트로크 IMO보다 더 잘 작동하는 트릭이 있습니다.

@Override
protected void onDraw(Canvas pCanvas) {
    int textColor = getTextColors().getDefaultColor();
    setTextColor(mOutlineColor); // your stroke's color
    getPaint().setStrokeWidth(10);
    getPaint().setStyle(Paint.Style.STROKE);
    super.onDraw(pCanvas);
    setTextColor(textColor);
    getPaint().setStrokeWidth(0);
    getPaint().setStyle(Paint.Style.FILL);
    super.onDraw(pCanvas);
}

개요가있는 텍스트를 수행하고 다른 모든 속성과 일반 텍스트보기의 그리기를 지원하는 클래스를 작성했습니다.

기본적으로 super.onDraw(Canves canvas)on을 사용 TextView하지만 다른 스타일로 두 번 그립니다.

도움이 되었기를 바랍니다.

public class TextViewOutline extends TextView {

    // constants
    private static final int DEFAULT_OUTLINE_SIZE = 0;
    private static final int DEFAULT_OUTLINE_COLOR = Color.TRANSPARENT;

    // data
    private int mOutlineSize;
    private int mOutlineColor;
    private int mTextColor;
    private float mShadowRadius;
    private float mShadowDx;
    private float mShadowDy;
    private int mShadowColor;

    public TextViewOutline(Context context) {
        this(context, null);
    }

    public TextViewOutline(Context context, AttributeSet attrs) {
        super(context, attrs);
        setAttributes(attrs);
    }

    private void setAttributes(AttributeSet attrs){ 
        // set defaults
        mOutlineSize = DEFAULT_OUTLINE_SIZE;
        mOutlineColor = DEFAULT_OUTLINE_COLOR;   
        // text color   
        mTextColor = getCurrentTextColor();
        if(attrs != null) {
            TypedArray a = getContext().obtainStyledAttributes(attrs,R.styleable.TextViewOutline);
            // outline size
            if (a.hasValue(R.styleable.TextViewOutline_outlineSize)) {
                mOutlineSize = (int) a.getDimension(R.styleable.TextViewOutline_outlineSize, DEFAULT_OUTLINE_SIZE);
            }
            // outline color
            if (a.hasValue(R.styleable.TextViewOutline_outlineColor)) {
                mOutlineColor = a.getColor(R.styleable.TextViewOutline_outlineColor, DEFAULT_OUTLINE_COLOR);
            }
            // shadow (the reason we take shadow from attributes is because we use API level 15 and only from 16 we have the get methods for the shadow attributes)
            if (a.hasValue(R.styleable.TextViewOutline_android_shadowRadius) 
                    || a.hasValue(R.styleable.TextViewOutline_android_shadowDx)
                    || a.hasValue(R.styleable.TextViewOutline_android_shadowDy) 
                    || a.hasValue(R.styleable.TextViewOutline_android_shadowColor)) {
                mShadowRadius = a.getFloat(R.styleable.TextViewOutline_android_shadowRadius, 0);
                mShadowDx = a.getFloat(R.styleable.TextViewOutline_android_shadowDx, 0);
                mShadowDy = a.getFloat(R.styleable.TextViewOutline_android_shadowDy, 0);
                mShadowColor = a.getColor(R.styleable.TextViewOutline_android_shadowColor, Color.TRANSPARENT);
            }

            a.recycle();
        }

        PFLog.d("mOutlineSize = " + mOutlineSize);
        PFLog.d("mOutlineColor = " + mOutlineColor);
    }

    private void setPaintToOutline(){
        Paint paint = getPaint();
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(mOutlineSize);
        super.setTextColor(mOutlineColor);
        super.setShadowLayer(mShadowRadius, mShadowDx, mShadowDy,  mShadowColor);
    }

    private void setPaintToRegular() {
        Paint paint = getPaint();
        paint.setStyle(Paint.Style.FILL);
        paint.setStrokeWidth(0);
        super.setTextColor(mTextColor);
        super.setShadowLayer(0, 0, 0, Color.TRANSPARENT);
    } 

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setPaintToOutline();
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    public void setTextColor(int color) {
        super.setTextColor(color);
        mTextColor = color;
    } 

    @Override
    public void setShadowLayer(float radius, float dx, float dy, int color) {
        super.setShadowLayer(radius, dx, dy, color);
        mShadowRadius = radius;
        mShadowDx = dx;
        mShadowDy = dy;
        mShadowColor = color;
    }

    public void setOutlineSize(int size){
        mOutlineSize = size;
    }

    public void setOutlineColor(int color){
       mOutlineColor = color;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        setPaintToOutline();
        super.onDraw(canvas);
        setPaintToRegular();
        super.onDraw(canvas);
    }

}

attr.xml

<declare-styleable name="TextViewOutline">
    <attr name="outlineSize" format="dimension"/>
    <attr name="outlineColor" format="color|reference"/>
    <attr name="android:shadowRadius"/>
    <attr name="android:shadowDx"/>
    <attr name="android:shadowDy"/>
    <attr name="android:shadowColor"/>
</declare-styleable>

아래 스 니펫을 사용하여 프로그래밍 방식으로이를 수행 할 수 있습니다. 검정색 배경에 흰색 글자를 제공합니다.

textView.setTextColor(Color.WHITE);            
textView.setShadowLayer(1.6f,1.5f,1.3f,Color.BLACK);

메서드의 매개 변수는 radius, dx, dy, color입니다. 특정 요구에 맞게 변경할 수 있습니다.

프로그래밍 방식으로 TextView를 만들고 xml에 포함하지 않는 사람을 도울 수 있기를 바랍니다.

stackOverflow 커뮤니티를 응원합니다!


@YGHM에 대한 크레딧 그림자 지원 추가 여기에 이미지 설명 입력

package com.megvii.demo;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;

public class TextViewOutline extends android.support.v7.widget.AppCompatTextView {

// constants
private static final int DEFAULT_OUTLINE_SIZE = 0;
private static final int DEFAULT_OUTLINE_COLOR = Color.TRANSPARENT;

// data
private int mOutlineSize;
private int mOutlineColor;
private int mTextColor;
private float mShadowRadius;
private float mShadowDx;
private float mShadowDy;
private int mShadowColor;

public TextViewOutline(Context context) {
    this(context, null);
}

public TextViewOutline(Context context, AttributeSet attrs) {
    super(context, attrs);
    setAttributes(attrs);
}

private void setAttributes(AttributeSet attrs) {
    // set defaults
    mOutlineSize = DEFAULT_OUTLINE_SIZE;
    mOutlineColor = DEFAULT_OUTLINE_COLOR;
    // text color   
    mTextColor = getCurrentTextColor();
    if (attrs != null) {
        TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.TextViewOutline);
        // outline size
        if (a.hasValue(R.styleable.TextViewOutline_outlineSize)) {
            mOutlineSize = (int) a.getDimension(R.styleable.TextViewOutline_outlineSize, DEFAULT_OUTLINE_SIZE);
        }
        // outline color
        if (a.hasValue(R.styleable.TextViewOutline_outlineColor)) {
            mOutlineColor = a.getColor(R.styleable.TextViewOutline_outlineColor, DEFAULT_OUTLINE_COLOR);
        }
        // shadow (the reason we take shadow from attributes is because we use API level 15 and only from 16 we have the get methods for the shadow attributes)
        if (a.hasValue(R.styleable.TextViewOutline_android_shadowRadius)
                || a.hasValue(R.styleable.TextViewOutline_android_shadowDx)
                || a.hasValue(R.styleable.TextViewOutline_android_shadowDy)
                || a.hasValue(R.styleable.TextViewOutline_android_shadowColor)) {
            mShadowRadius = a.getFloat(R.styleable.TextViewOutline_android_shadowRadius, 0);
            mShadowDx = a.getFloat(R.styleable.TextViewOutline_android_shadowDx, 0);
            mShadowDy = a.getFloat(R.styleable.TextViewOutline_android_shadowDy, 0);
            mShadowColor = a.getColor(R.styleable.TextViewOutline_android_shadowColor, Color.TRANSPARENT);
        }

        a.recycle();
    }

}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    setPaintToOutline();
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}

private void setPaintToOutline() {
    Paint paint = getPaint();
    paint.setStyle(Paint.Style.STROKE);
    paint.setStrokeWidth(mOutlineSize);
    super.setTextColor(mOutlineColor);
    super.setShadowLayer(0, 0, 0, Color.TRANSPARENT);

}

private void setPaintToRegular() {
    Paint paint = getPaint();
    paint.setStyle(Paint.Style.FILL);
    paint.setStrokeWidth(0);
    super.setTextColor(mTextColor);
    super.setShadowLayer(mShadowRadius, mShadowDx, mShadowDy, mShadowColor);
}


@Override
public void setTextColor(int color) {
    super.setTextColor(color);
    mTextColor = color;
}


public void setOutlineSize(int size) {
    mOutlineSize = size;
}

public void setOutlineColor(int color) {
    mOutlineColor = color;
}

@Override
protected void onDraw(Canvas canvas) {
    setPaintToOutline();
    super.onDraw(canvas);

    setPaintToRegular();
    super.onDraw(canvas);
}

}

속성 정의

<declare-styleable name="TextViewOutline">
    <attr name="outlineSize" format="dimension"/>
    <attr name="outlineColor" format="color|reference"/>
    <attr name="android:shadowRadius"/>
    <attr name="android:shadowDx"/>
    <attr name="android:shadowDy"/>
    <attr name="android:shadowColor"/>
</declare-styleable>

아래 xml 코드

<com.megvii.demo.TextViewOutline
    android:id="@+id/product_name"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center_horizontal"
    android:layout_marginTop="110dp"
    android:background="#f4b222"
    android:fontFamily="@font/kidsmagazine"
    android:padding="10dp"
    android:shadowColor="#d7713200"
    android:shadowDx="0"
    android:shadowDy="8"
    android:shadowRadius="1"
    android:text="LIPSTICK SET"
    android:textColor="@android:color/white"
    android:textSize="30sp"
    app:outlineColor="#cb7800"
    app:outlineSize="3dp" />

그래서 textview 주위에 스트로크를 원하십니까? 안타깝게도 스타일링을 할 수있는 간단한 방법은 없습니다. 다른보기를 만들고 텍스트보기를 위에 배치하여 상위보기 (위에있는보기)를 몇 픽셀 더 크게 만들어야합니다. 이렇게하면 윤곽선이 만들어집니다.


MagicTextView는 획 글꼴을 만드는 데 매우 유용하지만 제 경우에는 MagicTextView에서 설정 한 중복 배경 속성으로 인해 이와 같은 오류가 발생합니다.

따라서 attrs.xml 및 MagicTextView.java를 편집해야합니다.

attrs.xml

<attr name="background" format="reference|color" />
<attr name="mBackground" format="reference|color" />

MagicTextView.java 88:95

if (a.hasValue(R.styleable.MagicTextView_mBackground)) {
Drawable background = a.getDrawable(R.styleable.MagicTextView_mBackground);
if (background != null) {
    this.setBackgroundDrawable(background);
} else {
    this.setBackgroundColor(a.getColor(R.styleable.MagicTextView_mBackground, 0xff000000));
}
}

Nouman Hanif의 답변기반으로 몇 가지 추가 사항을 기반으로 라이브러리를 만들었습니다 . 예를 들어 View.invalidate () 호출에서 간접 무한 루프를 발생시킨 버그를 수정했습니다.

OTOH, 라이브러리는 또한 EditText 위젯에서 윤곽선이있는 텍스트를 지원합니다. 그것이 제 실제 목표 였고 TextView보다 약간 더 많은 작업이 필요했기 때문입니다.

다음은 내 라이브러리 링크입니다. https://github.com/biomorgoth/android-outline-textview

솔루션에 대한 초기 아이디어에 대해 Nouman Hanif에게 감사드립니다!


TextView 에서 상속하지 않고보기를 윤곽을 그리는 간단한 방법을 찾았습니다 . 나는 안드로이드의 스패너 블사용하여 텍스트를 요약 하는 간단한 라이브러리를 작성했습니다 . 이 솔루션은 텍스트의 일부만 윤곽을 그릴 수있는 가능성을 제공합니다.

같은 질문에 이미 답변했습니다 ( 답변 )

수업:

class OutlineSpan(
        @ColorInt private val strokeColor: Int,
        @Dimension private val strokeWidth: Float
): ReplacementSpan() {

    override fun getSize(
            paint: Paint,
            text: CharSequence,
            start: Int,
            end: Int,
            fm: Paint.FontMetricsInt?
    ): Int {
        return paint.measureText(text.toString().substring(start until end)).toInt()
    }


    override fun draw(
            canvas: Canvas,
            text: CharSequence,
            start: Int,
            end: Int,
            x: Float,
            top: Int,
            y: Int,
            bottom: Int,
            paint: Paint
    ) {
        val originTextColor = paint.color

        paint.apply {
            color = strokeColor
            style = Paint.Style.STROKE
            this.strokeWidth = this@OutlineSpan.strokeWidth
        }
        canvas.drawText(text, start, end, x, y.toFloat(), paint)

        paint.apply {
            color = originTextColor
            style = Paint.Style.FILL
        }
        canvas.drawText(text, start, end, x, y.toFloat(), paint)
    }

}

라이브러리 : OutlineSpan


성능 문제를 해결하기 위해 솔루션을 추가하고 싶습니다. 예를 들어, @YGHM 및 다른 몇 가지 답변이 작업을 수행하지만을 호출 onDraw하기 때문에 무한 호출이 발생 setTextColor합니다 invalidate(). 따라서이 문제를 해결하려면 진행 중일 때 획으로 그릴 때로 설정할 invalidate()변수 를 재정의 하고 추가 해야합니다 . 변수가이면 invalidate가 반환됩니다 .isDrawingtrueonDraw()true

override fun invalidate() {
    if (isDrawing) return
    super.invalidate()
  }

onDraw는 다음과 같습니다.

override fun onDraw(canvas: Canvas) {
    if (strokeWidth > 0) {
      isDrawing = true
      val textColor = textColors.defaultColor
      setTextColor(strokeColor)
      paint.strokeWidth = strokeWidth
      paint.style = Paint.Style.STROKE
      super.onDraw(canvas)
      setTextColor(textColor)
      paint.strokeWidth = 0f
      paint.style = Paint.Style.FILL
      isDrawing = false
      super.onDraw(canvas)
    } else {
      super.onDraw(canvas)
    }
  }

참고 URL : https://stackoverflow.com/questions/3182393/android-textview-outline-text

반응형