自定义View之CircleImageView
本文根据github上的这个类进行代码解析,点进去。
自定义View相关知识
Bitmap.Config
- ALPHA_8 每个像素使用一个半透明单通道存储,需要一个byte内存
- RGB_565 每个像素保存在2个字节上,并且规定red用5bit精度保存,green用6bit精度保存,blue用5bit保存
- ARGB_8888 每个像素保存在4个字节上,并且每个通道使用8bit精度保存
RectF
- RectF保存一个矩形的4个float型坐标。
- 通过矩阵的四个角(left,top,right,bottom)来描述这个矩形。
- 使用width()和height()来得到矩阵宽高
- 大多数方法不检查:left <= right and top <= bottom
BitmapShader(图像渲染)
- 作用是使用一张位图作为纹理来对某一区域进行填充。
- 参数tileX表示在位图X方向上位图衔接形式;
- 参数tileY表示在位图Y方向上位图衔接形式。
- Shader.TileMode有3种参数可供选择,分别为CLAMP、REPEAT和MIRROR。
- CLAMP的作用是如果渲染器超出原始边界范围,则会复制边缘颜色对超出范围的区域进行着色。
- REPEAT的作用是在横向和纵向上以平铺的形式重复渲染位图。
- MIRROR的作用是在横向和纵向上以镜像的方式重复渲染位图。
CircleView的实现
设置自定义属性:
在文件xxx\src\main\res\values\attrs.xml中加上:
<declare-styleable name="CircleImageView">
<attr name="civ_border_width" format="dimension"/>
<attr name="civ_border_color" format="color"/>
<attr name="civ_border_overlay" format="boolean"/>
<attr name="civ_fill_color" format="color"/>
</declare-styleable>
获取自定义属性值:
在CircleView的构造函数中获取到自定义属性的值。
public CircleImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleImageView, defStyleAttr, 0);
mBorderWidth = a.getDimensionPixelOffset(R.styleable.CircleImageView_civ_border_width, 0);
mBorderColor = a.getColor(R.styleable.CircleImageView_civ_border_color, DEFAULT_BORDER_COLOR);
mBorderOverlay = a.getBoolean(R.styleable.CircleImageView_civ_border_overlay, DEFAULT_BORDER_OVERLAY);
mFillColor = a.getColor(R.styleable.CircleImageView_civ_fill_color, DEFAULT_FILL_COLOR);
a.recycle();
init();
}
在onDraw中将圆和环画出来:
@Override
protected void onDraw(Canvas canvas) {
if (mDisableCircularTransformation) {
super.onDraw(canvas);
return;
}
if (mBitmap == null) {
return;
}
if (mFillColor != Color.TRANSPARENT) {
canvas.drawCircle(mDrawableRect.centerX(), mDrawableRect.centerY(), mDrawableRadius, mFillPaint);
}
//画圆
canvas.drawCircle(mDrawableRect.centerX(), mDrawableRect.centerY(), mDrawableRadius, mBitmapPaint);
//画环
if (mBorderWidth > 0) {
canvas.drawCircle(mBorderRect.centerX(), mBorderRect.centerY(), mBorderRadius, mBorderPaint);
}
}
设置画笔:
mBitmapPaint.setAntiAlias(true);
mBitmapPaint.setShader(mBitmapShader);
mBorderPaint.setStyle(Paint.Style.STROKE);
mBorderPaint.setAntiAlias(true);
mBorderPaint.setColor(mBorderColor);
mBorderPaint.setStrokeWidth(mBorderWidth);
mFillPaint.setStyle(Paint.Style.FILL);
mFillPaint.setAntiAlias(true);
mFillPaint.setColor(mFillColor);
mBitmapHeight = mBitmap.getHeight();
mBitmapWidth = mBitmap.getWidth();
mBorderRect.set(calculateBounds());
mBorderRadius = Math.min((mBorderRect.height() - mBorderWidth) / 2.0f, (mBorderRect.width() - mBorderWidth) / 2.0f);
mDrawableRect.set(mBorderRect);
if (!mBorderOverlay && mBorderWidth > 0) {
mDrawableRect.inset(mBorderWidth - 1.0f, mDrawableRect.width() / 2.0f);
}
mDrawableRadius = Math.min(mDrawableRect.height() / 2.0f, mDrawableRect.width() / 2.0f);
计算放置环的矩阵
private RectF calculateBounds() {
int availableWidth = getWidth() - getPaddingLeft() - getPaddingRight();
int availableHeight = getHeight() - getPaddingTop() - getPaddingBottom();
int sideLength = Math.min(availableHeight, availableWidth);
float left = getPaddingLeft() + (availableWidth - sideLength) / 2f;
float top = getPaddingTop() + (availableHeight - sideLength) / 2f;
return new RectF(left, top, left + sideLength, top + sideLength);
}
更新渲染图片
private void updateShaderMatrix() {
float scale;
float dx = 0;
float dy = 0;
mShaderMatrix.set(null);
if (mBitmapWidth * mDrawableRect.height() > mDrawableRect.width() * mBitmapHeight) {
scale = mDrawableRect.height() / (float) mBitmapHeight;
dx = (mDrawableRect.width() - mBitmapWidth * scale) * 0.5f;
} else {
scale = mDrawableRect.width() / (float) mBitmapWidth;
dy = (mDrawableRect.height() - mBitmapHeight * scale) * 0.5f;
}
//设置缩放
mShaderMatrix.setScale(scale, scale);
//平移
mShaderMatrix.postTranslate((int) (dx + 0.5f) + mDrawableRect.left, (int) (dy + 0.5f) + mDrawableRect.top);
mBitmapShader.setLocalMatrix(mShaderMatrix);
}
将drawable转化为Bitmap
private Bitmap getBitmapFromDrawable(Drawable drawable) {
if (drawable == null) {
return null;
}
if (drawable instanceof BitmapDrawable) {
return ((BitmapDrawable) drawable).getBitmap();
}
try {
Bitmap bitmap;
if (drawable instanceof ColorDrawable) {
bitmap = Bitmap.createBitmap(COLORDRAWABLE_DIMENSION, COLORDRAWABLE_DIMENSION, BITMAP_CONFIG);
} else {
bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), BITMAP_CONFIG);
}
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return bitmap;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
结果,只是一些代码片段,尴尬