Android TextView大纲文本


82

有一种简单的方法可以使文本具有黑色轮廓吗?我的文本视图将使用不同的颜色,但是某些颜色无法很好地显示在我的背景中,所以我想知道是否有一种简单的方法来获得黑色轮廓或其他可以完成此工作的方法?我希望不必创建自定义视图并制作画布等。


6
对于阅读此问题并考虑使用Paint-Stroke解决方案的任何人,请注意Android 4.4中存在一个带有笔触错误。如果文本大小大于256像素,则将导致非常奇怪的笔画渲染。一种解决方法是使用此答案中提出的替代方法绘制轮廓/描边。我不想在每个笔划类型的答案中都使用垃圾邮件,因此将其放在此处可以使人们意识到并避免他们遭受我所经历的悲伤。
托尼·陈

Answers:


54

您可以在文字后面加上阴影,这通常可以提高可读性。尝试在绿色文字上尝试使用50%半透明的黑色阴影。有关如何执行此操作的详细信息在此处:Android-文字阴影?

要真正在文本周围添加笔触,您需要做一些更复杂的事情,例如: 在Android的MapView中如何在边框上绘制文本?


2
请注意,Android 4.4中存在笔画错误。如果文本大小大于256像素,则将导致非常奇怪的笔画渲染。一种解决方法是使用此答案中提出的替代方法绘制轮廓/描边。
托尼·陈

这个注释是否指的是文本视图还是字体大小?
约翰

阴影不够好,带有黑色阴影的白色背景布局上的白色文本看起来仍然很糟糕
user924

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

5
这不会导致轮廓,因为它仅在两侧显示。
ban-geoengineering

对我来说完美!!
Ely Dantas

这个阴影对于轮廓来说非常微弱
user924

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有什么想法吗?
Piotr

dreamText.setStroke(4,Color.BLACK); dreamText.setTextColor(Color.WHITE); 我正在使用这些设置,但我的文本颜色是透明的,我可以看到黑色轮廓。怎么了?
穆罕默德·乌玛

可以,但是并没有真正添加边框。而是采用文本并使用外部边缘作为边框,这不会产生相同的视觉效果。
Warpzit

1
onDraw由于中的调用setTextColor,此解决方案导致以递归方式调用onDraw
Sermilion '19

23

该框架支持文本阴影,但不支持文本轮廓。但是有一个窍门:阴影是半透明的并且会褪色的东西。重画阴影几次,所有的alpha值都被累加,结果是轮廓。

一个非常简单的实现扩展TextView并覆盖了该draw(..)方法。每次要求绘制图纸时,我们的子类都会绘制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
Bevor

22

这是一个很老的问题,但我仍然看不到任何完整的答案。因此,我正在发布此解决方案,希望有人对此问题进行努力可能会发现它有用。最简单,最有效的解决方案是重写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" />

请记住用您项目的包名称替换包名称。还要在布局文件中添加xmlns命名空间,以便使用自定义XML属性。您可以在布局文件的根节点中添加以下行。

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

2
多么棒的,优雅的解决方案!我实现了它,并且效果很好。我只是将textStrokeWidth更改为尺寸(和a.getDimensionPixelSize)。谢谢!
dgmltn

1
效果很好,谢谢。当他们勾勒出整个文本时,我改变了案子的顺序:首先绘制轮廓,然后绘制文本。
mdiener '16

2
效果很好。不要使用Android Studio设计视图测试轮廓,表示不够准确。刚花了2h调试了一个非问题。
llmora '16

7
该解决方案将导致无限数量的onDraw,因为setTextColor调用无效。
Guliash

1
实际上,@ Guliash是正确的。经过测试后,由于invalidate()埋在的内部工作中,因此调用此方法后会导致调用自身的无限循环setTextColor。除非您希望将每行代码的最后一行复制TextView到您自己的类中,否则我能看到的唯一方法是蛮力访问使用Reflection的私有 mCurTextColor字段TextView。查看此答案以大致了解如何做。只是使用field.set(this, colorInt)而不是使用field.get()
VerumCH '18年

15

我一直在尝试找出方法,但在网上找不到好的指南,但最终找到了答案。正如史蒂夫·波默罗伊(Steve Pomeroy)所建议的,您确实需要做更多的事情。为了获得轮廓文本效果,您需要绘制两次文本:一次轮廓很粗,然后第二次在轮廓上绘制主文本。但是,此任务变得更加容易,因为您可以轻松地调整SDK随附的代码示例之一,即SDK目录中此名称下的代码示例:“ / samples / android- / ApiDemos / src / com / example / android /apis/view/LabelView.java”。您也可以在此处找到Android开发者网站。

根据您正在执行的操作,很容易看到您只需要对该代码进行较小的修改,例如将其更改为从TextView扩展,等等。在发现此示例之前,我忘记了重写onMeasure()(除了覆盖Android开发者网站上的“构建自定义组件”指南中提到的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);
   }

因此,为了获得轮廓文本效果,您需要绘制两次文本:一次轮廓很粗,然后第二次在轮廓上绘制主文本。


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此答案提供了有关如何执行此操作的一般指导。如果希望提示和链接文本也有笔触,则还必须更改mHintTextColormLinkTextColor。不幸的是,更改mTextColor仅作为参考,因此无济于事。
VerumCH '18年

中将永远循环onDraw
user924

8

我编写了一个类来执行带有轮廓的文本,并且仍然支持普通文本视图的所有其他属性和图形。

它基本上super.onDraw(Canves canvas)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>

TypedArray上的a.recycle()丢失
Leos Literak

7

感谢@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" />

5

您可以使用以下代码段以编程方式执行此操作。这提供了带有黑色背景的白色字母:

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

该方法的参数是radius,dx,dy,color。您可以根据自己的特定需求进行更改。

我希望我能帮助以编程方式创建TextView并且不在xml中包含它的人。

为stackOverflow社区加油!



2

我想添加一个解决方案以解决性能问题。例如,@YGHM的答案和其他几个答案都可以完成工作,但是它会导致无限调用onDraw因为setTextColor呼叫invalidate()。因此,为了解决该问题,您还需要覆盖invalidate()并添加一个变量isDrawing,该变量将在设置过程中以及笔触绘制true时设置为onDraw()。如果变量为,则invalidate将返回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


它不支持多行文本
user924

0

所以您想在textview周围笔触吗?不幸的是,没有简单的方法可以完成样式设置。您必须创建另一个视图,并将textview放在顶部,使父视图(位于其顶部的视图)仅大几个像素-这将创建一个轮廓。


嗯,这听起来比痛苦更值得。我只关心在白色背景上可读绿色文本(现在有点难以阅读) img88.imageshack.us/i/devicez.png 红色看起来不错。也许如果我换成深绿色,但我真的希望我能得到某种轮廓或某些东西
Falmarri 2010年

您是否正在尝试概述文本本身?除非您执行自己的自定义TextView,否则仍然不可能实现,但这可能要花很多功夫。使其变成深绿色可能更容易。
xil3

2
来自红/绿双色盲的人的一个次要要求:请考虑添加相同的红/绿信息的替代表示形式,因为对于我们而言,通常很难看到深绿色还是深红色。也许还有向上/向下箭头?
史蒂夫·波默罗伊

这是史蒂夫的好观点。我将来可能会添加。
法尔玛里
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.