clipChildren не работает, даже если установлено значение false?

В моем приложении я пытаюсь перемещать изображения с помощью анимации. Когда я пытаюсь анимировать изображение, оно обрезается, хотя я использую clipChildren false в каждом блоке xml.

    <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" >

person Vamshi    schedule 08.04.2014    source источник
comment
Для тех, кто ищет здесь, пожалуйста, обратите внимание, что roflharrison решил проблему, НО есть ошибка в примере кода, приведенном roflharrison. Правильный код: stackoverflow.com/a/53654808/294884   -  person Fattie    schedule 14.04.2021


Ответы (6)


Один из родителей вашего 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());
    }
}
person roflharrison    schedule 08.04.2014
comment
Мне помогло, спасибо за ответ! По-видимому, некоторые представления добавляются, когда вы включаете макет, и это вызывало у меня проблему. - person shalafi; 06.08.2014
comment
ОБНОВЛЕНИЕ: я использовал библиотеку поддержки 21.0.3. обновление до 22.0.0 решило эту проблему для меня! - person Sam; 02.04.2015
comment
Это сработало для меня. Но получаю одну проблему. Условие: предположим, что у ListView_1 есть родитель RelativeLayout_1. ListView_1 является родителем RelativeLayout_2. Родитель RelativeLayout_2 для ImageView_1. Мне нужно анимировать дочерний ImageView_1 и переместить его за пределы родительского, чем я использовал ваши методы. Это работало нормально, но при прокрутке списка ListView_1 также натыкается на RelativeLayout_1. Можно ли применить отсечение только для одного ребенка? - person Shanki Bansal; 20.05.2015
comment
для будущих читателей: программная настройка может не работать для анимации представлений, которые оставляют фрагмент диалога на устройствах Android 4.x. Но установка clipChildren и clipToPadding для всех ViewGroup через XML + аннулирование fragment root view в событии onAnimationUpdate делают свое дело. По каким-то причинам, которых я действительно не понимаю, программная настройка параметров клипа + отключение корневого просмотра на устройствах 4x does not work. На устройствах 5x он работает без XML и аннулирования вручную. - person ashakirov; 19.01.2016
comment
Работал для меня !! Просто интересно, это очевидная вещь, которую нужно знать? (Поскольку я не знал об этом, придя сюда :-/) - person Yash; 12.05.2017
comment
Не очевидно, что система оборачивает ваши представления во вспомогательные ViewGroup. Если вы хотите увидеть его в действии, откройте Layout Inspector для случая, когда вы столкнулись с тем, что clipChildren="false" не работает, и вы, вероятно, найдете таинственную ViewGroup в своей иерархии. - person roflharrison; 22.05.2017
comment
@roflharrison большое спасибо за решение, НО в вашем коде есть две незначительные ошибки, которые в некоторых случаях мешают ему работать. Ответ KehuiLi показывает проблему и исправление. - person Fattie; 14.04.2021

Я знаю, что уже поздно, но это самый простой полный ответ:

просто наденьте каждый макет:

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

Обратите внимание, что @roflharrison упоминается: это не будет работать в тех случаях, когда операционная система упаковывает/внедряет ваше представление в ViewGroup, которое не не в вашем макете

person mhdjazmati    schedule 24.01.2017
comment
Как объяснено в моем ответе, это не будет работать в тех случаях, когда операционная система упаковывает/вводит ваше представление в ViewGroup, которого нет в вашем макете. - person roflharrison; 22.05.2017
comment
Да это правда - person mhdjazmati; 22.05.2017

Последняя причина — «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>
person Xavier.S    schedule 29.01.2016

Идея @roflharrison довольно хороша, однако в коде есть некоторая проблема: здесь мы рекурсивно отключаем clipChildren, но когда мы доходим до корневого представления, v.getParents() будет нулевым, метод возвращается немедленно, а его атрибут 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());
}
person Kehui Li    schedule 06.12.2018
comment
ПРАВИЛЬНЫЙ ОТВЕТ СПАСИБО!! - person Fattie; 14.04.2021
comment
Обратите внимание, что вы также можете установить setClipToPadding(false) . - person Fattie; 14.04.2021

Привет~ если ваш макет содержит теги "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">

код выше будет обрезать childView, а следующий - нет:

<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">
person Yun.Lu    schedule 30.09.2016

В моем случае clipChildren=false не сработало, потому что я также установил clipToOutline = true для родителя в своем коде. Этот атрибут приводит к тому, что дочерние элементы обрезаются в контуре родителя, который в моем случае был контуром фона родителя. Похоже, clipToOutline имеет более высокий приоритет, чем clipChildren=false.

Если clipChildren=false у вас не работает, убедитесь, что в коде не установлено clipToOutline=true.

person Milszym    schedule 23.02.2021