2015-01-08 3 views
2

Следующие два файла макета дают разные результаты:Asymmetric RelativeLayout в Android

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:orientation="vertical" 
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent" 
    android:gravity="center"> 
    <RelativeLayout 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:gravity="center"> 
    <View 
     android:id="@+id/box" 
     android:background="#ff0000" 
     android:layout_width="0dp" 
     android:layout_height="30dp" 
     android:layout_alignParentLeft="true" 
     android:layout_toLeftOf="@+id/next_box" /> 
    <View 
     android:id="@+id/next_box" 
     android:background="#0000ff" 
     android:layout_width="60dp" 
     android:layout_alignParentRight="true" 
     android:layout_height="30dp" 
     /> 
    </RelativeLayout> 
</LinearLayout> 

Результат: enter image description here

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:orientation="vertical" 
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent" 
    android:gravity="center"> 
    <RelativeLayout 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:gravity="center"> 
    <View 
     android:id="@+id/box" 
     android:background="#ff0000" 
     android:layout_width="0dp" 
     android:layout_height="30dp" 
     android:layout_alignParentLeft="true" 
     /> 
    <View 
     android:id="@+id/next_box" 
     android:background="#0000ff" 
     android:layout_width="60dp" 
     android:layout_alignParentRight="true" 
     android:layout_height="30dp" 
     android:layout_toRightOf="@+id/box" 
     /> 
    </RelativeLayout> 
</LinearLayout> 

Результат: enter image description here

Обе макеты пытаются описать те же ограничения. А именно, красный прямоугольник должен касаться левого края родителя, синий прямоугольник должен касаться правого края родителя, и они должны появляться рядом друг с другом по горизонтали. Единственное различие заключается в том, задаете ли вы ограничение «рядом» с красным прямоугольником или синим прямоугольником. Я выяснил причину, связанную с порядком разрешения измерения, созданным путем формирования графика зависимостей ограничений, но я только вычислил его, прочитав исходный код RelativeLayout, и я не смог найти никакой документации/заметок относительно этого поведения. Поскольку RelativeLayout должен быть обычно используемым компонентом компоновки, есть ли более интуитивное объяснение этого поведения или есть какая-то часть документации, которую я пропускаю?

+1

Вы установите 'layout_width' attri bute или first 'View' до 0. В первом случае' RelativeLayout' явно дает ему оставшуюся ширину, так как вы определили ее выравнивания влево и вправо. Во втором случае нет правильного выравнивания, поэтому это макет слева с шириной 0, а другой 'View' принимает всю доступную ширину, поскольку она явно определена для выравнивания с правой границей первого' View '. – corsair992

ответ

4

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

В первом случае красная коробка зависит от синего квадрата, поэтому сначала формируется синяя коробка. Синяя коробка имеет ширину 60dp, поэтому синий квадрат 60dp строится первым и выравнивается вправо. Затем появляется красная рамка, которая имеет ограничение, чтобы сидеть рядом с синей рамкой. Ширина 0 игнорируется, потому что она должна сидеть рядом с синим цветом 60dp и выравнивать влево.

Во втором случае синий ящик зависит от красного квадрата, поэтому сначала создается красный квадрат. Красная рамка говорит, что она хочет 0dp и выравнивается влево, поэтому ее не видно. Затем появляется синий ящик, который должен сидеть рядом с невидимым красным и выравнивать вправо, тем самым занимая все пространство, его ширина игнорируется.

Надеется, что это имеет смысл :)

+0

Спасибо за разъяснение, и, как я сказал в последнем абзаце, я знаю разницу, но я не думаю, что он был документально зарегистрирован в документации на Android, что может быть довольно запутанным. Является ли это просто понятным для сообщества Android? – dementrock

+0

@dementrock: Что нужно документировать? Ограничения ведут себя точно так, как определено, и единственным способом это может иметь смысл. – corsair992

+0

Я думаю, что документации для Android и ее причуд никогда не хватит. Я быстро просмотрел документацию RelativeLayout и нашел, что это слишком коротко. Было бы хорошо, если бы вы могли читать больше. Для меня использование RelativeLayout - это немного проб и ошибок и использование вашей интуиции, чтобы определить, почему она ведет себя так, как она есть. – ekcr1

1

Всех эти параметры, определенные в: android.widget.RelativeLayout

private void applyHorizontalSizeRules(LayoutParams childParams, int myWidth, int[] rules) { 
    RelativeLayout.LayoutParams anchorParams; 

    // VALUE_NOT_SET indicates a "soft requirement" in that direction. For example: 
    // left=10, right=VALUE_NOT_SET means the view must start at 10, but can go as far as it 
    // wants to the right 
    // left=VALUE_NOT_SET, right=10 means the view must end at 10, but can go as far as it 
    // wants to the left 
    // left=10, right=20 means the left and right ends are both fixed 
    childParams.mLeft = VALUE_NOT_SET; 
    childParams.mRight = VALUE_NOT_SET; 

    anchorParams = getRelatedViewParams(rules, LEFT_OF); 
    if (anchorParams != null) { 
     childParams.mRight = anchorParams.mLeft - (anchorParams.leftMargin + 
       childParams.rightMargin); 
    } else if (childParams.alignWithParent && rules[LEFT_OF] != 0) { 
     if (myWidth >= 0) { 
      childParams.mRight = myWidth - mPaddingRight - childParams.rightMargin; 
     } 
    } 

    anchorParams = getRelatedViewParams(rules, RIGHT_OF); 
    if (anchorParams != null) { 
     childParams.mLeft = anchorParams.mRight + (anchorParams.rightMargin + 
       childParams.leftMargin); 
    } else if (childParams.alignWithParent && rules[RIGHT_OF] != 0) { 
     childParams.mLeft = mPaddingLeft + childParams.leftMargin; 
    } 

    anchorParams = getRelatedViewParams(rules, ALIGN_LEFT); 
    if (anchorParams != null) { 
     childParams.mLeft = anchorParams.mLeft + childParams.leftMargin; 
    } else if (childParams.alignWithParent && rules[ALIGN_LEFT] != 0) { 
     childParams.mLeft = mPaddingLeft + childParams.leftMargin; 
    } 

    anchorParams = getRelatedViewParams(rules, ALIGN_RIGHT); 
    if (anchorParams != null) { 
     childParams.mRight = anchorParams.mRight - childParams.rightMargin; 
    } else if (childParams.alignWithParent && rules[ALIGN_RIGHT] != 0) { 
     if (myWidth >= 0) { 
      childParams.mRight = myWidth - mPaddingRight - childParams.rightMargin; 
     } 
    } 

    if (0 != rules[ALIGN_PARENT_LEFT]) { 
     childParams.mLeft = mPaddingLeft + childParams.leftMargin; 
    } 

    if (0 != rules[ALIGN_PARENT_RIGHT]) { 
     if (myWidth >= 0) { 
      childParams.mRight = myWidth - mPaddingRight - childParams.rightMargin; 
     } 
    } 
} 

Вид левых и правый края (childParams.mLeft, childParams.mRight) расчеты, основанные на параметрах просмотра якорных (anchorParams). Из этого кода childParams.mRight край представления, определенного LEFT_OF (android: layout_toLeftOf), может быть пересчитан ALIGN_RIGHT (android: layout_alignRight) или ALIGN_PARENT_RIGHT (android: layout_alignParentRight). Вот объяснение, почему 0 ширина красный вид становится более 0.

<View 
     android:id="@+id/box" 
     android:background="#ff0000" 
     android:layout_width="0dp" 
     android:layout_height="30dp" 
     android:layout_alignParentLeft="true" 
     android:layout_toLeftOf="@+id/next_box"/> 

правый край этой точки зрения, определяемой LEFT_OF:

childParams.mRight = anchorParams.mLeft - (anchorParams.leftMargin + 
        childParams.rightMargin); 

В этом случае ввиду анкера:

<View 
     android:id="@+id/next_box" 
     android:background="#0000ff" 
     android:layout_width="60dp" 
     android:layout_alignParentRight="true" 
     android:layout_height="30dp" 
     /> 

левый край этого вида 60dp с правой стороны экрана не определен => childParams.mRight = screen_width - 60dp

левый край этой точки зрения, определяемой ALIGN_PARENT_LEFT:

childParams.mLeft = mPaddingLeft + childParams.leftMargin; 

левый край этой точки зрения левого края зрения Анкер 0, потому что андроид: layout_alignParentLeft = «истина» и поля не определен => childParams.mLeft = 0

такой же расчет можно сделать для второго примера: childParams.mRight = screen_width childParams.mLeft = 0