即使设置为false,clipChildren仍然无效?

36
在我的应用程序中,我试图使用动画移动图像。尽管在每个XML块中都使用了clipChildren false,但我仍然发现图片被切割了。
    <RelativeLayout
        android:id="@+id/baselayout"
        android:layout_width="match_parent"
        android:layout_height="120dp"
        android:layout_alignParentRight="true"
        android:layout_below="@+id/imageView1"
        android:clipChildren="false"
        android:clipToPadding="false" >

对于任何在这里搜索的人,请注意roflharrison已经解决了问题,但是roflharrison提供的代码示例中存在错误。正确的代码:https://dev59.com/f2Ag5IYBdhLWcg3w_vSF#53654808 - Fattie
6个回答

38

你的RelativeLayout的父视图可能会剪裁子视图(有时兼容库会添加神秘的ViewGroup,例如NoSaveStateFrameLayout)。我过去曾经成功地使用类似以下代码来禁用一个视图的所有父视图的剪裁功能:

public void disableClipOnParents(View v) {
    if (v.getParent() == null) {
        return;
    }

    if (v instanceof ViewGroup) {
        ((ViewGroup) v).setClipChildren(false);
    }

    if (v.getParent() instanceof View) {
        disableClipOnParents((View) v.getParent());
    }
}

1
它对我有用,感谢答案!显然,当您包含布局时,会添加一些视图,这对我造成了问题。 - shalafi
2
更新:我之前使用的是支持库21.0.3,升级到22.0.0后问题得到解决! - Sam
它对我起作用了。但是出现了一个问题。 条件是:假设RelativeLayout_1是ListView_1的父级。ListView_1是RelativeLayout_2的父级。RelativeLayout_2是ImageView_1的父级。 我需要动画化子元素“ImageView_1”并将其移动到父级之外,然后我使用了您的方法。它运行良好,但在滚动列表时,ListView_1也会覆盖RelativeLayout_1。 是否可能仅为一个子元素应用剪辑? - Shanki Bansal
对我有用!!只是想知道这是否是一个显而易见的事情?(因为我来之前不知道这个 :-/ ) - Yash
2
系统将您的视图包装到辅助ViewGroup中并不明显。如果您想看到它的效果,请打开布局检查器,找到一个clipChildren="false"无法正常工作的情况,并且您可能会在层次结构中发现一个神秘的ViewGroup。 - roflharrison
显示剩余2条评论

22

我知道现在已经很晚了,但这是最简单完整的答案:

只需在每个布局中加入:

    android:clipChildren="false"
    android:clipToPadding="false"

注意@roflharrison提到: 在操作系统包装/注入您的视图到不在您的布局中的ViewGroup的情况下,这种方法将无法工作。


2
正如我在答案中所解释的那样,在操作系统将您的视图包装/注入到不在您的布局中的ViewGroup的情况下,这种方法是行不通的。 - roflharrison
是的,那是真的。 - mhdjazmati

11

最后一个原因是"RelativeLayout"。为了解决这个问题,不要使用RelativeLayout作为超出父元素的控件的父元素,而应该使用FrameLayout,例如:

<!-- it's ok as grand parent -->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:clipChildren="false">

    <!-- parent must not be a RelativeLayout -->
    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="38dp"
        android:layout_alignParentBottom="true"
        android:layout_marginBottom="9dp">

        <!-- Your Larger-than-parent View -->
        <View
            android:layout_width="56dp"
            android:layout_height="138dp"
            android:layout_gravity="center"
            android:background="@android:color/black" />

    </FrameLayout>

</RelativeLayout>

6

@roflharrison的想法很好,但是代码存在一些问题:

在这里我们递归地禁用clipChildren,但是当我们到达根视图时,它的v.getParents()将为null,该方法会立即返回,并且其ClipChildren属性不会被禁用。

此外,对于以下行:

if (v.getParent() instanceof View)

父视图不应该是ViewGroup吗?我们不应该禁用ViewGroup的剪辑属性,而不是View的吗?所以我将代码更改为以下内容,它运行得非常好:

public void disableClipOnParents(View v) {
    if (v == null) {
        return;
    }
    if (v instanceof ViewGroup) {
        ((ViewGroup) v).setClipChildren(false);
    }
    disableClipOnParents((View) v.getParent());
}

请提供正确的回答,谢谢! - Fattie
1
注意,您可能还希望设置 setClipToPadding(false) - Fattie
这也不适用于所有设备。在将其转换为“View”之前,您应该检查v.getParent() instanceof View。否则,您可能会遇到“ClassCastException:android.view.ViewRootImpl无法转换为android.view.View”或类似情况。有多种情况可能会发生这种情况(请参见搜索结果)。 - Michal Vician

1

嗨~如果你的布局包含"paddingXXX"标签,你可以将它们移除并重试。这对我很有效~

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:clipChildren="false"
    android:gravity="center_vertical"
    android:padding="8dp"
    android:orientation="horizontal">

上面的代码将剪切子视图,下面的代码则不会:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:clipChildren="false"
    android:gravity="center_vertical"
    android:orientation="horizontal">

0
在我的情况下,clipChildren=false 没有起作用,因为我在代码中还设置了父级的 clipToOutline=true。这个属性会导致子元素被剪裁在父元素的轮廓线内,而在我的情况下,父元素的轮廓线是父元素背景的轮廓。看起来 clipToOutline 的优先级高于 clipChildren=false
如果 clipChildren=false 对你不起作用,请确保你的代码中没有设置 clipToOutline=true

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