Androidtextviewアウトラインテキスト


83

テキストに黒い輪郭を付ける簡単な方法はありますか?異なる色のテキストビューがありますが、一部の色が背景にうまく表示されないので、黒い輪郭を取得する簡単な方法や、その仕事をする何か他のものがあるかどうか疑問に思いました。カスタムビューを作成したり、キャンバスなどを作成したりする必要はありません。


7
この質問を読んでPaint-Strokeソリューションの使用を検討している人は、Android4.4のストロークにバグがあることに注意してください。テキストサイズが256ピクセルを超えると、非常に奇妙なストロークレンダリングになります。回避策は、この回答に示されている代替方法を使用してアウトライン/ストロークを描画することです。ストロークタイプの回答ごとにこれをスパムしたくなかったので、ここに置いて、人々に気づかせ、私が経験した悲しみを救ってもらいました。
トニーチャン

回答:


56

テキストの後ろに影を付けることができます。これは、読みやすさを向上させることがよくあります。緑のテキストに50%の半透明の黒い影を試してみてください。これを行う方法の詳細はここにあります:Android-テキストの影?

テキストの周りに実際にストロークを追加するには、次のようにもう少し複雑なことを行う必要があり ます。AndroidのMapViewで境界線付きのテキストを描画するにはどうすればよいですか。


3
Android4.4にはストロークに関するバグがあることに注意してください。テキストサイズが256ピクセルを超えると、非常に奇妙なストロークレンダリングになります。回避策は、この回答に示されている代替方法を使用してアウトライン/ストロークを描画することです。
トニーチャン

このコメントは、テキストビューまたはフォントサイズのどちらを参照していますか?
ジョン

影は十分ではありません。白い背景のレイアウト上の白いテキストは、その黒い影ではまだ本当にひどく見えます
user9 2420

81

アウトライン効果は、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"

これが最善の解決策になるはずです。よかった!ありがとう
Renan Bandeira 2016

5
両面にしか表示されないため、アウトラインにはなりません。
ban-geoengineering 2018

私にぴったり!
ElyDantas20年

この影は輪郭に対して非常に弱い
user9 2420

55

したがって、少し遅れますが、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よりも将来の旅行者のために多く投稿しています。これは境界スパムですが、話題になっているので、おそらく受け入れられますか?


1
こんにちは、EditTextに入力されているテキストにこのような境界線を追加するにはどうすればよいですか?
TilalHusain 2014年

EditTextについて何かアイデアはありますか?
ピョートル・

dreamText.setStroke(4、Color.BLACK); dreamText.setTextColor(Color.WHITE); 私はこれらの設定を使用していますが、テキストの色は透明ですが、黒い輪郭が見えます。なにが問題ですか?
ムハンマドウマル

大丈夫ですが、実際には境界線を追加しません。それはむしろテキストを取り、同じ視覚的結果を与えない境界として外側の端を使用します。
Warpzit 2015年

1
このソリューションonDrawでは、のsetTextColor内部が呼び出されるため、再帰的に呼び出されonDrawます。
Sermilion

23

かなり古い質問ですが、それでも完全な答えは見当たりません。だから私はこの解決策を投稿しています。この問題に苦しんでいる誰かがそれが役立つことを願っています。最も簡単で効果的な解決策は、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レイアウトファイルからストロークの色と幅を指定できるようにします。したがって、これらの属性は、attr.xmlファイルのフォルダー 'res'の下のサブフォルダー 'values'に追加する必要があります。以下をコピーして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"

2
なんて素晴らしい、エレガントな解決策でしょう。私はこれを実装しました、そしてそれはうまくいきます。textStrokeWidthをディメンション(およびa.getDimensionPixelSize)に変更しました。ありがとう!
dgmltn 2015

1
うまくいきます、ありがとう。アウトラインがテキスト全体を引き継いだので、私の場合は順序を変更しました。最初にアウトラインがペイントされ、次にテキストがペイントされます。
mdiener 2016

2
よく働く。アウトラインをテストするためにAndroidStudioデザインビューを使用しないでください。表現は十分に正確ではありません。問題のないデバッグに2時間費やしました。
llmora 2016

7
このソリューションでは、setTextColor呼び出しが無効になるため、onDrawの数が無限になります。
Guliash

2
実際、@ Guliashは正しいです。テスト後、このメソッドが呼び出されるとinvalidate()、の内部動作に埋め込まれた呼び出しのために、それ自体を呼び出す無限ループが発生しますsetTextColor。コードの最後のすべての行をTextView独自のクラスにコピーする場合を除いて、これを回避する唯一の方法は、Reflectionを使用するプライベート mCurTextColorフィールドにブルートフォースアクセスすることTextViewです。参照してください、この答えはそれを行う方法を大まかに見て。を使用するfield.set(this, colorInt)代わりに使用してくださいfield.get()
verumCH 2018

23

フレームワークは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" />

3
どうもありがとうございました。ただし、私はむしろこのメソッドを使用します。 '@ Override protected void onDraw(Canvas canvas){for(int i = 0; i <5; i ++){super.onDraw(canvas); }} '
IHeartAndroid 2014

1
追加情報:少なくともContextとAttributeSetを使用してctorを実装する必要があります。そうでなければあなたは遭遇します。java.lang.NoSuchMethodException: <init> [class android.content.Context, interface android.util.AttributeSet
18年

15

私はこれを行う方法を理解しようとしていて、オンラインで良いガイドを見つけることができませんでしたが、最終的にそれを理解しました。スティーブ・ポメロイが示唆したように、あなたはもっと複雑なことをしなければなりません。アウトラインテキスト効果を得るには、テキストを2回描画します。1回目は太いアウトラインで、2回目はアウトラインの上にメインテキストを描画します。ただし、SDKで提供されるコードサンプルの1つ、つまりSDKディレクトリ内の次の名前のコードサンプルを非常に簡単に適応できるため、タスクは簡単になります: "/ samples / android- / ApiDemos / src / com / example / android /apis/view/LabelView.java」。これは、Android開発者のWebサイトにもあります

実行している内容によっては、TextViewから拡張するようにコードを変更するなど、コードに小さな変更を加えるだけでよいことが非常に簡単にわかります。このサンプルを見つける前に、onMeasure()をオーバーライドするのを忘れていました(これはAndroid DeveloperWebサイトの「BuildingCustomComponents」ガイドに記載されているように、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);
   }

したがって、アウトラインテキスト効果を得るには、テキストを2回描画します。1回目は太いアウトラインで、2回目はアウトラインの上にメインテキストを描画します。


9

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

}

attr define

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

8

これが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);
}

TextViewの右側がトリミングされているように見えますが、アウトラインがその側に完全に描画されていません...部屋が不足しているかのように
RoundSparrow hilltx 2014

7
もう一つ。setTextColorが再描画を強制しているのではないかと思います。これにより、このonDrawの無限ループが何度も呼び出されます。テスト中は、このメソッドにlogcatまたはその他のインジケーターを配置することをお勧めします。
RoundSparrow hilltx 2014

@RoundSparrowhilltxは正しいです。別の同様の回答へのコメントで述べたように、全体をコピーTextViewして自分のクラスに貼り付ける以外の唯一の方法は、Reflectionを使用してのプライベート mCurTextColorフィールドに直接アクセスすることだと思いますTextViewこの回答は、これを行う方法の一般的なガイドラインを提供します。ヒントとリンクのテキストにもストロークを付けたい場合は、mHintTextColorとを変更する必要がありmLinkTextColorます。残念ながら、変更mTextColorは参照されるだけなので、何もしません。
verumCH 2018

inはonDrawを永久にループします
user9 2420

8

アウトライン付きのテキストを実行し、他のすべての属性と通常のテキストビューの描画をサポートするクラスを作成しました。

基本的にはsuper.onDraw(Canves canvas)onを使用しますが、TextView異なるスタイルで2回描画します。

お役に立てれば。

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>

TypedArrayのa.recycle()がありません
Leos Literak 2017年

5

以下のスニペットを使用して、プログラムでこれを行うことができます。それは黒い背景で白い文字を提供します:

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

メソッドのパラメーターは、radius、dx、dy、colorです。特定のニーズに合わせて変更できます。

TextViewをプログラムで作成し、xml内に持たない人を助けたいと思います。

stackOverflowコミュニティに乾杯!


2

Nouman Hanifの回答に基づいて、いくつかの追加を加えたライブラリを作成しました。たとえば、View.invalidate()呼び出しで間接無限ループを引き起こしたバグを修正します。

OTOH、ライブラリはEditTextウィジェットのアウトラインテキストもサポートしています。これは私の本当の目標であり、TextViewよりも少し多くの作業が必要だったためです。

これが私のライブラリへのリンクです:https//github.com/biomorgoth/android-outline-textview

ソリューションの最初のアイデアを提供してくれたNoumanHanifに感謝します。


2

パフォーマンスの問題を解決するためにソリューションを追加したいと思います。例えば、@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)
    }
  }

1

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

1

TextViewから継承せずにビューのアウトラインを作成する簡単な方法を見つけました。私は、AndroidのSpannableを使用してテキストのアウトラインを作成する簡単なライブラリを作成しました。このソリューションは、テキストの一部のみを概説する可能性を提供します。

私はすでに同じ質問に答えていました(答え

クラス:

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


1
複数行のテキストはサポートされていません
user9 2420

0

それで、あなたはテキストビューの周りにストロークが欲しいですか?残念ながら、スタイリングでそれを行う簡単な方法はありません。別のビューを作成し、テキストビューを上に配置して、親ビュー(その上にあるビュー)をわずか数ピクセル大きくする必要があります。これにより、アウトラインが作成されます。


うーん、それはそれが価値があるよりももっと苦痛のように聞こえます。私が気にしているのは、白い背景で緑のテキストを読み取れるようにすることだけです(今のところ読みにくいです) img88.imageshack.us/i/devicez.png 赤はきれいに見えます。濃い緑色に変えただけかもしれませんが、なんらかの輪郭や何かが得られたらいいのにと思います
Falmarri 2010

それでは、テキスト自体の概要を説明しようとしていますか?独自のカスタムTextViewを実行しない限り、それはまだ実際には不可能ですが、おそらくそれは価値があるよりも多くの作業です。濃い緑色にするだけの方が簡単でしょう。
xil3 2010

2
赤/緑の色覚異常の人からのマイナーなリクエストの1つ:同じ赤/緑の情報の代替表現を追加することを検討してください。濃い緑と濃い赤を見るのは難しいことが多いためです。たぶん上向き/下向き矢印も?
スティーブポメロイ2010

それはスティーブの良い点です。おそらく将来的に追加するでしょう。
falmarri 2010

0

TextViewを拡張することで見つけることができる最も簡単な方法は次のとおりです

public class CustomTextView extends androidx.appcompat.widget.AppCompatTextView {

float mStroke;

public CustomTextView(Context context, @Nullable AttributeSet attrs) {
    super(context, attrs);
    TypedArray a = context.obtainStyledAttributes(attrs,
            R.styleable.CustomTextView);
    mStroke=a.getFloat(R.styleable.CustomTextView_stroke,1.0f);
    a.recycle();
}

@Override
protected void onDraw(Canvas canvas) {
    TextPaint paint = this.getPaint();
    paint.setStyle(Paint.Style.STROKE);
    paint.setStrokeWidth(mStroke);
    
    super.onDraw(canvas);
}
}

次に、attrs.xmlファイルに以下を追加するだけです。

<declare-styleable name="CustomTextView">
    <attr name="stroke" format="float"/>
</declare-styleable>

これでapp:stroke、TextViewの他のすべての望ましいプロパティを保持しながら、ストローク幅を設定できるようになります。私のソリューションは、塗りつぶしなしでストロークを描画するだけです。これにより、他の製品よりも少し簡単になります。カスタムフォントをcustomtextviewに設定しているときに、画面キャプチャに結果が表示されます。

ここに画像の説明を入力してください

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.