2015-01-08 46 views
2

以下兩個佈局文件產生不同的結果:不對稱RelativeLayout的行爲

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

兩個佈局試圖描述相同的限制。也就是說,紅色矩形應觸摸父項的左邊緣,藍色矩形應該觸摸父項的右邊緣,並且它們應該水平相鄰。唯一的區別是您是否在紅色矩形或藍色矩形上指定了「next to」約束。我找出了與通過形成約束的依賴圖生成的度量解析順序有關的原因,但我只是通過閱讀RelativeLayout的源代碼來計算出來的,並且我找不到有關此行爲的任何文檔/註釋。由於RelativeLayout必須是常用的佈局組件,對此行爲是否有更直觀的解釋,或者是否存在我缺少的某些文檔部分?

+1

您已設置'layout_width' attri bute或第一個「視圖」爲0.在第一種情況下,「RelativeLayout」明確地給出了剩餘寬度,因爲您已經定義了它的左右對齊。在第二種情況下,沒有定義右對齊,因此左邊的佈局爲0寬度,另一個「視圖」佔用所有可用寬度,因爲它明確定義爲與第一個「視圖」的右邊界對齊'。 – 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)。從這個代碼可以通過ALIGN_RIGHT(android:layout_alignRight)或ALIGN_PARENT_RIGHT(android:layout_alignParentRight)重新計算由LEFT_OF(android:layout_toLeftOf)定義的視圖的childParams.mRight邊緣。下面是解釋爲什麼0寬度紅色視圖成爲LEFT_OF限定的本視圖的大於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"/> 

右邊緣:

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

相關問題