Android视图裁剪

70
有没有办法在Android(Honeycomb)中定义ViewGroup的剪辑区域?例如,我有一个带有圆角的图像背景的ListView。当我滚动列表时,子项超出了背景的角落 - 我希望它们在圆角内剪切。
左侧图片是当前的效果,右侧是我想要的效果。
我正在看ClipDrawable,但似乎这只能用于进度条?
另外,我正在尝试在小部件中完成此操作。因此,我无法使用自定义视图并覆盖onDraw进行遮罩处理。
谢谢!

你找到解决方案了吗?我也在尝试在小部件中实现这个。 - anavarroma
9个回答

30

请确保layout具有带圆角的背景。

Kotlin

layout.outlineProvider = ViewOutlineProvider.BACKGROUND
layout.clipToOutline = true

Java

layout.setOutlineProvider(ViewOutlineProvider.BACKGROUND);
layout.setClipToOutline(true);

7
需要 API Level 21 注意。 - Sebek

26

尝试通过子类化ViewGroup并重写OnDraw方法,如下所示,用RADIUS_IN_PIXELS的值进行替换:

@Override
protected void onDraw(Canvas canvas) {
    Path clipPath = new Path();
    clipPath.addRoundRect(new RectF(canvas.getClipBounds()), RADIUS_IN_PIXELS, RADIUS_IN_PIXELS, Path.Direction.CW);
    canvas.clipPath(clipPath);
    super.onDraw(canvas);
}

...同时创建一个自定义的Drawable,例如名为“rounded”,使用YOUR_BACKGROUND_COLOR和RADIUS_IN_DP进行替换,确保将DP中矩形的圆角半径与以前PX中的裁剪半径匹配:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <corners android:radius="RADIUS_IN_DP" />
    <solid android:color="YOUR_BACKGROUND_COLOR"/>
</shape>

然后您可以在布局中使用该子类,加入以下行:

android:background="@drawable/rounded"
android:clipChildren="true"

所有的孩子都将按照您在OnDraw()重写中指定的边界进行裁剪,根据您的“圆角”可绘制对象添加背景。


8
不要在onDraw方法内实例化对象,否则会导致卡顿。 - Louis CAD
原问题是要求与RemoteViews兼容的内容。 - N1hk

6
使用overridden onDraw(Canvas canvas)创建自定义布局。
调用canvas.clipRect(0, 0, mCanvasWidth, mCanvasHeight);,这将剪裁所有超出布局边界的视图。
在构造函数中不要忘记调用setWillNotDraw(false),以便执行onDraw。

1
补充一下@Marco的回答,你还可以提供自定义的View.outlineProvider。我在使用Google较新的MaterialCardView时遇到了类似的问题。由于某种原因,该视图不会使用圆角裁剪其子视图。子视图只会绘制在圆角上方。
Kotlin:
val cornerRadius = 16.dp()
materialCardView.apply {
    clipToOutline = true
    outlineProvider = object : ViewOutlineProvider() {
        override fun getOutline(view: View?, outline: Outline?) {
            view?.apply {
                outline?.setRoundRect(0, 0, width, (height + cornerRadius).toInt(), cornerRadius)
            }
        }
    }
}

enter image description here


1
这样怎么样:如何将Android视图渲染为位图,然后裁剪该位图。
或者,另一个想法是使用FrameLayout,将您的剪辑蒙版堆叠在ViewGroup上。剪辑蒙版中间应该是透明的,边框不透明。
在这两种情况下,我猜处理用户输入会很棘手...

第一个选项行不通,因为它在小部件中,所以它必须只使用兼容RemoteViews的视图。 - Jon Ross
对于第二个选项,由于它是一个主屏幕小部件,剪辑蒙版不可行。 - Jon Ross

1
Path p = new Path()

// define your clipping path...

canvas.clipPath(p);

1

如果你看一下WhatsUp,你会发现在联系人图片中有一个被圆角边框包围的图像。 为了实现这个效果,我把ImageView放在了一个FrameLayout中(使用FrameLayout是因为我在图片前面使用了ProgressBar来通知加载[实际上是不可见的]),该FrameLayout具有圆角边框。图片呈正方形,但要使其更精细,需要使用画布进行处理。

再看一下这个链接,它将解决你的问题;)


0
也许你可以使用Canvas.clipRegion方法来裁剪两个视图之间的差异。

-4

尝试使用android:clipToPadding。它将解决你的问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接