如何将视图置于所有内容的前面?

170

我有一个活动和很多小部件,其中一些有动画效果,因为这些动画效果,一些小部件会移动(平移)到另一个小部件的上面。例如,文本视图会移动到某些按钮上面……

现在的问题是,我希望按钮始终处于最前面。当文本视图移动时,我希望它在按钮的后面。

我无法实现这个功能,尝试了我所知道的所有方法,“bringToFront()”肯定行不通。

请注意,我不想通过布局中元素的放置顺序来控制z-order,因为我根本做不到:),布局很复杂,我无法将所有按钮都放在布局的开头。


4
我使用了一个RelativeLayout,并在XML中将“顶部”视图放在最后。请参见https://dev59.com/7HLYa4cB1Zd3GeqPYHhc#31340762。 - Ferran Maylinch
请问有人可以告诉我“bringToFront”的XML对应代码吗? - Shirish Herwade
3
请尝试在xml中将底部视图(bottomView)的elevation设置为1dp,将顶部视图(topView)的elevation设置为2dp || 使用ViewCompat.setElevation(View, int)方法。 - Tlacaelel Ramon Luis
19个回答

169
你可以在想要前置的视图上调用 bringToFront() 方法。
这是一个示例:
    yourView.bringToFront();

5
意外结果:我在垂直线性布局中使用了它,并且置于前面的视图出现在底部...例如,我有 A / B / C 并想将 A 置于前面,所以运行 a.bringToFront() 后,我的布局变成了 B / C / A - Ferran Maylinch
2
所以我发现LinearLayout不能与bringToFront一起使用。我最终使用了RelativeLayout。请参见我在问题本身上的评论。 - Ferran Maylinch
1
请问有人可以告诉我“bringToFront”的XML对应代码吗? - Shirish Herwade
这会导致我移动的元素重新定位到前面,无论出于什么原因。另一方面,ViewCompat.setTranslationZ(view, 1) 却完美地工作。 - Bimde
1
如果我在Activity中的manifest中使用android:theme="@android:style/Theme.Light.NoTitleBar",那么yourView.bringToFront();将完美运行,但是如果我使用了android:theme="@android:style/Theme.AppCompat.Light.NoActionBar",yourView.bringToFront();就会无效。对此有什么线索吗? - Rahul
显示剩余2条评论

87

使用此XML代码

 android:translationZ="90dp"

5
“90dp”这个单位从哪里来的? - Sudhir Singh Khanger
1
这是手动输入。您可以根据需要尝试使用45dp或135dp或180dp或270dp。 - Krishna
1
你不能只使用1dp吗? - Tyler Turnbull
5
所需 API 版本为 21 或更高。 - Muhammad Saqib
2
translationZ值(90dp)将添加到android:elevation提供的值中。因此,translationZ + elevation将决定顺序。总和最高的视图将位于最前面。其次是其后面的下一个最高视图,依此类推。 - Namitha Reval

54

我一直在Stack Overflow上寻找一个好的答案,当我找不到时,我去查阅了文档。

似乎还没有人碰巧找到这个简单的答案:

ViewCompat.setTranslationZ(view, translationZ);

默认翻译 z 为 0.0


这是元素在Z轴上的位置,以像素为单位,也称为高度。setTranslationX将沿着X轴(左/右)移动视图,setTranslationY将沿着Y轴(上/下)移动视图。 Z轴是第三个轴。 - xdevs23
setZ() 呢?如果我没记错的话,视图的 Z 位置实际上是其高度和 Z 轴平移量之和。 - Gensoukyou1337
2
@Gensoukyou1337,然后ViewCompat.setZ(view, yourValueInPixels);view.setZ()仅适用于API 21及更高版本。 - Johnny Five
1
在Android Studio中检查了Java 8代码 - 它只检查SDK_INT是否> = 21,因此对于<21的API没有影响。 - Vadim

45

一个更简单的解决方案是编辑活动的XML。使用

android:translationZ=""

6
只有在Android API 21或以上版本中才有用。 - isakbob

26

bringToFront() 是正确的方法,但是,请注意必须在您根视图下最高级别的视图上调用 bringToFront()invalidate() 方法,例如:

您的视图层次结构如下:

-RelativeLayout
|--LinearLayout1
|------Button1
|------Button2
|------Button3
|--ImageView
|--LinearLayout2
|------Button4
|------Button5
|------Button6
所以,当你将按钮(1-6)还原为动画时,你的按钮会在ImageView下方。要将其置于ImageView上方,你必须在LinearLayout上调用bringToFront()invalidate()方法。然后它就可以工作了 :) **注意:记得为你的根布局或动画视图的祖先布局设置android:clipChildren="false"。让我们看一下我的实际代码:

.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:hw="http://schemas.android.com/apk/res-auto"
    android:id="@+id/layout_parent"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/common_theme_color"
    android:orientation="vertical" >

    <com.binh.helloworld.customviews.HWActionBar
        android:id="@+id/action_bar"
        android:layout_width="match_parent"
        android:layout_height="@dimen/dimen_actionbar_height"
        android:layout_alignParentTop="true"
        hw:titleText="@string/app_name" >
    </com.binh.helloworld.customviews.HWActionBar>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@id/action_bar"
        android:clipChildren="false" >

        <LinearLayout
            android:id="@+id/layout_top"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentTop="true"
            android:gravity="center_horizontal"
            android:orientation="horizontal" >
        </LinearLayout>

        <ImageView
            android:id="@+id/imgv_main"
            android:layout_width="@dimen/common_imgv_height"
            android:layout_height="@dimen/common_imgv_height"
            android:layout_centerInParent="true"
            android:contentDescription="@string/app_name"
            android:src="@drawable/ic_launcher" />

        <LinearLayout
            android:id="@+id/layout_bottom"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:gravity="center_horizontal"
            android:orientation="horizontal" >
        </LinearLayout>
    </RelativeLayout>

</RelativeLayout>

一些在 .java 文件中的代码

private LinearLayout layoutTop, layoutBottom;
...
layoutTop = (LinearLayout) rootView.findViewById(R.id.layout_top);
layoutBottom = (LinearLayout) rootView.findViewById(R.id.layout_bottom);
...
//when animate back
//dragedView is my layoutTop's child view (i added programmatically) (like buttons in above example) 
dragedView.setVisibility(View.GONE);
layoutTop.bringToFront();
layoutTop.invalidate();
dragedView.startAnimation(animation); // TranslateAnimation
dragedView.setVisibility(View.VISIBLE);

祝你好运!


如果您只想将按钮6置于ImageView上方而不是其他按钮,该怎么办? - Adam Katz
@AdamKatz:我认为你必须先将它们重新组织到另一个层次,然后按照你的方式进行。 - Justin
谢谢,我正在尝试将 RecyclerView 中的一个项目置于视图之上,但保留其他项目在其下方,目前遇到了困难! - Adam Katz
我使用了相同的方法。它可以正常工作,但有一个问题是它隐藏了工具栏。 - user2980181
这个能处理多层级吗?比如我有一个包含RelativeLayout和另一个RelativeLayout的ConstraintLayout,两者都与其根ConstraintLayout(match_parent)大小相同。第一个RelativeLayout有一个Button,并且在z-order方面也在第二个RelativeLayout后面。我可以使用View :: bringToFront()使第一个RelativeLayout中的Button看起来像是在所有内容的顶部,以便它可见且可点击吗? - oaskamay

20

如果您正在使用ConstraintLayout,只需将该元素放在其他元素之后即可使其位于其他元素的前面。


1
编程上的方法是什么? - Wajid

18

请尝试使用 FrameLayout,它可以让你把视图放在彼此之上。你可以创建两个 LinearLayouts,一个放置背景视图,另一个放置前景视图,然后使用 FrameLayout 来组合它们。希望这有帮助。


1
我们如何将它置于顶部,就像对话框一样? - Gaurav Arora
@Infinity,你可以创建一个FragmentDialog来实现这个目的,或者只需为你的Activity使用Theme.Dialog。 - Egor
我无法使用FragmentDialog,因为它与API 10不兼容。其次,我已经为我的应用程序使用了一个主题。还有其他方法吗?我已经像你说的那样使用了FrameLayout! - Gaurav Arora
@Infinity,您可以使用兼容库版本的FragmentDialog,该版本可从API 4中获得。 - Egor

6
我面临过同样的问题。 以下解决方案对我有用。
 FrameLayout glFrame=(FrameLayout) findViewById(R.id.animatedView);
        glFrame.addView(yourView);
        glFrame.bringToFront();
        glFrame.invalidate();

第二种解决方案是通过在视图 XML 中添加此属性来实现。
android:translationZ=""

5

3

可能还有另一种方法可以拯救情况。只需使用所需的布局初始化一个新的对话框,然后显示它即可。我需要将加载视图显示在DialogFragment上,这是我成功的唯一方法。

Dialog topDialog = new Dialog(this, android.R.style.Theme_Translucent_NoTitleBar);
topDialog.setContentView(R.layout.dialog_top);
topDialog.show();

bringToFront()在某些情况下可能无效,例如我所遇到的情况。但dialog_top布局的内容必须覆盖UI层上的任何内容。但无论如何,这是一种丑陋的解决方法。


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