Android的textview大纲文本

有一个简单的方法可以让文字有一个黑色的轮廓? 我有textviews将是不同的颜色,但一些颜色不显示在我的背景如此之好,所以我想知道是否有一个简单的方法来得到一个黑色的轮廓或其他什么可以做的工作? 我宁愿不必创build一个自定义视图,并创build一个canvas等。

你可以在文字背后加上阴影,这往往有助于可读性。 尝试在绿色文字上使用50%半透明的黑色阴影。 如何做到这一点的详细信息在这里: Android – 阴影文本?

为了在文本中添加笔触,需要做一些更多的工作,比如: 如何在Android中的MapView中使用边框绘制文本?

所以,迟到一点,但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" /> 

注意:我做了这个,并且为了未来的旅行者而张贴更多的内容。 这是边缘的垃圾邮件,但在话题上,也许可以接受?

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

我刚刚试图找出如何做到这一点,无法find一个很好的指导,但最终弄清楚了。 正如Steve Pomeroy所说,你必须做更多的事情。 为了得到轮廓的文字效果,您可以绘制文字两次:一次是粗轮廓,然后是第二次在轮廓上绘制主文本。 但是,这个任务变得更容易了,因为你可以很容易地适应SDK提供的一个代码示例,也就是你的SDK目录下的这个名称:“/ samples / android- / ApiDemos / src / com / example / android /apis/view/LabelView.java”。 这里也可以在Android开发者网站上find 。

取决于你在做什么,很容易看到你只需要对代码做一些小的修改,比如把它改成从TextView扩展等。在我发现这个例子之前,我忘记了重写onMeasure()(它除了在Android开发者网站的“构build自定义组件”指南中提到的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); } 

所以,为了获得轮廓的文字效果,您需要绘制文字两次:一次是粗轮廓,然后是第二次在轮廓上绘制主文本。

该框架支持文字阴影,但不支持文字轮廓。 但是有一个诀窍:影子是半透明的,会消失的。 重绘一个阴影几次,所有的阿尔法将得到总结,结果是一个轮廓。

一个非常简单的实现扩展了TextView并重写了绘制方法。 每次请求平局,我们的子类会做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" /> 

这是一个相当古老的问题,但我还没有看到任何完整的答案。 所以我发布了这个解决scheme,希望有人能够解决这个问题,可能会发现它有用。 最简单和最有效的解决scheme是重写TextView类的onDraw方法。 我所看到的大多数实现都使用drawText方法来绘制笔画,但是这种方法没有考虑到所有的格式化alignment和文字换行。结果往往笔画和文本会在不同的地方出现。 下面的方法使用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" /> 

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

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

我已经写了一个类来执行带有大纲的文本,并且仍然支持正常文本视图的所有其他属性和绘图。

它基本上使用TextViewsuper.onDraw(Canves canvas) ,但绘制两次不同的风格。

希望这可以帮助。

 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> 

我发现这个技巧比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周围中风? 不幸的是,没有简单的方法来做这个造型。 您必须创build另一个视图,并将您的textview置于顶部,使父视图(它位于顶部的视图)稍微大一些像素 – 这应该创build一个大纲。

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

我已经创build了一个基于Nouman Hanif的答案,并增加了一些库。 例如,修复导致View.invalidate()调用间接无限循环的错误。

OTOH,图书馆还支持EditText小部件中的概要文本,因为这是我真正的目标,它需要比TextView多一点的工作。

这里是我的图书馆的链接: https : //github.com/biomorgoth/android-outline-textview

感谢Nouman Hanif提供解决scheme的最初想法!