将视图放置/重叠(z-index)在android中另一个视图之上


229

我有一个线性布局,其中包含imageview和textview,一个在另一个布局下面。

<LinearLayout android:orientation="horizontal" ... >
 <ImageView 
     android:id="@+id/thumbnail"
     android:layout_weight="0.8" 
     android:layout_width="0dip"
     android:layout_height="fill_parent">
 </ImageView>
 <TextView 
    android:id="@+id/description"
    android:layout_weight="0.2"
    android:layout_width="0dip"
    android:layout_height="wrap_content">
 </TextView>

可能缺少一些规则,这是一个想法,布局看起来如何。我想在图像视图上方放置另一个长度和宽度为50dip的小文本视图,“上方”是指z-index大于imageview,我希望将其放置在imageview的中心和上方(重叠)。

我想知道如何将z-index(最好是线性布局)变化的一个视图放置在另一个视图之上?

Answers:


294

您不能为此使用LinearLayout,但是可以使用FrameLayout。在中FrameLayout,z-index由项目添加的顺序定义,例如:

<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    >
    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/my_drawable"
        android:scaleType="fitCenter"
        />
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|center"
        android:padding="5dp"
        android:text="My Label"
        />
</FrameLayout>

在这种情况下,TextView将沿着图像的底部中心绘制在ImageView的顶部。


是的,在查阅文档后,我是使用框架布局本身完成的。谢谢。
坐在

11
为此,使用FrameLayout而不是RelativeLayout有优势吗?
Ixx 2012年

12
FrameLayout与组中的其他视图无关,只是将它们相对于父视图进行分层。RelativeLayout更适合相对于其他项目定位。
凯文·科波克

3
嗨,kcoppock,我的手机(hdpi)在帧布局中不遵循z顺序,但是我有另一个(xhdpi)并遵循此顺序,您知道为什么这样做吗?提前致谢!:d
MerlíEscarpenter佩雷斯

1
从API 21 / KitKat开始,您现在可以使用setZ和translationZ了。不再需要FrameLayout hack(最终!)。对于现代的5.0+开发,这应该是首选的答案:stackoverflow.com/a/29703860/358578
pbarranis


66

RelativeLayout以相同的方式工作,相对布局中的最后一个图像获胜。


14
除非您使用高程,否则您还需要其中的最大值。
Sami Kuhmonen

5
在海拔升高之前就已经问过并回答了这个问题。如果您的应用程序的minSdk小于Lollipop(使用棒棒糖的手机,如果仅依靠海拔高度,布局看起来会错误),那么使用海拔高度将无法解决问题-您仍然必须注意布局的顺序。没错,但是,如果在底部组件上使用高程-绝对需要在顶部至少具有相同或更高的高度。
jt-gilkeson

27

更改抽签顺序

一种替代方法是更改​​父级绘制视图的顺序。您可以通过调用setChildrenDrawingOrderEnabled(true)并重写getChildDrawingOrder(int childCount,int i)从ViewGroup启用此功能。

例:

/**
 * Example Layout that changes draw order of a FrameLayout
 */
public class OrderLayout extends FrameLayout {

    private static final int[][] DRAW_ORDERS = new int[][]{
            {0, 1, 2},
            {2, 1, 0},
            {1, 2, 0}
    };

    private int currentOrder;

    public OrderLayout(Context context) {
        super(context);
        setChildrenDrawingOrderEnabled(true);
    }

    public void setDrawOrder(int order) {
        currentOrder = order;
        invalidate();
    }

    @Override
    protected int getChildDrawingOrder(int childCount, int i) {
        return DRAW_ORDERS[currentOrder][i];
    }
}

输出:

拨打OrderLayout#setDrawOrder(int)0-1-2会导致:

在此处输入图片说明 在此处输入图片说明 在此处输入图片说明


您是否在活动的onCreate()中调用setDrawOrder(i)?如果我的xml中有6个小部件,是否需要使用6个数字(0-5)的数组初始化DRAW_ORDERS的每一行?
约翰·沃德

@JohnWard上面显示的布局仅用于示例目的,您可以在getChildDrawingOrder()中定义自己的行为。
Tobrun


20

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


3
现在,这应该是API 21 / KitKat / 5.0或更高版本的首选答案。幸运的是,不再需要旧的frameLayout hack。我个人不了解setZ和translationZ之间的区别,但是后者是一个属性,对我来说效果很好。谢谢!
pbarranis '16

对于以前的api,您也可以使用ViewCompat#setZ()。
Ali Yucel Akgul

@AliYucelAkgul如果您在这里查看文档,则可以看到 Compatibility: API < 21: No-op 。所以我认为这行不通
Vadim Kotov

@VadimKotov,我已经在我的应用程序中尝试过了,并且可以正常工作。
Ali Yucel Akgul

@AliYucelAkgul很好,很奇怪。也许是文档中的错误?您是否100%确定它适用于API <21?我有一个想法,它可以改变的看法上一个API的顺序,但没有花哨的东西,如海拔等。
瓦迪姆·科托夫

14

我通过android:elevation="1dp"在另一个视图上添加想要的视图来解决了相同的问题。但是它不能在5.0以下显示,并且会有一点阴影,如果可以接受,就可以了。

因此,最正确的解决方案是@kcoppock。


7

在RelativeLayout中尝试以下操作:

ImageView image = new ImageView(this);
image.SetZ(float z);

这个对我有用。


2
您应该更好地解释。例如,您将此代码放在哪里?
DevB2F

好吧,我把它放在OnCreate()方法中。与之前添加的图像相比,添加的每个图像都有z优先级索引。我的意思是,通过z索引,我可以更改下一个在上一个之后的位置。
里佐

5

有一种使用LinearLayout的方法。只需将上一个元素的marginTop设置为相应的负值,并确保您想要的顶部元素在XML中您想要的下方元素之后。

<linearLayout android:orientation="horizontal" ... >
<ImageView 
 android:id="@+id/thumbnail"
 android:layout_weight="0.8" 
 android:layout_width="0dip"
 android:layout_height="fill_parent"
>
</ImageView>
<TextView 
android:id="@+id/description"
android:layout_marginTop="-20dip"
android:layout_weight="0.2"
android:layout_width="0dip"
android:layout_height="wrap_content"
>
</TextView>



0

如果您只需要在需要时将一个视图放在最前面,则使用此方法:

containerView.bringChildToFront(topView);

containerView是要排序的视图的容器,topView是我想要在容器中最顶部的视图。

要安排多个视图,将如上所述使用setChildrenDrawingOrderEnabled(true)并覆盖getChildDrawingOrder(int childCount,int i)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.