一 前言
毕业了,纷纷杂杂的事情。
参考资料:
Android BitmapShader 实战 实现圆形、圆角图片
好的,第一个问题就是BitmapShader是什么。
二 BitmapShader是什么
Shader used to draw a bitmap as a texture. The bitmap can be repeated or mirrored by setting the tiling mode.
Shader用于将位图绘制为纹理。通过设置平铺模式可以重复或镜像位图。
没懂,纹理又是什么?
Android BitmapShader 实战 实现圆形、圆角图片第三节浅谈BitmapShader中了解到,其实就是用bitmap来绘制。根据指定的TileMode,对指定区域用bitmap进行着色。
而它继承的Shader
,就是一个着色器。
具体关于BitmapShader的效果,看自定义控件其实很简单1/3
三 实现思路
从mPaint.setShader(new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.MIRROR));
这句语句以及它的实现效果,我们可以看到,它就是一个根据传入的Bitmap
,和设置的TileMode
模式进行上色的作用
那么假如,把画笔设置成这样,并且让它画圆形,不就实现了想要的效果吗?
四 实践
public class CircleImageView extends android.support.v7.widget.AppCompatImageView {
private Paint bitmapPaint;
private BitmapShader bitmapShader;
/**
* 3x3 矩阵,主要用于缩小放大
*/
private Matrix mMatrix;
//View的宽高
private int mWidth;
//半径
private int mRadius;
public CircleImageView(Context context, AttributeSet attrs) {
super(context, attrs);
bitmapPaint = new Paint();
bitmapPaint.setAntiAlias(true);
mMatrix = new Matrix();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//强制改变view的宽高一致,以小值为准
mWidth = Math.min(getMeasuredWidth(), getMeasuredHeight());
mRadius = mWidth / 2;
setMeasuredDimension(mWidth, mWidth);
}
/**
* 初始化BitmapShader
*/
private void setUpShader()
{
Drawable drawable = getDrawable();
if (drawable == null)
{
return;
}
Bitmap bmp = drawableToBitmap(drawable);
// 将bmp作为着色器,就是在指定区域内绘制bmp
bitmapShader = new BitmapShader(bmp, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
float scale = 1.0f;
// 拿到bitmap宽或高的小值
int bSize = Math.min(bmp.getWidth(), bmp.getHeight());
scale = mWidth * 1.0f / bSize;
// shader的变换矩阵,我们这里主要用于放大或者缩小
mMatrix.setScale(scale, scale);
// 设置变换矩阵
bitmapShader.setLocalMatrix(mMatrix);
// 设置shader
bitmapPaint.setShader(bitmapShader);
}
private Bitmap drawableToBitmap(Drawable drawable) {
if (drawable instanceof BitmapDrawable)
{
BitmapDrawable bd = (BitmapDrawable) drawable;
return bd.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;
}
@Override
protected void onDraw(Canvas canvas) {
if (getDrawable() == null) {
return;
}
setUpShader();
canvas.drawCircle(mRadius, mRadius, mRadius, bitmapPaint);
}
}
五 反馈-api学习
说实话,有了清晰的思路之后,问题在于api不熟悉。不知道有什么方法可以做到什么效果。
这里总结一下上面用到的:
- setUpShader方法中
bitmapShader.setLocalMatrix(mMatrix);
设置变化矩阵,能让你对横轴纵轴做缩放。通过mMatrix.setScale(scale, scale);
方法。 - onMeasure方法中
mWidth = Math.min(getMeasuredWidth(), getMeasuredHeight());
与
setMeasuredDimension
方法。他们的含义是什么?文章1 measure
文章二:setMeasuredDimension决定了当前View的大小。Dimension是尺寸的意思 - drawableToBitmap方法中
drawable.getIntrinsicWidth();
参考:获得drawable的宽
Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
参考:即创建一个空数组
new Canvas(bitmap)
这就是我们一直以来用的canvas的创建方式了!用位图来绘制,所以传入bitmap
drawable.setBounds(0, 0, w, h);
表示drawable会绘制在(0,0) (w,h)区域内
drawable.draw(canvas);
Drawable就是一个可画的对象,其可能是一张位图(BitmapDrawable),也可能是一个图形(ShapeDrawable),还有可能是一个图层(LayerDrawable)。所以想paint一样可以画
后记
-
类似于自定义View注入失败这种报错,不是只和构造函数有关系。
如果说自定义View里面有比如空指针这样的bug,IDE并不会报错空指针,而是报错注入失败。 -
不借鉴别人的,真的不知道有这么些api。不知道有哪些api,就是巧妇难为无米之炊。