相对布局对齐父容器的*侧面* + 边距*侧面*。

19

我注意到当你把一个视图与布局的边缘(任意一侧)对齐并且在同一方向上有很大的边距时,RelativeLayout存在奇怪的行为。

我有两个 RelativeLayout,每个包含一个简单的视图。在一个布局中,该视图与顶部和左侧对齐,在另一个布局中,该视图与底部和右侧对齐:

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

它看起来像这样:

basic setup

我在父对齐的每个方向上添加了130dp的边距。这意味着视图应该只在布局中部分可见。结果如下:

130dp in each direction of alignment

正如你所看到的,视图现在比原始大小更小,因为它们被推到了布局的“墙”上。接下来,我尝试给一个比布局大的边距,所以我在对齐方向上给它们151dp的边距。结果如下:

enter image description here

底部右对齐的视图现在“突破”了布局,又恢复成了原来的大小。另一方面,左上角对齐的视图也是原来的大小,但完全在布局内而不是外部。

我已经尝试过这种情况,并且按照每种对齐方式的每种排列组合都得到了相同的结果。

问题1:有人能解释这种不一致的行为吗?

我尝试了同样的方法,这次将行为与FrameLayout进行比较。

初始设置:

enter image description here

添加边距后:

enter image description here

FrameLayout始终保持视图的原始大小,并允许视图“退出”。我尝试在至少应该超出RelativeLayout的视图大小的相反方向上给出负边距,并看到了与默认情况下FrameLayout中发生的相同行为。

问题2:有人能解释行为上的差异和相反的负边距效果吗?

1个回答

3
为什么它只能部分可见?
引用:
我在父元素对齐的每个方向上添加了130dp的边距。这意味着在布局中,视图应该只能部分可见。
盒子变小是因为优先考虑将其保留在父布局内,同时仍然应用边距。由于较小的子视图为50dp,您已添加了130dp的边距,它需要的总宽度为180dp,但父视图本身只有150dp宽。即130dp + 50dp>150dp——子元素加上边距无法适应父元素。
这是“愚蠢的输入”,XML解释器正在尽力呈现某些内容。它最终做出的决定是可以更改子框的宽度并仍然遵守边距约束。或者在数学上
130dp + 20dp == 150dp

基本上,它将内部盒子的宽度从指定的50dp缩小到20dp,以便其带有添加的边距适合父级。如果您查看正方形的大小,20dp看起来非常合适。它小了60%。
这是解释器的巧妙行为,因为随着屏幕尺寸的变化,它遇到像这样的问题时,应始终保留边距约束而不是宽度约束。
总之,解释器正在尽力适应框和其边距在其父级内部,为此它正在使框变小。它选择保留给定的边距,而不是给定的宽度-可能是因为最上层的父级布局。
当您说“这应该部分可见”时,我认为您认为子元素将呈现一半位于父级范围内,另一半位于父级范围外,类似于窗体开发。但实际情况并非如此,因为在大多数布局中,它将始终尝试将子元素保持在父元素的范围内。
所做出的选择也取决于最上层的父级布局,某些布局可能更喜欢保留子框的宽度而不是边距,甚至在父级范围之外呈现框。
在第二种情况下:

所以我在对齐方向上给了他们151dp的边距。

您超出了解释器可以缩小图像的点。它不能将图像缩小到负1。
50dp + 151dp > 150dp

它无法满足您给出的边距限制,因此行为相当不可预测。我猜它知道无法同时保留图像及其边距在父元素内部。因此,它只是在内部呈现一个图像,在外部呈现另一个图像。

再次说明,这是愚蠢的输入,解释器正在尽力呈现您想要的结果。


有人能解释一下行为差异和相反的负边距效果吗?

负边距会根据其所在父容器的布局类型以及对齐方式而产生不同的效果。在框架布局中,它的行为将与相对布局不同。通常,如果您正在查看负布局,则选择了错误的父容器,并且您正在尝试通过黑客方式使其看起来正确。

我不知道您究竟想做什么,但也许您只需要稍微调整一下思维方式,考虑一下试图理解您给出的XML的可怜解释器。

您不会是第一个被Android的XML布局彻底搞糊涂的人。在布局内嵌布局总是很令人困惑的,行为会因边距、对齐方式、宽度等多种因素而发生变化。我认识的大多数人只是不断地尝试,直到它正确,并尝试不同的容器布局类型以获得正确的设计。

简而言之,避免使用边距(如Flash或WinForms),而是使用布局类型来将元素放置在您想要的位置。

希望这有所帮助,抱歉有点长。


首先感谢您的回答。我认为您并没有完全理解我的问题。我对XML系统并不困惑,它相当直观。我发现FrameLayoutRelativeLayout更好用。我有一个基于布局的动画,用来移动视图(实际上是移动而不仅仅是动画)。我需要能够将它们“移出屏幕”,或者说“移出容器”更为准确。我只想知道为什么 RelativeLayout会在一个方向上将视图推到外面,但在另一个方向上却不会。边距在各个地方都被使用,这并不是“愚蠢”的输入。 - Itai Hanski
你不应该将它们“移出屏幕”,为什么不直接隐藏它们呢?听起来你是在有点像使用flash,或者你有flash的背景并试图将东西动态衔接到舞台之外?高级运动和动画应该使用openGL来完成。 - ddoor

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