`
810364804
  • 浏览: 788235 次
文章分类
社区版块
存档分类
最新评论

外发光、内发光、描边、阴影的TextView

 
阅读更多

取自https://github.com/m5/MagicTextView,感谢m5

设置一个attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
	<declare-styleable name="MagicTextView">
		<attr name="innerShadowColor" format="color"/>
		<attr name="innerShadowRadius" format="float"/>
		<attr name="innerShadowDx" format="float"/>
		<attr name="innerShadowDy" format="float"/>
		
		<attr name="outerShadowColor" format="color"/>
		<attr name="outerShadowRadius" format="float"/>
		<attr name="outerShadowDx" format="float"/>
		<attr name="outerShadowDy" format="float"/>
		
		<attr name="typeface" format="string" />
		
		<attr name="foreground" format="reference|color"/>
		<attr name="background" format="reference|color"/>
		
		<attr name="strokeWidth" format="float" />
		<attr name="strokeMiter" format="float" />
		<attr name="strokeColor" format="color" />
		<attr name="strokeJoinStyle">
		    <enum name="miter" value="0" />
		    <enum name="bevel" value="1" />
		    <enum name="round" value="2" />
		</attr>
	</declare-styleable>
</resources>

然后自定义我们的TextView类:

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<Shadow> outerShadows;
	private ArrayList<Shadow> innerShadows;
	
	private WeakHashMap<String, Pair<Canvas, Bitmap>> 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<Shadow>();
		innerShadows = new ArrayList<Shadow>();
		if(canvasStore == null){
		    canvasStore = new WeakHashMap<String, Pair<Canvas, Bitmap>>();
		}
	
		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<Canvas, Bitmap> stored = canvasStore.get(key);
	    if(stored != null){
	        tempCanvas = stored.first;
	        tempBitmap = stored.second;
	    }else{
            tempCanvas = new Canvas();
            tempBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
            tempCanvas.setBitmap(tempBitmap);
            canvasStore.put(key, new Pair<Canvas, Bitmap>(tempCanvas, tempBitmap));
	    }
	}

	
	// Keep these things locked while onDraw in processing
	public void freeze(){
		lockedCompoundPadding = new int[]{
				getCompoundPaddingLeft(),
				getCompoundPaddingRight(),
				getCompoundPaddingTop(),
				getCompoundPaddingBottom()
		};
		frozen = true;
	}
	
	public void unfreeze(){
		frozen = false;
	}
	
    
    @Override
    public void requestLayout(){
        if(!frozen) super.requestLayout();
    }
	
	@Override
	public void postInvalidate(){
		if(!frozen) super.postInvalidate();
	}
	
   @Override
    public void postInvalidate(int left, int top, int right, int bottom){
        if(!frozen) super.postInvalidate(left, top, right, bottom);
    }
	
	@Override
	public void invalidate(){
		if(!frozen)	super.invalidate();
	}
	
	@Override
	public void invalidate(Rect rect){
		if(!frozen) super.invalidate(rect);
	}
	
	@Override
	public void invalidate(int l, int t, int r, int b){
		if(!frozen) super.invalidate(l,t,r,b);
	}
	
	@Override
	public int getCompoundPaddingLeft(){
		return !frozen ? super.getCompoundPaddingLeft() : lockedCompoundPadding[0];
	}
	
	@Override
	public int getCompoundPaddingRight(){
		return !frozen ? super.getCompoundPaddingRight() : lockedCompoundPadding[1];
	}
	
	@Override
	public int getCompoundPaddingTop(){
		return !frozen ? super.getCompoundPaddingTop() : lockedCompoundPadding[2];
	}
	
	@Override
	public int getCompoundPaddingBottom(){
		return !frozen ? super.getCompoundPaddingBottom() : lockedCompoundPadding[3];
	}
	
	public static class Shadow{
		float r;
		float dx;
		float dy;
		int color;
		public Shadow(float r, float dx, float dy, int color){
			this.r = r;
			this.dx = dx;
			this.dy = dy;
			this.color = color;
		}
	}
}
这类中的描边是内描边,如果要外描边的话

在onDraw里面画完描边字体以后加上

paint.setStrokeWidth(0);
super.onDraw(canvas);

就ok了


调用方发如下:

xml:

<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"
    android:drawableLeft="@android:drawable/btn_star"
    android:textStyle="bold"
    android:padding="10dp"
    qwerjk:foreground="@drawable/fake_luxury_tiled"
    qwerjk:innerShadowDy="2"
    qwerjk:innerShadowColor="#FF000000"
    qwerjk:innerShadowRadius="1"
    qwerjk:outerShadowDy="3"
    qwerjk:outerShadowColor="#FF0088ff"
    qwerjk:outerShadowRadius="10"
    qwerjk:strokeColor="#FFff0000"
    qwerjk:strokeJoinStyle="miter"
    qwerjk:strokeWidth="5"
    android:text="Sample" />

java:

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


分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics