取自https://github.com/m5/MagicTextView,感谢m5
设置一个attrs.xml
import java.util.ArrayList;
import java.util.WeakHashMap;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BlurMaskFilter;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Join;
import android.graphics.Paint.Style;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.Pair;
import android.widget.TextView;
import com.carcon.navi.uitools.ScreenMeasure;
import com.carcon.ui.R;
public class MagicTextView extends TextView {
private ArrayList outerShadows;
private ArrayList innerShadows;
private WeakHashMap> canvasStore;
private Canvas tempCanvas;
private Bitmap tempBitmap;
private Drawable foregroundDrawable;
private float strokeWidth;
private Integer strokeColor;
private Join strokeJoin;
private float strokeMiter;
private int[] lockedCompoundPadding;
private boolean frozen = false;
public MagicTextView(Context context) {
super(context);
init(null);
}
public MagicTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs);
}
public MagicTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(attrs);
}
public void init(AttributeSet attrs){
outerShadows = new ArrayList();
innerShadows = new ArrayList();
if(canvasStore == null){
canvasStore = new WeakHashMap>();
}
if(attrs != null){
TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.MagicTextView);
String typefaceName = a.getString( R.styleable.MagicTextView_typeface);
if(typefaceName != null) {
Typeface tf = Typeface.createFromAsset(getContext().getAssets(), String.format("fonts/%s.ttf", typefaceName));
setTypeface(tf);
}
if(a.hasValue(R.styleable.MagicTextView_foreground)){
Drawable foreground = a.getDrawable(R.styleable.MagicTextView_foreground);
if(foreground != null){
this.setForegroundDrawable(foreground);
}else{
this.setTextColor(a.getColor(R.styleable.MagicTextView_foreground, 0xff000000));
}
}
if(a.hasValue(R.styleable.MagicTextView_background)){
Drawable background = a.getDrawable(R.styleable.MagicTextView_background);
if(background != null){
this.setBackgroundDrawable(background);
}else{
this.setBackgroundColor(a.getColor(R.styleable.MagicTextView_background, 0xff000000));
}
}
if(a.hasValue(R.styleable.MagicTextView_innerShadowColor)){
this.addInnerShadow(a.getFloat(R.styleable.MagicTextView_innerShadowRadius, 0),
a.getFloat(R.styleable.MagicTextView_innerShadowDx, 0),
a.getFloat(R.styleable.MagicTextView_innerShadowDy, 0),
a.getColor(R.styleable.MagicTextView_innerShadowColor, 0xff000000));
}
if(a.hasValue(R.styleable.MagicTextView_outerShadowColor)){
this.addOuterShadow(a.getFloat(R.styleable.MagicTextView_outerShadowRadius, 0),
a.getFloat(R.styleable.MagicTextView_outerShadowDx, 0),
a.getFloat(R.styleable.MagicTextView_outerShadowDy, 0),
a.getColor(R.styleable.MagicTextView_outerShadowColor, 0xff000000));
}
if(a.hasValue(R.styleable.MagicTextView_strokeColor)){
float strokeWidth = a.getFloat(R.styleable.MagicTextView_strokeWidth, 1);
int strokeColor = a.getColor(R.styleable.MagicTextView_strokeColor, 0xff000000);
float strokeMiter = a.getFloat(R.styleable.MagicTextView_strokeMiter, 10);
Join strokeJoin = null;
switch(a.getInt(R.styleable.MagicTextView_strokeJoinStyle, 0)){
case(0): strokeJoin = Join.MITER; break;
case(1): strokeJoin = Join.BEVEL; break;
case(2): strokeJoin = Join.ROUND; break;
}
this.setStroke(strokeWidth, strokeColor, strokeJoin, strokeMiter);
}
}
}
public void setStroke(float width, int color, Join join, float miter){
strokeWidth = width;
strokeColor = color;
strokeJoin = join;
strokeMiter = miter;
}
public void setStroke(float width, int color){
setStroke(width, color, Join.MITER, 10);
}
public void addOuterShadow(float r, float dx, float dy, int color){
if(r == 0){ r = 0.0001f; }
outerShadows.add(new Shadow(r,dx,dy,color));
}
public void addInnerShadow(float r, float dx, float dy, int color){
if(r == 0){ r = 0.0001f; }
innerShadows.add(new Shadow(r,dx,dy,color));
}
public void clearInnerShadows(){
innerShadows.clear();
}
public void clearOuterShadows(){
outerShadows.clear();
}
public void setForegroundDrawable(Drawable d){
this.foregroundDrawable = d;
}
public Drawable getForeground(){
return this.foregroundDrawable == null ? this.foregroundDrawable : new ColorDrawable(this.getCurrentTextColor());
}
@Override
public void onDraw(Canvas canvas){
super.onDraw(canvas);
freeze();
Drawable restoreBackground = this.getBackground();
Drawable[] restoreDrawables = this.getCompoundDrawables();
int restoreColor = this.getCurrentTextColor();
this.setCompoundDrawables(null, null, null, null);
for(Shadow shadow : outerShadows){
this.setShadowLayer(shadow.r, shadow.dx, shadow.dy, shadow.color);
super.onDraw(canvas);
}
this.setShadowLayer(0,0,0,0);
this.setTextColor(restoreColor);
if(this.foregroundDrawable != null && this.foregroundDrawable instanceof BitmapDrawable){
generateTempCanvas();
super.onDraw(tempCanvas);
Paint paint = ((BitmapDrawable) this.foregroundDrawable).getPaint();
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP));
this.foregroundDrawable.setBounds(canvas.getClipBounds());
this.foregroundDrawable.draw(tempCanvas);
canvas.drawBitmap(tempBitmap, 0, 0, null);
tempCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
}
if(strokeColor != null){
TextPaint paint = this.getPaint();
// paint.setTextAlign(Paint.Align.CENTER);
paint.setStyle(Style.STROKE);
paint.setStrokeJoin(strokeJoin);
paint.setStrokeMiter(strokeMiter);
this.setTextColor(strokeColor);
paint.setStrokeWidth(strokeWidth);
super.onDraw(canvas);
paint.setStyle(Style.FILL);
this.setTextColor(restoreColor);
}
if(innerShadows.size() > 0){
generateTempCanvas();
TextPaint paint = this.getPaint();
for(Shadow shadow : innerShadows){
this.setTextColor(shadow.color);
super.onDraw(tempCanvas);
this.setTextColor(0xFF000000);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
paint.setMaskFilter(new BlurMaskFilter(shadow.r, BlurMaskFilter.Blur.NORMAL));
tempCanvas.save();
tempCanvas.translate(shadow.dx, shadow.dy);
super.onDraw(tempCanvas);
tempCanvas.restore();
canvas.drawBitmap(tempBitmap, 0, 0, null);
tempCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
paint.setXfermode(null);
paint.setMaskFilter(null);
this.setTextColor(restoreColor);
this.setShadowLayer(0,0,0,0);
}
}
if(restoreDrawables != null){
this.setCompoundDrawablesWithIntrinsicBounds(restoreDrawables[0], restoreDrawables[1], restoreDrawables[2], restoreDrawables[3]);
}
this.setBackgroundDrawable(restoreBackground);
this.setTextColor(restoreColor);
unfreeze();
}
private void generateTempCanvas(){
String key = String.format("%dx%d", getWidth(), getHeight());
Pair
这类中的描边是内描边,如果要外描边的话
在onDraw里面画完描边字体以后加上
paint.setStrokeWidth(0);
super.onDraw(canvas);
调用方发如下:
xml:
view = new MagicTextView(context);
view.addInnerShadow(0, -1, 0, 0xFFffffff);
view.addOuterShadow(0, -1, 0, 0xff000000);
view.setStroke(4, 0xFFff0000);
view.setForegroundDrawable(getResources().getDrawable(R.drawable.fake_luxury_tiled);