Android 视图剪辑

Posted

技术标签:

【中文标题】Android 视图剪辑【英文标题】:Android View Clipping 【发布时间】:2011-07-31 06:14:49 【问题描述】:

有没有办法在 android (Honeycomb) 中定义 ViewGroup 的剪辑区域?例如,我有一个带有圆角图像背景的 ListView。当我滚动浏览列表时,孩子们会伸出背景的角落——我希望他们夹在圆角内。

左图是它当前正在做的,右图是我想要的。

我在看ClipDrawable,不过好像只能用于进度条?

另外,我正在尝试在小部件中执行此操作。所以我不能使用自定义视图并覆盖 onDraw 进行遮罩。

谢谢!

【问题讨论】:

您找到解决方案了吗?我也试图在一个小部件中实现这一点。 【参考方案1】:

尝试将 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);

...并创建一个像这样的自定义可绘制对象,称为“圆角”,替换为 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() 覆盖中指定的边界,并且将根据您的“圆形”可绘制对象添加背景。

【讨论】:

永远不要在 onDraw 中实例化对象,这会导致延迟。 最初的问题是要求一些可以与 RemoteViews 一起使用的东西。【参考方案2】:

确保layout 具有圆角背景。

科特林

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

Java

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

【讨论】:

注意:需要 API 级别 21【参考方案3】:

使用overridden onDraw(Canvas canvas) 创建自定义布局

致电canvas.clipRect(0, 0, mCanvasWidth, mCanvasHeight);

这将剪切所有超出布局边界的视图。

别忘了在构造函数中调用setWillNotDraw(false),这样你的onDraw就会执行

【讨论】:

【参考方案4】:

这个怎么样:How to render an Android view to a bitmap,然后剪辑那个位图。

或者,另一个想法,使用FrameLayout,将您的剪辑蒙版堆叠在您的视图组之上。剪辑蒙版将具有透明的中间、不透明的边框。

在这两种情况下,我想处理用户输入会很棘手......

【讨论】:

第一个选项不起作用,因为它在一个小部件中,因此它只能使用与 RemoteViews 兼容的视图。 第二个选项,因为它是一个主屏幕小部件,所以剪辑蒙版不可行。【参考方案5】:
Path p = new Path()

// define your clipping path...

canvas.clipPath(p);

【讨论】:

【参考方案6】:

如果您查看WhatsUp,您可以看到在联系人图片中有一个被圆角边框环绕的图像。 为此,我将 ImageView 放在具有圆形边框的 FrameLayout(FrameLayout 因为我在图片前面使用 ProgressBar 来通知加载[实际上不可见])中。图片是方形的,但要对其进行细化,您需要使用画布。

再看看这个link,它将解决您的问题;)

【讨论】:

【参考方案7】:

也许你可以使用 Canvas.clipRegion 方法来剪辑到视图的差异。

【讨论】:

【参考方案8】:

要添加@Marco 的答案,您还可以提供自定义View.outlineProvider。我在使用 Google 较新的 MaterialCardView 时遇到了类似的问题。出于某种原因,该视图不会用圆角剪裁其子视图。子视图只会绘制在圆角的顶部。

科特林:

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)
            
        
    

【讨论】:

【参考方案9】:

试试 android:clipToPadding。它会解决你的问题。

【讨论】:

以上是关于Android 视图剪辑的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Xamarin Android 中剪辑滚动视图的边界

如何在android中剪辑圆圈

Android ScrollView 在旋转动画上丢失剪辑

Android实现一个progressBar,上面有两个剪辑textview

Android ListView scrollby 剪辑列表中的项目

在颤动中滚动列表视图时剪辑填充