您的位置:首页 > 移动开发 > Android开发

Android 开发之 SimpleTagImageView自定义ImageView

2015-08-17 14:59 671 查看
这两天看了ImageView相关的开源项目:https://github.com/wujingchao/SimpleTagImageView,对我来说比较有用,刚好要用到这个,在电商美食相关的app开发中经常遇到新品热销、火爆、消费状态的状态标示,这里一个imageview就解决了这个布局问题,都不用考虑适配问题。废话不多说了,下面看SimpleTagImageView效果图以及构造方法:





public class SimpleTagImageView extends ImageView {
public SimpleTagImageView(Context context) {
this(context, null);
}

public SimpleTagImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}

public SimpleTagImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mDensity = context.getResources().getDisplayMetrics().density;
TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.SimpleTagImageView,defStyleAttr,0);
mTagOrientation = a.getInteger(R.styleable.SimpleTagImageView_simple_tag_orientation,0);
mTagWidth = a.getDimensionPixelSize(R.styleable.SimpleTagImageView_simple_tag_width, dip2px(DEFAULT_TAG_WIDTH));
mCornerDistance = a.getDimensionPixelSize(R.styleable.SimpleTagImageView_simple_corner_distance,dip2px(DEFAULT_CORNER_DISTANCE));
mTagBackgroundColor = a.getColor(R.styleable.SimpleTagImageView_simple_tag_background_color,DEFAULT_TAG_BACKGROUND_COLOR);
mTagText = a.getString(R.styleable.SimpleTagImageView_simple_tag_text);
mTagTextSize = a.getDimensionPixelSize(R.styleable.SimpleTagImageView_simple_tag_textSize, dip2px(DEFAULT_TAG_TEXT_SIZE));
mTagTextColor = a.getColor(R.styleable.SimpleTagImageView_simple_tag_textColor, DEFAULT_TAG_TEXT_COLOR);
mTagEnable = a.getBoolean(R.styleable.SimpleTagImageView_simple_tag_enable,true);
mRoundRadius = a.getDimensionPixelSize(R.styleable.SimpleTagImageView_simple_tag_round_radius,0);
a.recycle();
if(TextUtils.isEmpty(mTagText))mTagText = "";
mPaint = new Paint();
mPath = new Path();
mTextPaint = new Paint();
mTagTextBound = new Rect();
startPoint = new MyPoint();
endPoint = new MyPoint();
mRoundRect = new RectF();
}
}


这里获取自定义属性值,并且初始化画笔以及rect等参数,自定义属性如下:

<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="SimpleTagImageView">
<attr name="simple_corner_distance" format="dimension" />
<attr name="simple_tag_width" format="dimension"/>
<attr name="simple_tag_background_color" format="color"/>
<attr name="simple_tag_text" format="string"/>
<attr name="simple_tag_textSize" format="dimension" />
<attr name="simple_tag_textColor" format="color"/>
<attr name="simple_tag_orientation" format="enum">
<enum name="left_top" value="0"/>
<enum name="right_top" value="1"/>
<enum name="left_bottom" value="2"/>
<enum name="right_bottom" value="3"/>
</attr>
<attr name="simple_tag_enable" format="boolean"/>
<attr name="simple_tag_round_radius" format="dimension"/>
</declare-styleable>
</resources>


下面来看onDraw代码块

@Override
protected void onDraw(Canvas mCanvas) {
if(mRoundRadius == 0) {
super.onDraw(mCanvas);
}else {
Drawable d = getDrawable();
if(d == null) return;
if(d.getIntrinsicWidth() == 0 || d.getIntrinsicHeight() == 0) return;
setupBitmapPaint();
mRoundRect.set(getPaddingLeft(),getPaddingTop(),getMeasuredWidth() - getPaddingRight(),getMeasuredHeight() - getPaddingBottom());
mCanvas.drawRoundRect(mRoundRect, mRoundRadius, mRoundRadius, mBitmapPaint);
}
................
}


如果背景图片需要圆角,并且图片的宽高不等0,就先调用setupBitmapPaint()方法初始化mBitmapPaint画笔,并配置画笔缩放模式和shader,接着rect边界赋值,最后绘制到画布。

@Override
protected void onDraw(Canvas mCanvas) {
...................................
if(mTagWidth > 0 && mTagEnable) {
float rDistance = mCornerDistance + mTagWidth/2;
chooseTagOrientation(rDistance);
mTextPaint.setTextSize(mTagTextSize);
mTextPaint.getTextBounds(mTagText,0,mTagText.length(),mTagTextBound);
mPaint.setDither(true);
mPaint.setAntiAlias(true);
mPaint.setColor(mTagBackgroundColor);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.SQUARE);
mPaint.setStrokeWidth(mTagWidth);
mPath.reset();
mPath.moveTo(startPoint.x, startPoint.y);
mPath.lineTo(endPoint.x, endPoint.y);
mCanvas.drawPath(mPath, mPaint);
mTextPaint.setColor(mTagTextColor);
mTextPaint.setTextSize(mTagTextSize);
mTextPaint.setAntiAlias(true);
//          斜边长度
float hypotenuse = THE_SQUARE_ROOT_OF_2 * rDistance;
mCanvas.drawTextOnPath(mTagText, mPath, hypotenuse / 2 - mTagTextBound.width() / 2,
mTagTextBound.height() / 2, mTextPaint);
}
}


绘制圆角背景图后,根据Tag方向检测起始点,然后通过贝塞尔曲线Path绘制到画布,控件公开了自定义属性的set 、get方法,例如:

/**
*
* @param tagOrientation {@link #LEFT_TOP} or
*                       {@link #LEFT_BOTTOM} or
*                       {@link #RIGHT_TOP} or
*                       {@link #RIGHT_BOTTOM}
*/
public void setTagOrientation(int tagOrientation) {
if(tagOrientation == this.mTagOrientation)return;
this.mTagOrientation = tagOrientation;
invalidate();
}


Eclipse开发者项目中引用只需要把自定义属性文件和自定义控件导入即可,自定义控件完整代码如下:

/**
* @author wujingchao  2015-02-20 email:wujingchao@aliyun.com
*/
public class SimpleTagImageView extends ImageView {

public static final String TAG = "SimpleTagImageView";

public  static final byte LEFT_TOP = 0x00;

public  static final byte RIGHT_TOP = 0x01;

public  static final byte LEFT_BOTTOM = 0x02;

public  static final byte RIGHT_BOTTOM = 0x03;

private static final float THE_SQUARE_ROOT_OF_2 = (float) Math.sqrt(2);

private static final int DEFAULT_TAG_WIDTH = 20;

private static final int DEFAULT_CORNER_DISTANCE = 20;

private static final int DEFAULT_TAG_BACKGROUND_COLOR = 0x9F27CDC0;

private static final int DEFAULT_TAG_TEXT_SIZE = 15;

private static final int DEFAULT_TAG_TEXT_COLOR = 0xFFFFFFFF;

private float mCornerDistance;

private float mTagWidth;

private int mTagBackgroundColor;

private Path mPath;

private Paint mPaint;

private String mTagText;

private int mTagTextSize;

private Paint mTextPaint;

private Rect mTagTextBound;

private int mTagTextColor;

private float mDensity;

private int mTagOrientation;

private MyPoint startPoint;

private MyPoint endPoint;

private Paint mBitmapPaint;

private RectF mRoundRect;

private boolean mTagEnable;

private int mRoundRadius;

public SimpleTagImageView(Context context) {
this(context, null);
}

public SimpleTagImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}

public SimpleTagImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mDensity = context.getResources().getDisplayMetrics().density;
TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.SimpleTagImageView,defStyleAttr,0);
mTagOrientation = a.getInteger(R.styleable.SimpleTagImageView_simple_tag_orientation,0);
mTagWidth = a.getDimensionPixelSize(R.styleable.SimpleTagImageView_simple_tag_width, dip2px(DEFAULT_TAG_WIDTH));
mCornerDistance = a.getDimensionPixelSize(R.styleable.SimpleTagImageView_simple_corner_distance,dip2px(DEFAULT_CORNER_DISTANCE));
mTagBackgroundColor = a.getColor(R.styleable.SimpleTagImageView_simple_tag_background_color,DEFAULT_TAG_BACKGROUND_COLOR);
mTagText = a.getString(R.styleable.SimpleTagImageView_simple_tag_text);
mTagTextSize = a.getDimensionPixelSize(R.styleable.SimpleTagImageView_simple_tag_textSize, dip2px(DEFAULT_TAG_TEXT_SIZE));
mTagTextColor = a.getColor(R.styleable.SimpleTagImageView_simple_tag_textColor, DEFAULT_TAG_TEXT_COLOR);
mTagEnable = a.getBoolean(R.styleable.SimpleTagImageView_simple_tag_enable,true);
mRoundRadius = a.getDimensionPixelSize(R.styleable.SimpleTagImageView_simple_tag_round_radius,0);
a.recycle();
if(TextUtils.isEmpty(mTagText))mTagText = "";
mPaint = new Paint();
mPath = new Path();
mTextPaint = new Paint();
mTagTextBound = new Rect();
startPoint = new MyPoint();
endPoint = new MyPoint();
mRoundRect = new RectF();
}

/**
*
* @param textSize unit:dip
*/
public void setTagTextSize(int textSize) {
this.mTagTextSize = dip2px(textSize);
invalidate();
}

public int getTagTextSize(){
return mTagTextSize;
}

/**
*
* @param cornerDistance unit:dip
*/
public void setCornerDistance(int cornerDistance) {
if(this.mCornerDistance == cornerDistance)return;
this.mCornerDistance = dip2px(cornerDistance);
invalidate();
}

/**
*
* @return unit:dip
*/
public int getCornerDistance() {
return px2dip(this.mCornerDistance);
}

public int getTagTextColor() {
return this.mTagTextColor;
}

public void setTagTextColor(int tagTextColor) {
if(this.mTagTextColor == tagTextColor)return;
this.mTagTextColor = tagTextColor;
invalidate();
}

public String getTagText() {
return this.mTagText;
}

public void setTagText(String tagText){
if(tagText.equals(this.mTagText))return;
this.mTagText = tagText;
invalidate();
}

public void setTagBackgroundColor(int tagBackgroundColor) {
if(this.mTagBackgroundColor == tagBackgroundColor)return;
this.mTagBackgroundColor = tagBackgroundColor;
invalidate();
}

public int getTagBackgroundColor() {
return this.mTagBackgroundColor;
}

/**
* @return unit:dip
*/
public int getTagWidth() {
return px2dip(this.mTagWidth);
}

/**
*
* @param tagWidth unit:dip
*/
public void setTagWidth(int tagWidth) {
this.mTagWidth = dip2px(tagWidth);
invalidate();
}

/**
* @return  0 : left_top
*          1 : right_top
*          2 : left_bottom
*          3 : right_bottom
*/
public int getTagOrientation() {
return mTagOrientation;
}

/**
*
* @param tagOrientation {@link #LEFT_TOP} or
*                       {@link #LEFT_BOTTOM} or
*                       {@link #RIGHT_TOP} or
*                       {@link #RIGHT_BOTTOM}
*/
public void setTagOrientation(int tagOrientation) {
if(tagOrientation == this.mTagOrientation)return;
this.mTagOrientation = tagOrientation;
invalidate();
}

public void setTagEnable(boolean tagEnable) {
if(this.mTagEnable == tagEnable) return ;
this.mTagEnable = tagEnable;
invalidate();
}

public boolean getTagEnable() {
return this.mTagEnable;
}

public  int getTagRoundRadius() {
return this.mRoundRadius;
}

public void setTagRoundRadius(int roundRadius) {
if(this.mRoundRadius == roundRadius) return;
this.mRoundRadius = roundRadius;
invalidate();
}

@Override
protected void onDraw(Canvas mCanvas) {
if(mRoundRadius == 0) {
super.onDraw(mCanvas);
}else {
Drawable d = getDrawable();
if(d == null) return;
if(d.getIntrinsicWidth() == 0 || d.getIntrinsicHeight() == 0) return;
setupBitmapPaint();
mRoundRect.set(getPaddingLeft(),getPaddingTop(),getMeasuredWidth() - getPaddingRight(),getMeasuredHeight() - getPaddingBottom());
mCanvas.drawRoundRect(mRoundRect, mRoundRadius, mRoundRadius, mBitmapPaint);
}

if(mTagWidth > 0 && mTagEnable) {
float rDistance = mCornerDistance + mTagWidth/2;
chooseTagOrientation(rDistance);
mTextPaint.setTextSize(mTagTextSize);
mTextPaint.getTextBounds(mTagText,0,mTagText.length(),mTagTextBound);
mPaint.setDither(true);
mPaint.setAntiAlias(true);
mPaint.setColor(mTagBackgroundColor);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.SQUARE);
mPaint.setStrokeWidth(mTagWidth);
mPath.reset();
mPath.moveTo(startPoint.x, startPoint.y);
mPath.lineTo(endPoint.x, endPoint.y);
mCanvas.drawPath(mPath, mPaint);
mTextPaint.setColor(mTagTextColor);
mTextPaint.setTextSize(mTagTextSize);
mTextPaint.setAntiAlias(true);
//          斜边长度
float hypotenuse = THE_SQUARE_ROOT_OF_2 * rDistance;
mCanvas.drawTextOnPath(mTagText, mPath, hypotenuse / 2 - mTagTextBound.width() / 2,
mTagTextBound.height() / 2, mTextPaint);
}
}

private void chooseTagOrientation(float rDistance) {
int mWidth = getMeasuredWidth();
int mHeight = getMeasuredHeight();
switch (mTagOrientation) {
case 0:
startPoint.x = 0;
startPoint.y = rDistance;
endPoint.x = rDistance;
endPoint.y = 0;
break;
case 1:
startPoint.x = mWidth - rDistance;
startPoint.y = 0;
endPoint.x = mWidth;
endPoint.y = rDistance;
break;
case 2:
startPoint.x = 0;
startPoint.y = mHeight - rDistance;
endPoint.x = rDistance;
endPoint.y = mHeight;
break;
case 3:
startPoint.x = mWidth - rDistance;
startPoint.y = mHeight;
endPoint.x = mWidth;
endPoint.y = mHeight - rDistance;
break;
}
}

private void setupBitmapPaint() {
Drawable drawable = getDrawable();
if (drawable == null) {
return;
}
Bitmap mBitmap = drawableToBitmap(drawable);
BitmapShader mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
if(getScaleType() != ScaleType.FIT_XY){
Log.w(TAG,String.format("Now scale type just support fitXY,other type invalid"));
}
//now scale type just support fitXY
//todo support all scale type
Matrix mMatrix = new Matrix();
mMatrix.setScale(getWidth() * 1.0f / mBitmap.getWidth(), getHeight() * 1.0f / mBitmap.getHeight());
mBitmapShader.setLocalMatrix(mMatrix);
if(mBitmapPaint == null) {
mBitmapPaint = new Paint();
mBitmapPaint.setDither(false);
mBitmapPaint.setAntiAlias(true);
mBitmapPaint.setShader(mBitmapShader);
}
}

private int dip2px(int dip) {
return (int)(mDensity * dip + 0.5f);
}

private int px2dip(float px) {
return (int)(px/mDensity + 0.5f);
}

private Bitmap drawableToBitmap(Drawable drawable) {
if (drawable instanceof BitmapDrawable) {
BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
return bitmapDrawable.getBitmap();
}
int w = drawable.getIntrinsicWidth();
int h = drawable.getIntrinsicHeight();
Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, w, h);
drawable.draw(canvas);
return bitmap;
}

static class MyPoint {
float x;
float y;
}
}


小逗逼我自定义控件不玩不溜,只有充当搬运工了,进阶路上摸索,求指导。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: