今日防疫提示
房间应每日开窗通风,上下午各1次,每次通风时间30分钟以上,可选择阳光充足的时间段进行,保持空气清新。
今天项目需要用到一个圆角ImageView,本来已经打开了百度搜索“Android圆角Image...”,还是打消了这个念头,本着一个热(xian)爱(de)学(dan)习(teng)的态度,这个轮子还是自己动手造一下吧
由于只是需要实现圆角效果,直接继承ImageView即可,这里为了兼容,选中继承androidx下的AppcompatImageView.
1.自定义属性
简单粗暴,一般来说,我们是需要四个角都是统一半径的圆角,所以定义一个radius就可以了。但是不排除万能的PM可能要你明天只要左上圆角和右下圆角,所以四个圆角半径也分别定义一下。
<declare-styleable name="RoundImageView">
<!--一步到位,四个圆角统一半径-->
<attr name="radius" format="dimension"/>
<!--左上圆角半径-->
<attr name="left_top_radius" format="dimension"/>
<!--右上圆角半径-->
<attr name="right_top_radius" format="dimension"/>
<!--左下圆角半径-->
<attr name="left_bottom_radius" format="dimension"/>
<!--右下圆角半径-->
<attr name="right_bottom_radius" format="dimension"/>
</declare-styleable>
2. 实现方法
实现圆角ImageView基本上有两种思路:
综合实际考虑,实际项目中,基本都会将ImageView的scaleType设为center_crop或者scaleXY, 一般是不会出现图片比实际控件小的情况,所以本文实现第一种方式,简简单单,需要的变量如下:
public class RoundImageView extends AppCompatImageView {
//控件宽度,需要用来检验圆角半径合法性
private float width;
//控件高度,需要用来检验圆角半径合法性
private float height;
//统一圆角半径
private int mRadius;
//左上圆角半径-
private int mLeftTopRadius;
//右上圆角半径-
private int mRightTopRadius;
//右下圆角半径-
private int mRightBottomRadius;
//左下圆角半径-
private int mLeftBottomRadius;
//带圆角的Path
private Path mRoundPath;
圆角实现
1、 获取自定义属性
public RoundImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mRoundPath = new Path();
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RoundImageView, defStyleAttr, 0);
mRadius = typedArray.getDimensionPixelSize(R.styleable.RoundImageView_radius, 0);
mLeftTopRadius = typedArray.getDimensionPixelSize(R.styleable.RoundImageView_left_top_radius, 0);
mLeftBottomRadius = typedArray.getDimensionPixelSize(R.styleable.RoundImageView_left_bottom_radius, 0);
mRightTopRadius = typedArray.getDimensionPixelSize(R.styleable.RoundImageView_right_top_radius, 0);
mRightBottomRadius = typedArray.getDimensionPixelSize(R.styleable.RoundImageView_right_bottom_radius, 0);
//别忘了释放资源
typedArray.recycle();
}
2、绘制前,校验参数合法性
为了增强健壮性,如果用户设置一个无穷大的圆角半径,那画出来就是个妖怪了,所以要进行参数校验,圆角半径不能超过边长的一半
private void checkRadius() {
//如果未分别设置四个原画半径,都使用统一圆角半径
if (mLeftTopRadius == 0) {
mLeftTopRadius = mRadius;
}
if (mLeftBottomRadius == 0) {
mLeftBottomRadius = mRadius;
}
if (mRightTopRadius == 0) {
mRightTopRadius = mRadius;
}
if (mRightBottomRadius == 0) {
mRightBottomRadius = mRadius;
}
//获取控件较短的一条边
int minSize = (int) (Math.min(width, height) / 2);
//如果用户任意设置一个很大的半径,将radius修正为较短边的一半
//显示效果就是一个圆或者两端呈圆形的矩形
if (mLeftTopRadius > minSize) {
mLeftTopRadius = minSize;
}
if (mLeftBottomRadius > minSize) {
mLeftBottomRadius = minSize;
}
if (mRightTopRadius > minSize) {
mRightTopRadius = minSize;
}
if (mRightBottomRadius > minSize) {
mRightBottomRadius = minSize;
}
}
3、绘制圆角路径
这里使用二阶贝塞尔曲线来绘制圆角弧度,当然用arcTo( ) 也是可以的,同时由于没有设置默认圆角半径,减少不必要的绘制,如果用户没有设置圆角半径,直接按原图绘制即可
四个圆角分别绘制,可以实现任意圆角,其他角保持直角
@Override
protected void onDraw(Canvas canvas) {
checkRadius();
mRoundPath.reset();
//绘制左上圆角
if (mLeftTopRadius != 0) {
mRoundPath.moveTo(0, mLeftTopRadius);
mRoundPath.quadTo(0, 0, mLeftTopRadius, 0);
} else {
//如果未设置圆角,不作处理,下同
mRoundPath.moveTo(0, 0);
}
//绘制右上圆角
if (mRightTopRadius != 0) {
mRoundPath.lineTo(width - mRightTopRadius, 0);
mRoundPath.quadTo(width, 0, width, mRightTopRadius);
} else {
mRoundPath.lineTo(width, 0);
}
//绘制右下圆角
if (mRightBottomRadius != 0) {
mRoundPath.lineTo(width, height - mRightBottomRadius);
mRoundPath.quadTo(width, height, width - mRightBottomRadius, height);
} else {
mRoundPath.lineTo(width, height);
}
//绘制左下圆角
if (mLeftBottomRadius != 0) {
mRoundPath.lineTo(mLeftBottomRadius, height);
mRoundPath.quadTo(0, height, 0, height - mLeftBottomRadius);
} else {
mRoundPath.lineTo(0, height);
}
mRoundPath.close();
canvas.clipPath(mRoundPath);
super.onDraw(canvas);
}
实现效果
API返回原图:
实际效果:
布局文件:
<com.android.xxx.ui.widget.RoundImageView
android:id="@+id/banner_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:radius="6dp"
android:scaleType="fitXY" />
由于时间紧急,还有很多考虑不周的地方,请各位大牛指正,反正...