昨天有个朋友让我折腾一个这样的ImageView,
他说“我想要一个既可以圆角又可以设置宽高比的imageview”
所以我就折腾了下。
大概是这样的
1.attributes
这里说一下:如果参考边是:宽,那么你高度的设置其实是没有效果的
因为,代码里面 我直接把高度重新计算了
<declare-styleable name="SakuraImage">
<!--参考边-->
<attr name="refer" format="enum">
<enum name="宽" value="1"/>
<enum name="高" value="2"/>
</attr>
<!--长宽比例-->
<attr name="ratio" format="float"/>
<!--圆弧度-->
<attr name="radius" format="float"/>
</declare-styleable>
2.xml
<mos.kos.cache.widget.SakuraImage
android:layout_width="200dp"
android:layout_height="200dp"
android:scaleType="centerCrop"
android:src="@drawable/image"
sakura:radius="20"
sakura:ratio="1"
sakura:refer="高"/>
3.Code
3.1.长宽按比例设置
这一步主要是在
onMeasure
里面完成的
具体的看下面的代码和代码里的注释
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (ratio > 0) {
//参考边为:宽
if (referEdge == 1) {
ratioW = MeasureSpec.getSize(widthMeasureSpec);
ratioH = (int) (ratioW * ratio);//根据宽来计算高
//参考边为:高
} else {
ratioH = MeasureSpec.getSize(heightMeasureSpec);
ratioW = (int) (ratioH * ratio);//根据高来计算宽
}
//丢给父类处理
super.onMeasure(MeasureSpec.makeMeasureSpec(ratioW, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(ratioH, MeasureSpec.EXACTLY));
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
Logger.v("宽高1:ratioW=" + ratioW + ",ratioH=" + ratioH);
}
3.2.设置带圆弧的图片
这里稍微麻烦一点,不过主要还是在
onDraw
里面处理的
- 1.先找到图片的锚点
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
rectF.top = 0;
rectF.left = 0;
rectF.right = getWidth(); // 宽度
rectF.bottom = getHeight(); // 高度
setBitmapShader();
}
- 2.关键的一步:设置图片的透明区域Shader
下面是一段伪代码,把这一块的关键点都整到一起的
//先整一个画笔
Paint bmpPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
bmpPaint.setStyle(Paint.Style.FILL);
bmpPaint.setAntiAlias(true);
//这里的bmp是搞到的Bitmap图片
BitmapShader bmpShader = new BitmapShader(bmp,
Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
//bmpShader 就是圆弧所裁剪调的透明区域
bmpPaint.setShader(bmpShader);
//这个矩阵主要是对裁剪后的图片做缩放、还有位置的处理
matrix.set(null);//设为默认值,固定为CENTER_CROP
// 缩放
float scale = Math.max(getWidth() * 1f / bmp.getWidth(), getHeight() * 1f / bmp.getHeight());
// 居中
float dx = (getWidth() - bmp.getWidth() * scale) / 2;
float dy = (getHeight() - bmp.getHeight() * scale) / 2;
matrix.setScale(scale, scale);
matrix.postTranslate(dx, dy);
bmpShader.setLocalMatrix(matrix);
invalidate();//刷新
- 3.最后绘制
这里我踩了个坑,记录一下:
绘制的时候最好
用Canvas 的路径绘制canvas.drawPath()
,就是第1步打的那4个锚点,这样也是最简单的我之前尝试过直接用画布来绘制矩形
canvas.drawRoundRect(
或者绘制图形canvas.drawBitmap(
。
虽然也成功了,但是效果不怎么理想。
@Override
protected void onDraw(Canvas canvas) {
if (bmp != null) {
path.reset();
path.addRoundRect(rectF, radius, radius, Path.Direction.CW);
canvas.drawPath(path, bmpPaint);
}
}
最后丢再几张效果图
- 1.宽高比为1的时候
- 2.这里是以宽为参考边
- 3.这里是以高为参考边