Вот способ, который я обнаружил, чтобы сделать это с помощью ImageView. Я пробовал другие методы, в том числе ответы здесь и на похожие вопросы, но обнаружил, что они не работают для меня, так как мне нужно, чтобы углы были применены к представлению изображения, а не непосредственно к растровому изображению. Применение непосредственно к растровому изображению не будет работать, если вы масштабируете / обрезаете / панорамируете это растровое изображение, поскольку углы также будут масштабироваться / обрезаться / панорамироваться.
public class RoundedCornersImageView extends ImageView {
private final Paint restorePaint = new Paint();
private final Paint maskXferPaint = new Paint();
private final Paint canvasPaint = new Paint();
private final Rect bounds = new Rect();
private final RectF boundsf = new RectF();
public RoundedCornersImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public RoundedCornersImageView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public RoundedCornersImageView(Context context) {
super(context);
init();
}
private void init() {
canvasPaint.setAntiAlias(true);
canvasPaint.setColor(Color.argb(255, 255, 255, 255));
restorePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP));
maskXferPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));
}
@Override
protected void onDraw(Canvas canvas) {
canvas.getClipBounds(bounds);
boundsf.set(bounds);
canvas.saveLayer(boundsf, restorePaint, Canvas.ALL_SAVE_FLAG);
super.onDraw(canvas);
canvas.saveLayer(boundsf, maskXferPaint, Canvas.ALL_SAVE_FLAG);
canvas.drawARGB(0, 0, 0, 0);
canvas.drawRoundRect(boundsf, 75, 75, canvasPaint);
canvas.restore();
canvas.restore();
}
}
Вот альтернатива, которая использует аппаратные слои для окончательного слоя:
public class RoundedCornersImageView extends ImageView {
private final Paint restorePaint = new Paint();
private final Paint maskXferPaint = new Paint();
private final Paint canvasPaint = new Paint();
private final Rect bounds = new Rect();
private final RectF boundsf = new RectF();
public RoundedCornersImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public RoundedCornersImageView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public RoundedCornersImageView(Context context) {
super(context);
init();
}
private void init() {
canvasPaint.setAntiAlias(true);
canvasPaint.setColor(Color.argb(255, 255, 255, 255));
restorePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP));
maskXferPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));
setLayerType(View.LAYER_TYPE_HARDWARE, restorePaint);
}
@Override
protected void onDraw(Canvas canvas) {
canvas.getClipBounds(bounds);
boundsf.set(bounds);
super.onDraw(canvas);
canvas.saveLayer(boundsf, maskXferPaint, Canvas.ALL_SAVE_FLAG);
canvas.drawARGB(0, 0, 0, 0);
canvas.drawRoundRect(boundsf, 75, 75, canvasPaint);
canvas.restore();
}
}
Сначала я не смог заставить его работать с этим методом, потому что мои углы становились черными; Позже я понял, в чем проблема после прочтения этого вопроса: Android, как применить маску к ImageView? . Оказывается, что изменение альфы на холсте на самом деле «царапает ее» прямо на экране и пробивает дыру в нижнем окне, которое является черным. Вот почему необходимы два слоя: один для наложения маски, а другой для наложения составного изображения на экран.