在Android中定义RelativeLayout视图的Z顺序

239

我希望定义Android RelativeLayout中各视图的z顺序。

我知道一种方法是调用bringToFront函数。

是否有更好的方法可以在布局XML中定义z顺序呢?这将会很方便。


4
View.bringToFront(); 的意思是将该视图置于最前方。 - Shirish Herwade
13个回答

327

最简单的方法就是注意将视图(Views)添加到XML文件中的顺序。在文件底部添加的视图将会在Z轴上处于更高的位置。

编辑: 这个文档在Android开发者网站这里这里有记录。(感谢@flightplanner)


16
很不幸,有时候无法更改。例如,在相对布局中,每个元素只能与文件中先前定义的元素相关联来进行布局。 - Casebash
69
Casebash,我不认为那一定是这样的,你只需要使用"@+id/your_element_before_its_defined",然后在稍后定义的元素中使用相同的ID即可。我可能对此有所错误,这些布局对我来说很棘手,但我肯定有这种印象,它可以工作。 - tjb
7
"Tjb是正确的(我很高兴他是对的)。在第一次提到ID时使用@+id,例如layout_above="@+id/some_id"。" - Michiel
3
您还可以将 <item type="id" name="<your_id>"/> 放入 values xml 文件中,就可以在任何地方引用它。 - karl
8
我知道我已经晚了大约3年才来参加这个派对,但是回答@hpique的问题,这里有相关文档链接 - HexAndBugs
显示剩余6条评论

91

如果您想在代码中执行此操作,您可以这样做

View.bringToFront();

请参阅 文档


80
请注意,API 21及以上版本的按钮和其他元素都具有较高的高度,并且无论父布局如何,它们都会忽略元素的xml顺序。我花了一些时间才弄清楚这一点。

19
对我而言,解决这个 bug 的方法是在我想要渲染在按钮之上的视图上调用 setElevation(1000)。 - fire in the hole
1
setElevation() 需要 API 级别 21。 - dp2050
在一个Button后定义了TextView,它们在预览渲染中位于下方。通过添加“tools:elevation="10dp"”进行修复。请注意,这里使用了Tools命名空间,因为显然设备上没有问题。如果需要,可以随时切换到Android命名空间。 - Slion

27

从API 21开始,在Android中,布局文件中的项根据它们在文件中的顺序(如正确答案所述)和它们的高度获得它们的Z顺序,更高的高度值意味着该项获得更高的Z顺序。这有时会导致问题,特别是对于按照XML顺序应该在其下方的项目上经常显示在按钮上的情况。要解决此问题,只需将布局XML中的项目的android:elevation设置为您想要实现的Z顺序。

如果您设置了布局中元素的高度,则会开始投射阴影。如果您不希望出现此效果,则可以使用以下代码删除阴影:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
   myView.setOutlineProvider(null);
}

我还没有找到任何一种方法可以通过布局xml去除高程视图的阴影。


1
如评论中所述,您可以使用 android:elevation="1000dp"。这样就不会渲染阴影了。 - Vadim Kotov
在XML中使用android:outlineProvider="none" - Francis

16
请注意,从API 21开始,您可以使用view.setZ(float)。在这里,您可以找到更多信息。

16

我遇到了相同的问题:在一个相对布局的parentView中,我有两个子视图childView1和childView2。一开始,我将childView1放在childView2上面,并且我想让childView1在childView2的顶部。改变子视图的顺序并不能解决我的问题。对我有用的是在parentView上设置android:clipChildren="false",并在代码中设置:

childView1.bringToFront();

parentView.invalidate();

3
这段话的意思是:child.bringToFront()parent.invalidate() 一起使用可以实现某项功能,但是 parent.bringChildToFront(child) 不能。这让我感到非常沮丧,因为我们都期望操作系统有逻辑性。 - Oliver Hausler
为了给一些视图添加动画效果(在X和Y方向上的平移),我尝试了多种LinearLayout、FrameLayout和RelativeLayout的组合,但总是会出现问题(与重叠或不成比例的大小有关)。最终,android:clipChildren="false"解决了问题。谢谢! - JCarlosR

16

由于 XML 字段

android:translationZ

的介绍使得情况有了一些变化,所以我想补充一个回答。其他回答建议运行...

childView1.bringToFront();

parentView.invalidate();

除了这段代码无法将带有硬编码android:translationZ的视图放在childView1前面外,你的所有观点都是完全正确的。我遇到了这个问题,一旦我从其他视图中删除了这个字段,bringToFront()就可以正常工作。


对于Android 5中的“elevation”来说,这同样适用。 - shelll

7

API 21内置了view.setElevation(float)

为了向后兼容,使用ViewCompat.setElevation(view, float);

更多方法包括ViewCompat.setZ(v, pixels)ViewCompat.setTranslationZ(v, pixels)

另一种方法是收集按钮或视图数组并使用addView添加到RelativeLayout中


5

1
你可以使用自定义的RelativeLayout并重新定义其protected int getChildDrawingOrder (int childCount, int i)方法。
请注意,此方法将参数i作为“我应该绘制第几个视图”。这是ViewPager的工作方式。它与PageTransformer一起设置自定义绘制顺序。

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