Skip to content

Instantly share code, notes, and snippets.

@wyon
Created July 19, 2017 07:51
Show Gist options
  • Save wyon/c6262108e266dbc70e73a3c2fa97dfd5 to your computer and use it in GitHub Desktop.
Save wyon/c6262108e266dbc70e73a3c2fa97dfd5 to your computer and use it in GitHub Desktop.
RoundCornerImageView 带圆角的ImageView
public class RoundCornerImageView extends ImageView {
private final RectF mTmpRectF = new RectF();
private int topLeftRadius;
private int topRightRadius;
private int bottomLeftRadius;
private int bottomRightRadius;
// todo canvas.clipPath(Round Rect)?
private Path topLeftPath;
private Path topRightPath;
private Path bottomLeftPath;
private Path bottomRightPath;
private boolean hasRound;
private Paint roundPaint;
private Paint defaultPaint;
private Bitmap mTmpBitmap;
private Canvas mCanvasOrigin;
public RoundCornerImageView(Context context) {
super(context);
init(context, null);
}
public RoundCornerImageView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public RoundCornerImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public RoundCornerImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
if (attrs != null) {
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RoundCornerImageView);
if (a != null) {
final int radius = a.getDimensionPixelSize(R.styleable.RoundCornerImageView_radius, 0);
topLeftRadius = a.getDimensionPixelSize(R.styleable.RoundCornerImageView_topLeftRadius, radius);
topRightRadius = a.getDimensionPixelSize(R.styleable.RoundCornerImageView_topRightRadius, radius);
bottomLeftRadius = a.getDimensionPixelSize(R.styleable.RoundCornerImageView_bottomLeftRadius, radius);
bottomRightRadius = a.getDimensionPixelSize(R.styleable.RoundCornerImageView_bottomRightRadius, radius);
a.recycle();
}
}
setHasRound();
}
private void setHasRound() {
hasRound = topLeftRadius > 0
|| topRightRadius > 0
|| bottomLeftRadius > 0
|| bottomRightRadius > 0;
if (hasRound && roundPaint == null) {
roundPaint = new Paint();
roundPaint.setColor(Color.WHITE);
roundPaint.setAntiAlias(true);
roundPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
defaultPaint = new Paint();
defaultPaint.setXfermode(null);
}
}
private void resetRoundPath() {
topLeftPath = topRightPath = bottomLeftPath = bottomRightPath = null;
}
private void initTopLeftPath() {
if (topLeftRadius > 0) {
if (topLeftPath == null) {
final Path path = new Path();
path.moveTo(0, topLeftRadius);
path.lineTo(0, 0);
path.lineTo(topLeftRadius, 0);
mTmpRectF.setEmpty();
mTmpRectF.set(0, 0, topLeftRadius * 2, topLeftRadius * 2);
path.arcTo(mTmpRectF, -90, -90);
path.close();
topLeftPath = path;
}
} else {
topLeftPath = null;
}
}
private void initTopRightPath() {
if (topRightRadius > 0) {
if (topRightPath == null) {
final Path path = new Path();
final int width = getWidth();
path.moveTo(width, topRightRadius);
path.lineTo(width, 0);
path.lineTo(width - topRightRadius, 0);
mTmpRectF.setEmpty();
mTmpRectF.set(width - topRightRadius * 2, 0, width, topRightRadius * 2);
path.arcTo(mTmpRectF, -90, 90);
path.close();
topRightPath = path;
}
} else {
topRightPath = null;
}
}
private void initBottomLeftPath() {
if (bottomLeftRadius > 0) {
if (bottomLeftPath == null) {
final Path path = new Path();
final int height = getHeight();
path.moveTo(0, height - bottomLeftRadius);
path.lineTo(0, height);
path.lineTo(bottomLeftRadius, height);
mTmpRectF.setEmpty();
mTmpRectF.set(0, height - bottomLeftRadius * 2, bottomLeftRadius * 2, height);
path.arcTo(mTmpRectF, 90, 90);
path.close();
bottomLeftPath = path;
}
} else {
bottomLeftPath = null;
}
}
private void initBottomRightPath() {
if (bottomRightRadius > 0) {
if (bottomRightPath == null) {
final Path path = new Path();
final int width = getWidth();
final int height = getHeight();
path.moveTo(width - bottomRightRadius, height);
path.lineTo(width, height);
path.lineTo(width, height - bottomRightRadius);
mTmpRectF.setEmpty();
mTmpRectF.set(width - bottomRightRadius * 2, height - bottomRightRadius * 2, width, height);
path.arcTo(mTmpRectF, 0, 90);
path.close();
bottomRightPath = path;
}
} else {
bottomRightPath = null;
}
}
private boolean canDrawRound() {
return hasRound && getWidth() != 0 && getHeight() != 0;
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
resetRoundPath();
if (!canDrawRound()) {
return;
}
initTopLeftPath();
initTopRightPath();
initBottomLeftPath();
initBottomRightPath();
if (mTmpBitmap != null) {
mTmpBitmap.recycle();
mTmpBitmap = null;
mCanvasOrigin = null;
}
}
@Override
public void draw(Canvas canvas) {
if (!canDrawRound()) {
super.draw(canvas);
return;
}
initCanvasOrigin();
mCanvasOrigin.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
super.draw(mCanvasOrigin);
// draw top left
if (topLeftPath != null) {
mCanvasOrigin.drawPath(topLeftPath, roundPaint);
}
// draw top right
if (topRightPath != null) {
mCanvasOrigin.drawPath(topRightPath, roundPaint);
}
// draw bottom left
if (bottomLeftPath != null) {
mCanvasOrigin.drawPath(bottomLeftPath, roundPaint);
}
// draw bottom right
if (bottomRightPath != null) {
mCanvasOrigin.drawPath(bottomRightPath, roundPaint);
}
canvas.drawBitmap(mTmpBitmap, 0, 0, defaultPaint);
}
private void initCanvasOrigin() {
if (mTmpBitmap == null) {
mTmpBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
mCanvasOrigin = new Canvas(mTmpBitmap);
}
}
}
<declare-styleable name="RoundCornerImageView">
<attr name="topLeftRadius" format="dimension"/>
<attr name="topRightRadius" format="dimension"/>
<attr name="bottomLeftRadius" format="dimension"/>
<attr name="bottomRightRadius" format="dimension"/>
<attr name="radius" format="dimension"/>
</declare-styleable>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment