如何用Java/Kotlin实现上下带曲线的自定义ImageView(ViewPager滑块)
实现上下边缘带曲线的自定义ImageView

我正在使用ViewPager制作图片滑块,需要为列表项创建一个上下边缘带曲线的自定义ImageView,并且通过API加载图片。目前已能实现自定义矩形ImageView,但不清楚如何添加上下曲线。
已尝试方案:
- 将SVG设置给ImageView,但动态设置图片后形状发生变化。
- 继承ImageView实现自定义图片类。
解决方案一:通过ClipPath自定义View实现
直接继承AppCompatImageView,通过裁剪画布实现曲线边缘,适配动态加载的图片:
public class CurvedEdgeImageView extends androidx.appcompat.widget.AppCompatImageView { private Path mPath; private float mCurveHeight = 30f; // 曲线高度,可根据需求调整 public CurvedEdgeImageView(Context context) { super(context); init(); } public CurvedEdgeImageView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public CurvedEdgeImageView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { mPath = new Path(); // 关闭硬件加速,避免部分设备ClipPath失效 setLayerType(LAYER_TYPE_SOFTWARE, null); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mPath.reset(); // 绘制上边缘二次贝塞尔曲线 mPath.moveTo(0, mCurveHeight); mPath.quadTo(w / 2f, 0, w, mCurveHeight); // 连接右侧直线 mPath.lineTo(w, h - mCurveHeight); // 绘制下边缘二次贝塞尔曲线 mPath.quadTo(w / 2f, h, 0, h - mCurveHeight); // 连接左侧直线并闭合路径 mPath.lineTo(0, mCurveHeight); mPath.close(); } @Override protected void onDraw(Canvas canvas) { canvas.clipPath(mPath); super.onDraw(canvas); } // 提供方法动态调整曲线高度 public void setCurveHeight(float curveHeight) { mCurveHeight = curveHeight; requestLayout(); } }
使用时直接在布局xml中引用该类,正常用Glide/Picasso加载图片即可,无需额外处理形状适配。
解决方案二:使用ShapeDrawable作为遮罩
如果不想自定义View,可通过给ImageView设置遮罩实现曲线边缘:
- 创建遮罩Shape文件(
res/drawable/curved_mask.xml):
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <solid android:color="#FFFFFF"/> <path android:pathData="M0,30 Q@width/2,0 @width,30 L@width,@height-30 Q@width/2,@height 0,@height-30 Z"/> </shape>
注:@width和@height需替换为实际ImageView的宽高,或在代码中动态生成PathData。
- 代码中设置遮罩:
ImageView imageView = findViewById(R.id.your_image_view); imageView.setClipToOutline(true); imageView.setOutlineProvider(new ViewOutlineProvider() { @Override public void getOutline(View view, Outline outline) { Drawable mask = ContextCompat.getDrawable(view.getContext(), R.drawable.curved_mask); if (mask != null) { mask.setBounds(0, 0, view.getWidth(), view.getHeight()); mask.getOutline(outline); } } });
API 30及以上可直接在xml中配置:
<ImageView android:id="@+id/your_image_view" android:layout_width="match_parent" android:layout_height="200dp" android:clipToOutline="true" android:outlineProvider="@drawable/curved_mask"/>
注意事项
- ClipPath方案需关闭硬件加速,避免部分设备出现显示异常
- 使用图片加载框架时,确保ImageView尺寸已确定后再加载图片,避免路径计算错误
- 可通过自定义属性将曲线高度开放到xml中,提升复用性
内容的提问来源于stack exchange,提问作者Rakesh
相关产品推荐
相关产品推荐

