如何将ImageView转换为指定形状?求兼容低API的实现方案
解决ImageView图片自定义形状(兼容API<23)的方案
我理解你的痛点——想要把ImageView中的图片裁剪成特定形状,还得兼容API 23以下的版本,试了设置foreground(但动态设置只支持高版本)和GradientDrawable都没解决问题。这里给你两个可靠的解决方案,亲测在低版本Android上也能正常工作:
方案一:自定义ImageView+BitmapShader(灵活适配任意形状)
这个方法通过自定义View,利用BitmapShader将原图填充到你定义的任意路径中,完全不受API版本限制。
代码示例
public class ShapeImageView extends AppCompatImageView { private Paint mPaint; private Path mShapePath; // 用于定义目标形状的路径 public ShapeImageView(Context context) { super(context); init(); } public ShapeImageView(Context context, AttributeSet attrs) { super(context, attrs); init(); } private void init() { mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mShapePath = new Path(); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); // 在这里定义你的目标形状,示例为「顶部左右圆角、底部直角」的形状 float cornerRadius = dpToPx(20); mShapePath.reset(); mShapePath.moveTo(cornerRadius, 0); mShapePath.lineTo(w - cornerRadius, 0); mShapePath.arcTo(new RectF(w - 2*cornerRadius, 0, w, 2*cornerRadius), 270, 90); mShapePath.lineTo(w, h); mShapePath.lineTo(0, h); mShapePath.lineTo(0, cornerRadius); mShapePath.arcTo(new RectF(0, 0, 2*cornerRadius, 2*cornerRadius), 180, 90); mShapePath.close(); // 将原图转换为BitmapShader,填充到Paint中 Bitmap bitmap = drawableToBitmap(getDrawable()); if (bitmap != null) { BitmapShader shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); mPaint.setShader(shader); } } @Override protected void onDraw(Canvas canvas) { // 按照定义的路径绘制图片 canvas.drawPath(mShapePath, mPaint); } // 辅助方法:Drawable转Bitmap private Bitmap drawableToBitmap(Drawable drawable) { if (drawable instanceof BitmapDrawable) { return ((BitmapDrawable) drawable).getBitmap(); } Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); drawable.draw(canvas); return bitmap; } // 辅助方法:DP转PX private float dpToPx(float dp) { return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics()); } }
使用说明
- 在布局文件中直接使用这个自定义
ShapeImageView,就像普通ImageView一样设置图片 - 修改
onSizeChanged里的mShapePath代码,就能定义你需要的任意形状(比如多边形、特殊圆角等)
方案二:ShapeDrawable遮罩+PorterDuffXfermode(无需自定义View)
如果不想自定义View,可以通过遮罩混合的方式,将原图裁剪成指定形状,兼容所有支持PorterDuffXfermode的Android版本(1.6+)。
代码示例
/** * 将原图与指定形状的遮罩混合,生成带形状的Drawable * @param originalBitmap 原始图片Bitmap * @param shapeDrawable 目标形状的ShapeDrawable * @return 裁剪后的Drawable */ public static Drawable getShapeMaskedDrawable(Bitmap originalBitmap, ShapeDrawable shapeDrawable) { // 绘制遮罩Bitmap Bitmap maskBitmap = Bitmap.createBitmap(originalBitmap.getWidth(), originalBitmap.getHeight(), Bitmap.Config.ARGB_8888); Canvas maskCanvas = new Canvas(maskBitmap); shapeDrawable.setBounds(0, 0, maskCanvas.getWidth(), maskCanvas.getHeight()); shapeDrawable.draw(maskCanvas); // 混合原图与遮罩,只保留重叠部分 Bitmap resultBitmap = Bitmap.createBitmap(originalBitmap.getWidth(), originalBitmap.getHeight(), Bitmap.Config.ARGB_8888); Canvas resultCanvas = new Canvas(resultBitmap); Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN)); resultCanvas.drawBitmap(originalBitmap, 0, 0, null); resultCanvas.drawBitmap(maskBitmap, 0, 0, paint); paint.setXfermode(null); return new BitmapDrawable(resultBitmap); }
使用方式
// 1. 创建目标形状的ShapeDrawable,示例为「顶部圆角、底部直角」的矩形 float[] radii = new float[]{20,20,20,20,0,0,0,0}; ShapeDrawable shapeDrawable = new ShapeDrawable(new RoundRectShape(radii, null, null)); shapeDrawable.getPaint().setColor(Color.WHITE); // 颜色任意,只要不透明即可 // 2. 假设你已经获取到原始图片的Bitmap(originalBitmap) Drawable maskedDrawable = getShapeMaskedDrawable(originalBitmap, shapeDrawable); // 3. 设置给ImageView imageView.setImageDrawable(maskedDrawable);
适用场景
适合简单形状(如圆角、椭圆、矩形)的裁剪,无需自定义View,代码更轻量化。
内容的提问来源于stack exchange,提问作者Srinivas Nahak
相关产品推荐
相关产品推荐

