You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在XML中裁剪CardView内图片左下角实现半圆角效果?

CardView内图片左下角半圆角裁剪实现方案

以下方案均适配Android平台原生CardView组件:

方案1:使用Material Components ShapeableImageView(推荐,代码量最低)

无需自定义View,依赖官方Material库实现:

  • 先在模块级build.gradle中引入依赖(已引入可跳过):
implementation 'com.google.android.material:material:1.9.0'
  • 布局中将普通ImageView替换为ShapeableImageView,嵌入CardView内部:
<androidx.cardview.widget.CardView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:cardPreventCornerOverlap="true"
    app:cardElevation="4dp">

    <com.google.android.material.imageview.ShapeableImageView
        android:id="@+id/coverIv"
        android:layout_width="match_parent"
        android:layout_height="200dp"
        android:scaleType="centerCrop"
        android:src="@drawable/your_image"/>

</androidx.cardview.widget.CardView>
  • 代码中仅给左下角设置圆角即可:
// 8为圆角大小,单位dp,可按需调整
val cornerRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8f, resources.displayMetrics)
coverIv.shapeAppearanceModel = ShapeAppearanceModel.builder()
    .setBottomLeftCorner(CornerFamily.ROUNDED, cornerRadius)
    .build()

方案2:自定义ImageView实现(无第三方依赖)

如果不想引入Material库,可自定义ImageView重写绘制逻辑实现裁剪:

public class LeftBottomRoundImageView extends AppCompatImageView {
    // 圆角大小,单位px,可通过自定义属性从xml配置
    private final float roundRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8, getResources().getDisplayMetrics());
    private final Path clipPath = new Path();

    public LeftBottomRoundImageView(Context context) {
        super(context);
        setLayerType(LAYER_TYPE_SOFTWARE, null); // 关闭硬件加速避免裁剪失效
    }

    public LeftBottomRoundImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        setLayerType(LAYER_TYPE_SOFTWARE, null);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        int width = getWidth();
        int height = getHeight();
        clipPath.reset();
        // 构建仅左下角带圆角的裁剪区域
        clipPath.moveTo(0, 0);
        clipPath.lineTo(width, 0);
        clipPath.lineTo(width, height);
        clipPath.lineTo(roundRadius, height);
        clipPath.quadTo(0, height, 0, height - roundRadius);
        clipPath.close();
        canvas.clipPath(clipPath);
        super.onDraw(canvas);
    }
}

直接将上述自定义View放入CardView中使用即可。

方案3:图片加载库Transformation实现

如果使用Glide、Picasso等图片加载库,可通过自定义Transformation实现裁剪,不侵入布局:
以Glide为例,自定义Transformation代码:

class LeftBottomRoundTransform(private val radiusDp: Int) : BitmapTransformation() {
    private val radiusPx = TypedValue.applyDimension(
        TypedValue.COMPLEX_UNIT_DIP,
        radiusDp.toFloat(),
        Resources.getSystem().displayMetrics
    )

    override fun transform(
        pool: BitmapPool,
        toTransform: Bitmap,
        outWidth: Int,
        outHeight: Int
    ): Bitmap {
        val output = pool.get(outWidth, outHeight, Bitmap.Config.ARGB_8888)
        val canvas = Canvas(output)
        val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
            shader = BitmapShader(toTransform, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
        }
        val path = Path().apply {
            moveTo(0f, 0f)
            lineTo(outWidth.toFloat(), 0f)
            lineTo(outWidth.toFloat(), outHeight.toFloat())
            lineTo(radiusPx, outHeight.toFloat())
            quadTo(0f, outHeight.toFloat(), 0f, outHeight - radiusPx)
            close()
        }
        canvas.drawPath(path, paint)
        return output
    }

    override fun updateDiskCacheKey(messageDigest: MessageDigest) {
        messageDigest.update("left_bottom_round_$radiusDp".toByteArray())
    }
}

使用时直接添加到Glide加载逻辑即可:

Glide.with(context)
    .load(yourImageUrl)
    .transform(LeftBottomRoundTransform(8)) // 8为圆角大小,单位dp
    .into(coverIv)

内容的提问来源于stack exchange,提问作者Abhas Sharma

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 21:27:00