[Android]【安卓】自定义圆角图片,可在xml中设置任意角是否为圆角
本篇博客已收录到我的安卓开发小结中——点击【安卓开发小结】
- 本篇博客有参考博客【android自定义一圆角ImageView】
- 较原博客,本篇博客有如下改进:
1、可在xml中设置四个角中的任意一个角是否为圆角。
2、将px改为dp。
3、增加原理说明。
修改后代码如下:
1、在values文件夹下,新建一个attrs.xml资源文件。
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="C2RoundAngleImageView">
<attr name="roundWidth2" format="dimension" />
<attr name="roundHeight2" format="dimension" />
<attr name="leftUpCorner" format="boolean" />
<attr name="rightUpCorner" format="boolean" />
<attr name="leftDownCorner" format="boolean" />
<attr name="rightDownCorner" format="boolean" />
</declare-styleable>
</resources>
2、自定义View。
public class C2RoundAngleImageView extends ImageView {
private Paint paint;
private int roundWidth = 10;
private int roundHeight = 10;
private boolean rightUpCorner = true;
private boolean leftUpCorner = true;
private boolean rightDownCorner = true;
private boolean leftDownCorner = true;
private Paint paint2;
private static Context context;
public C2RoundAngleImageView(Context context) {
super(context);
init(context, null);
}
public C2RoundAngleImageView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public C2RoundAngleImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
this.context = context;
if(attrs != null) {
//Point1
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.C2RoundAngleImageView);
roundWidth= a.getDimensionPixelSize(R.styleable.C2RoundAngleImageView_roundWidth2, roundWidth);
roundHeight= a.getDimensionPixelSize(R.styleable.C2RoundAngleImageView_roundHeight2, roundHeight);
rightUpCorner = a.getBoolean(R.styleable.C2RoundAngleImageView_rightUpCorner,true);
rightDownCorner = a.getBoolean(R.styleable.C2RoundAngleImageView_rightDownCorner,true);
leftUpCorner = a.getBoolean(R.styleable.C2RoundAngleImageView_leftUpCorner,true);
leftDownCorner = a.getBoolean(R.styleable.C2RoundAngleImageView_leftDownCorner,true);
}else {
//Point2
float density = context.getResources().getDisplayMetrics().density;
roundWidth = (int) (roundWidth*density);
roundHeight = (int) (roundHeight*density);
}
paint = new Paint();
paint.setColor(Color.WHITE);
paint.setAntiAlias(true);
//Point3
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
paint2 = new Paint();
paint2.setXfermode(null);
}
@TargetApi(Build.VERSION_CODES.KITKAT)
@Override
public void draw(Canvas canvas) {
//Point4
Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_4444);
try {
Canvas canvas2 = new Canvas(bitmap);
//Point5
super.draw(canvas2);
if(leftUpCorner){
//Point6
drawLiftUp(canvas2);
}
if(leftDownCorner){
drawLiftDown(canvas2);
}
if(rightUpCorner){
drawRightUp(canvas2);
}
if(rightDownCorner){
drawRightDown(canvas2);
}
//Point7
canvas.drawBitmap(bitmap, 0, 0, paint2);
bitmap.recycle();
} catch (Throwable e) {
e.printStackTrace();
}
}
private void drawLiftUp(Canvas canvas) {
Path path = new Path();
path.moveTo(0, roundHeight);
path.lineTo(0, 0);
path.lineTo(roundWidth, 0);
path.arcTo(new RectF(
0,
0,
roundWidth * 2,
roundHeight * 2),
-90,
-90);
path.close();
canvas.drawPath(path, paint);
}
private void drawLiftDown(Canvas canvas) {
Path path = new Path();
path.moveTo(0, getHeight()-roundHeight);
path.lineTo(0, getHeight());
path.lineTo(roundWidth, getHeight());
path.arcTo(new RectF(
0,
getHeight()-roundHeight*2,
0+roundWidth*2,
getHeight()),
90,
90);
path.close();
canvas.drawPath(path, paint);
}
private void drawRightDown(Canvas canvas) {
Path path = new Path();
path.moveTo(getWidth()-roundWidth, getHeight());
path.lineTo(getWidth(), getHeight());
path.lineTo(getWidth(), getHeight()-roundHeight);
path.arcTo(new RectF(
getWidth()-roundWidth*2,
getHeight()-roundHeight*2,
getWidth(),
getHeight()), 0, 90);
path.close();
canvas.drawPath(path, paint);
}
private void drawRightUp(Canvas canvas) {
Path path = new Path();
path.moveTo(getWidth(), roundHeight);
path.lineTo(getWidth(), 0);
path.lineTo(getWidth()-roundWidth, 0);
path.arcTo(new RectF(
getWidth()-roundWidth*2,
0,
getWidth(),
0+roundHeight*2),
-90,
90);
path.close();
canvas.drawPath(path, paint);
}
}
- Point1:在这里接收xml里设置的参数。
- Point2:在这里将px转化为dp。
- Point3:设置画笔的Xfermode类型为PorterDuff.Mode.DST_OUT,这种模式可以理解为在不相交的地方绘制源图像
- Point4:根据canvas的尺寸创建一个可以修改的Bitmap对象。
- Point5:根据Bitmap对象创建一个canvas2画布,并让本将draw到canvas上的View画到canvas2的bitmap上,可看源码:
public void draw(Canvas canvas) {
final int privateFlags = mPrivateFlags;
final boolean dirtyOpaque = (privateFlags & PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE &&
(mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState);
mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN;
/*
* Draw traversal performs several drawing steps which must be executed
* in the appropriate order:
*
* 1. Draw the background
* 2. If necessary, save the canvas' layers to prepare for fading
* 3. Draw view's content
* 4. Draw children
* 5. If necessary, draw the fading edges and restore layers
* 6. Draw decorations (scrollbars for instance)
*/
... ...
}
- Point6:在左上角绘制一个待切除的Path闭合路径,并与画布进行Xfermode处理,切出圆角,bitmap的轮廓随着canvas2一同改变。
- Point7:将切割好圆角的bitmap绘制到要展现的画布canvas上。
3、在xml中使用。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:round="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<!-- 列表图片 -->
<com.example.weihy.mygithubproject.C2RoundAngleImageView
android:id="@+id/c2lamp_recipe_img"
android:layout_width="300dp"
android:layout_height="160dp"
android:scaleType="centerCrop"
android:src="@drawable/coffee"
round:leftUpCorner="false"
round:rightDownCorner="false"
round:roundHeight2="50dp"
round:roundWidth2="50dp"
/>
</LinearLayout>