Android 开发之 SimpleTagImageView自定义ImageView
2015-08-17 14:59
671 查看
这两天看了ImageView相关的开源项目:https://github.com/wujingchao/SimpleTagImageView,对我来说比较有用,刚好要用到这个,在电商美食相关的app开发中经常遇到新品热销、火爆、消费状态的状态标示,这里一个imageview就解决了这个布局问题,都不用考虑适配问题。废话不多说了,下面看SimpleTagImageView效果图以及构造方法:
这里获取自定义属性值,并且初始化画笔以及rect等参数,自定义属性如下:
下面来看onDraw代码块
如果背景图片需要圆角,并且图片的宽高不等0,就先调用setupBitmapPaint()方法初始化mBitmapPaint画笔,并配置画笔缩放模式和shader,接着rect边界赋值,最后绘制到画布。
绘制圆角背景图后,根据Tag方向检测起始点,然后通过贝塞尔曲线Path绘制到画布,控件公开了自定义属性的set 、get方法,例如:
Eclipse开发者项目中引用只需要把自定义属性文件和自定义控件导入即可,自定义控件完整代码如下:
小逗逼我自定义控件不玩不溜,只有充当搬运工了,进阶路上摸索,求指导。
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; } }
小逗逼我自定义控件不玩不溜,只有充当搬运工了,进阶路上摸索,求指导。
相关文章推荐
- 安卓学习笔记(一)自定义控件2
- Android Service的生命周期
- Android中listview extends Linearlayout
- Android缓存-LruCache分析
- Android中实现短信验证码自动填入
- Android简介
- Android Hook神器:XPosed入门与登陆劫持演示
- 分享一种最简单的Android打渠道包的方法
- android开发 自定义图文混排控件
- Android 动画详解
- android sdk 离线安装
- 获取Android手机SD卡容量大小
- Android笔记:去除标题栏
- Android清除本地数据缓存代码
- AndroidStudio开发工具快捷键整理分享
- Android事件分发机制
- 对于startActivity的使用改进
- android强行隐藏自带的输入法
- Mac下Android Studio快捷键
- 关于Android中的四大组件(Service的开启与关闭)