RelativeLayout выравнивает родителя *side* + margin *side*

Я заметил странное поведение в RelativeLayout, когда вы выравниваете вид по стороне макета (любой стороне) и имеете большой запас в том же направлении.

У меня есть 2 RelativeLayouts, каждый из которых содержит простое представление. В одном макете этот вид выравнивается по верхнему и левому краю, в другом — по нижнему и правому краю:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <RelativeLayout 
        android:layout_width="150dp"
        android:layout_height="150dp"
        android:layout_marginTop="110dp"
        android:layout_gravity="center"
        android:background="#ff555555" >

        <View
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:layout_alignParentTop="true"
            android:layout_alignParentLeft="true"
            android:background="#aa8711" />     
    </RelativeLayout>

    <RelativeLayout 
        android:layout_width="150dp"
        android:layout_height="150dp"
        android:layout_marginBottom="110dp"
        android:layout_gravity="center"
        android:background="#ff555555" >

        <View
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:layout_alignParentBottom="true"
            android:layout_alignParentRight="true"
            android:background="#998877" />         
     </RelativeLayout>      
</FrameLayout>

Это выглядит так:

базовая настройка

Я добавил 130 dp поля в каждом направлении родительского выравнивания. Это означает, что вид должен быть виден в макете только частично. Вот что происходит:

130dp в каждом направлении выравнивания

Как видите, виды теперь меньше исходного размера, так как они отталкиваются от «стен» макета. Затем я попытался дать поле больше, чем макет, поэтому я дал им 151 dp поля в выровненных направлениях. Это выглядело так:

введите здесь описание изображения

Вид, выровненный по нижнему правому краю, теперь «вырывается» из макета и снова имеет тот же размер, что и был изначально. С другой стороны, представление, выровненное по верхнему левому краю, также имеет исходный размер, но полностью находится внутри макета, а не за его пределами.

Я пробовал это индивидуально и в каждой перестановке выравнивания и получил те же результаты.

Вопрос 1. Кто-нибудь может объяснить это непоследовательное поведение?

Я попробовал то же самое, на этот раз сравнив поведение с поведением FrameLayout. Начальная настройка:

введите здесь описание изображения

и после полей:

введите здесь описание изображения

FrameLayout постоянно сохраняет вид в исходном размере и просто позволяет виду "выйти" из него. Я попытался дать отрицательный запас в противоположном направлении, по крайней мере, размер представления, который должен быть за пределами RelativeLayout, и увидел то же поведение, что и в FrameLayout по умолчанию.

Вопрос 2. Кто-нибудь может объяснить разницу в поведении и противоположный отрицательный эффект маржи?


person Itai Hanski    schedule 11.09.2013    source источник


Ответы (1)


Почему он должен быть виден только частично?

Я добавил 130 dp поля в каждом направлении родительского выравнивания. Это означает, что вид должен быть виден только частично в макете.

Поле становится меньше, потому что предпочтение отдается тому, чтобы любой ценой сохранить его внутри родительского макета, сохраняя при этом поля. Поскольку меньшее дочернее представление имеет размер 50dp, вы добавили поле 130dp, общая ширина, которая ему нужна, составляет 180dp, но само родительское представление имеет ширину всего 150dp. То есть 130dp + 50dp > 150dp - дочерний элемент плюс поле не могут поместиться внутри родителя.

Это «глупый ввод», и интерпретатор XML делает все возможное, чтобы что-то отобразить. Решение, которое он принимает в конце, заключается в том, что он может изменить ширину дочернего блока и по-прежнему соблюдать ограничение поля. Или математически

130dp + 20dp == 150dp

По сути, он уменьшает ширину внутреннего блока с назначенного 50dp до 20dp, чтобы он мог поместиться внутри родителя с добавленным полем. И если вы посмотрите на размер квадрата, то 20dp выглядит примерно так. Он на 60% меньше.

Это разумное поведение интерпретатора, потому что по мере изменения размеров экрана и возникновения подобных проблем он всегда должен сохранять ограничение поля, противоположное ограничению ширины.

Таким образом, интерпретатор делает все возможное, чтобы подогнать блок и его поля внутри своего родителя, для этого он делает блок меньше. Он выбирает сохранение данного поля по заданной ширине - вероятно, из-за самого верхнего родительского макета.

Когда вы говорите «это должно быть частично видно», я предполагаю, что вы думаете, что дочерний элемент будет отображать половину внутри родительских границ, а половину - за пределами родительских границ, аналогично разработке форм Windows. Однако это не так, потому что в большинстве макетов он всегда будет пытаться удерживать детей внутри границ родителей.

Сделанный выбор также зависит от самого верхнего родительского макета, некоторые макеты могут предпочитать сохранять ширину дочернего блока, а не поля, или даже отображать блок за пределами родительских границ.


Во втором случае:

поэтому я дал им 151dp поля в выровненных направлениях.

Вы выходите за пределы точки, в которой интерпретатор может уменьшить изображение. Он не может уменьшить изображение до негатива 1. То есть

50dp + 151dp > 150dp

Он не может соответствовать этому ограничению маржи, которое вы ему дали, поэтому поведение довольно непредсказуемо. На первый взгляд, я бы сказал, что он знает, что не может хранить оба изображения вместе с их полями внутри родителя. Таким образом, он просто отображает один внутри и один снаружи.

Еще раз, это глупый ввод, и интерпретатор делает все возможное, чтобы отобразить то, что вы хотите.


Кто-нибудь может объяснить разницу в поведении и противоположный эффект отрицательной маржи?

Отрицательное поле будет делать разные вещи в зависимости от типа макета в его родительском элементе, а также от того, выровнено ли оно. В макете кадра он будет вести себя иначе, чем относительный макет. Обычно, если вы смотрите на негативные макеты, вы выбрали неправильный родительский контейнер и пытаетесь взломать его, чтобы он выглядел правильно.

Я не знаю, что именно вы пытаетесь сделать, но, возможно, вам просто нужно немного изменить свой мыслительный процесс и подумать о плохой интерпретации, пытающейся понять XML, который вы ему даете.

Вы не будете первым человеком, который будет совершенно сбит с толку XML-макетами Android. Вложение макетов внутри макетов всегда сбивает с толку, и поведение меняется в зависимости от ряда вещей, таких как поля, выравнивание, ширина и т. Д. Большинство людей, которых я знаю, просто возятся с этим, пока он не станет правильным, и пробуют разные типы макетов контейнеров, чтобы получить правильный дизайн. .

Короче говоря, избегайте игры с полями (например, flash или winforms) и играйте без типов макетов, чтобы получить вещи там, где вы хотите.

надеюсь, что это поможет, извините за tl; dr.

person FaddishWorm    schedule 23.12.2013
comment
Прежде всего спасибо за ответ. Я не думаю, что вы полностью понимаете. Меня не смущает система XML, она вполне интуитивно понятна. Я обнаружил, что FrameLayout ведет себя лучше, чем RelativeLayout. У меня есть анимация на основе макета, которую я использую для перемещения представлений (фактически перемещаю их, а не просто анимирую). Мне нужно иметь возможность перемещать их за пределы экрана или, возможно, за пределы контейнера, если точнее. Я просто хотел знать, есть ли причина для RelativeLayout сохранять вид внутри, когда я толкаю его наружу в одном направлении, но не в другом. Поля используются везде, это не глупый ввод - person Itai Hanski; 26.12.2013
comment
Вы никогда не должны убирать их с экрана, почему бы просто не скрыть их? Похоже, вы используете его как вспышку, или у вас есть фон во вспышке, и вы пытаетесь двигать вещи за пределами сцены? Расширенное движение и анимация должны быть выполнены в openGL. - person FaddishWorm; 27.12.2013