圆角圆形图片解决方案
2018-07-17 本文已影响54人
Wish_xy
一个圆角图片的解决方案,解决设计需要不同圆角图片时,避免重复让设计师出不一样的切图。
废话不多说,先上效果图:
圆角图形.jpg
属性介绍
参数 | 属性 | 介绍 |
---|---|---|
round_rect_circle | boolean | 是否显示圆形 |
round_rect_corner | int | 圆角大小 |
round_rect_corner_top_to_left | int | 左上角圆弧 |
round_rect_corner_top_to_right | int | 右上角圆弧 |
round_rect_corner_bottom_to_left | int | 左下角圆弧 |
round_rect_corner_bottom_to_right | int | 右下角圆弧 |
round_rect_stroke_color | int | 描边颜色 |
round_rect_stroke_width | int | 描边大小 |
- round_rect_circle:默认false,如果是true,直接绘制圆形。
- round_rect_corner:四个角圆弧属性,默认为0。
- round_rect_corner_top_to_left:左上角圆弧,如果设置了该属性,round_rect_corner的左上角设置不起作用。
- round_rect_corner_top_to_right:右上角圆弧,如果设置了该属性,round_rect_corner的右上角设置不起作用。
- round_rect_corner_bottom_to_left:左下角圆弧,如果设置了该属性,round_rect_corner的左下角设置不起作用。
- round_rect_corner_bottom_to_right:右下角圆弧,如果设置了该属性,round_rect_corner的右下角设置不起作用。
- round_rect_stroke_color:描边的颜色,默认是白色。
- round_rect_stroke_width:圆弧的描边,默认描边的宽度是0。
实现思路
先上完整代码:
首先先定义圆角图形所需要的属性:
<declare-styleable name="RoundRectLayout">
<attr name="round_rect_circle" format="boolean"/>
<attr name="round_rect_corner" format="dimension"/>
<attr name="round_rect_corner_top_to_left" format="dimension"/>
<attr name="round_rect_corner_top_to_right" format="dimension"/>
<attr name="round_rect_corner_bottom_to_left" format="dimension"/>
<attr name="round_rect_corner_bottom_to_right" format="dimension"/>
<attr name="round_rect_stroke_color" format="color"/>
<attr name="round_rect_stroke_width" format="dimension"/>
</declare-styleable>
然后在定义一个RoundRectLayout继承RelativeLayout:完整代码如下:
ublic class RoundRectLayout extends RelativeLayout {
private RectF mRectF;//绘制画布的大小
public float[] mRadii = new float[8];//绘制眼角矩形所需的8个角
private boolean mCircle;//是否是绘制圆形
private int mRectCorner; //圆角弧度
private int mStrokeColor;// 描边颜色
private int mStrokeWidth;// 描边宽度
public RoundRectLayout(Context context) {
this(context, null);
}
public RoundRectLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public RoundRectLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView(context, attrs);
}
private void initView(Context context, AttributeSet attrs) {
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.RoundRectLayout);
mCircle = array.getBoolean(R.styleable.RoundRectLayout_round_rect_circle, false);
mRectCorner = array.getDimensionPixelSize(R.styleable.RoundRectLayout_round_rect_corner, 0);
int roundRectTopLeft = array.getDimensionPixelSize(R.styleable.RoundRectLayout_round_rect_corner_top_to_left, -1);
int roundRectTopRight = array.getDimensionPixelSize(R.styleable.RoundRectLayout_round_rect_corner_top_to_right, -1);
int roundRectBottomLeft = array.getDimensionPixelSize(R.styleable.RoundRectLayout_round_rect_corner_bottom_to_left, -1);
int roundRectBottomRight = array.getDimensionPixelSize(R.styleable.RoundRectLayout_round_rect_corner_bottom_to_right, -1);
mRadii[0] = roundRectTopLeft == -1 ? mRectCorner : roundRectTopLeft;
mRadii[1] = roundRectTopLeft == -1 ? mRectCorner : roundRectTopLeft;
mRadii[2] = roundRectTopRight == -1 ? mRectCorner : roundRectTopRight;
mRadii[3] = roundRectTopRight == -1 ? mRectCorner : roundRectTopRight;
mRadii[4] = roundRectBottomLeft == -1 ? mRectCorner : roundRectBottomLeft;
mRadii[5] = roundRectBottomLeft == -1 ? mRectCorner : roundRectBottomLeft;
mRadii[6] = roundRectBottomRight == -1 ? mRectCorner : roundRectBottomRight;
mRadii[7] = roundRectBottomRight == -1 ? mRectCorner : roundRectBottomRight;
mStrokeColor = array.getColor(R.styleable.RoundRectLayout_round_rect_stroke_color, Color.WHITE);
mStrokeWidth = array.getDimensionPixelSize(R.styleable.RoundRectLayout_round_rect_stroke_width, 0);
array.recycle();
mRectF = new RectF();
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mRectF.left = getPaddingLeft();
mRectF.top = getPaddingTop();
mRectF.right = w - getPaddingRight();
mRectF.bottom = h - getPaddingBottom();
}
@Override
protected void dispatchDraw(Canvas canvas) {
canvas.saveLayer(mRectF, null, Canvas.ALL_SAVE_FLAG);
super.dispatchDraw(canvas);
Path path = new Path();
path.reset();
//判断是否绘制圆
if (mCircle) {
float width = (mRectF.right - mRectF.left) > (mRectF.bottom - mRectF.top) ? mRectF.bottom - mRectF.top : mRectF.right - mRectF.left;
path.addCircle((mRectF.right - mRectF.left) / 2, (mRectF.bottom - mRectF.top) / 2, (width - mStrokeWidth) / 2, Path.Direction.CW);
} else {
path.addRoundRect(mRectF, mRadii, Path.Direction.CW);
}
Paint paint = new Paint();
paint.setAntiAlias(true);
//绘制描边
if (mStrokeWidth > 0) {
paint.setColor(mStrokeColor);
paint.setStrokeWidth(mStrokeWidth);
paint.setStyle(Paint.Style.STROKE);
canvas.drawPath(path, paint);
}
//剪切圆角矩形
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
paint.setStyle(Paint.Style.FILL);
canvas.drawPath(path, paint);
}
}
使用步骤
在xml文件直接引用
<com.android.round.weight.RoundRectLayout
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_margin="30dp"
app:round_rect_circle="true">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:src="@mipmap/club_bg"/>
<TextView
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_alignParentBottom="true"
android:background="@mipmap/bottom_bg"
android:gravity="center"
android:textColor="@android:color/white"
android:textSize="10sp"/>
</com.android.round.weight.RoundRectLayout>
具体的实现思路:
首先要获取自定义的属性:
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.RoundRectLayout);
mCircle = array.getBoolean(R.styleable.RoundRectLayout_round_rect_circle, false);
mRectCorner = array.getDimensionPixelSize(R.styleable.RoundRectLayout_round_rect_corner, 0);
int roundRectTopLeft = array.getDimensionPixelSize(R.styleable.RoundRectLayout_round_rect_corner_top_to_left, -1);
int roundRectTopRight = array.getDimensionPixelSize(R.styleable.RoundRectLayout_round_rect_corner_top_to_right, -1);
int roundRectBottomLeft = array.getDimensionPixelSize(R.styleable.RoundRectLayout_round_rect_corner_bottom_to_left, -1);
int roundRectBottomRight = array.getDimensionPixelSize(R.styleable.RoundRectLayout_round_rect_corner_bottom_to_right, -1);
mRadii[0] = roundRectTopLeft == -1 ? mRectCorner : roundRectTopLeft;
mRadii[1] = roundRectTopLeft == -1 ? mRectCorner : roundRectTopLeft;
mRadii[2] = roundRectTopRight == -1 ? mRectCorner : roundRectTopRight;
mRadii[3] = roundRectTopRight == -1 ? mRectCorner : roundRectTopRight;
mRadii[4] = roundRectBottomLeft == -1 ? mRectCorner : roundRectBottomLeft;
mRadii[5] = roundRectBottomLeft == -1 ? mRectCorner : roundRectBottomLeft;
mRadii[6] = roundRectBottomRight == -1 ? mRectCorner : roundRectBottomRight;
mRadii[7] = roundRectBottomRight == -1 ? mRectCorner : roundRectBottomRight;
mStrokeColor = array.getColor(R.styleable.RoundRectLayout_round_rect_stroke_color, Color.WHITE);
mStrokeWidth = array.getDimensionPixelSize(R.styleable.RoundRectLayout_round_rect_stroke_width, 0);
array.recycle();
获取到之后要及时关闭typeArray,这个不需要详述,然后在onSizeChanged()方法中获取当前view的大小属性。onSizeChanged方法会在view有改动的时候调用,第一次创建view的时候也会调用一次。然后在dispatchDraw()方法中绘制图形。
因为要使用setXfermode方法,所以首先要进行离屏缓冲,至于为什么,请点击了解,行离屏缓冲很简单,只需要一行代码:
canvas.saveLayer(mRectF, null, Canvas.ALL_SAVE_FLAG);
然后判断是绘制圆形还是圆角矩形,绘制画布路径
Path path = new Path();
path.reset();
//判断是否绘制圆
if (mCircle) {
float width = (mRectF.right - mRectF.left) > (mRectF.bottom - mRectF.top) ? mRectF.bottom - mRectF.top : mRectF.right - mRectF.left;
path.addCircle((mRectF.right - mRectF.left) / 2, (mRectF.bottom - mRectF.top) / 2, (width - mStrokeWidth) / 2, Path.Direction.CW);
} else {
path.addRoundRect(mRectF, mRadii, Path.Direction.CW);
}
之后判断是否需要描边
//绘制描边
if (mStrokeWidth > 0) {
paint.setColor(mStrokeColor);
paint.setStrokeWidth(mStrokeWidth);
paint.setStyle(Paint.Style.STROKE);
canvas.drawPath(path, paint);
}
最后通过drawPath方法绘制需要的图形
//剪切圆角矩形
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
paint.setStyle(Paint.Style.FILL);
canvas.drawPath(path, paint);
代码很简单,如果有需要,可以直接引用git项目