Android约束布局 - 将一个视图放在另一个视图的上方

152

我正在尝试在ConstraintLayout中的一个Button上方添加一个ProgressBar

<Button
    android:id="@+id/sign_in_button"
    android:layout_width="280dp"
    android:layout_height="75dp"
    android:layout_marginBottom="75dp"
    android:layout_marginTop="50dp"
    android:text="@string/sign_in"
    android:textColor="@color/white"
    android:textSize="22sp"
    android:textStyle="bold"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/passwordEditText"
    app:layout_constraintVertical_bias="0.0"/>

<ProgressBar
    android:id="@+id/progressBar"
    style="?android:attr/progressBarStyle"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:layout_constraintTop_toTopOf="@+id/sign_in_button"
    android:layout_marginTop="8dp"
    app:layout_constraintBottom_toBottomOf="@+id/sign_in_button"
    android:layout_marginBottom="8dp"
    app:layout_constraintVertical_bias="0.5"
    android:layout_marginLeft="8dp"
    app:layout_constraintLeft_toLeftOf="@+id/sign_in_button"
    android:layout_marginRight="8dp"
    app:layout_constraintRight_toRightOf="@+id/sign_in_button"/>

但是即使在onCreate中对ProgressBar调用了bringToFront,它仍然总是停留在Button的后面。

ProgressBar progressBar = (ProgressBar)findViewById(R.id.progressBar);
progressBar.bringToFront();

这太奇怪了,我尝试着对你的布局进行一些调整,甚至倒转链式结构,让进度条约束于编辑框,按钮约束于进度条,但是按钮似乎总是在进度条之上。 - lelloman
你能使用FrameLayout吗?试一试,知道在FrameLayout中,z-index是由布局内的顺序给出的(所以Button在前,Progress在后)。 - razgraf
你的 passwordEditText 在哪里?我检查了一下,没有 app:layout_constraintTop_toBottomOf="@+id/passwordEditText",我可以看到进度条在上面,请提供 passwordEditText。 - Pavan
8个回答

249

ProgressBar 上设置一个高度;2dp 似乎可以使用。

android:elevation="2dp"

你还可以尝试按照接受的答案所建议的方式设置translationZ,这是一个类似问题的解决方法。

我也发现这个答案作为另一种选择。


21
elevationtranslationZ只适用于API >= 21,那么对于旧的API呢? - q126y
1
@q126y 我认为这个问题直到API 21才出现,所以旧的API不需要这个。我已经在运行API 17的模拟器上尝试过了,进度条按预期显示在顶部。 - Cheticamp
8
@q126y ViewCompat.setTranslationZ(view, 5) - Silvia H
3
ViewCompat.setElevation(view, 20f)可以帮助您设置视图的高度为20个像素。 - sagus_helgy
为什么要保留两位小数?一位小数可以吗? - hmac
显示剩余5条评论

27
我们需要使用 android:elevation 来进行控制。
android:elevation="10dp"

这个 elevation 属性只在 API 等级 >= 21 上工作。但在此之下,它将正常运行。如果我们在按钮视图下面添加进度条视图,它会显示底部的视图在另一个视图的顶部。


13

在想要出现在下方的视图之后,您可以简单地定义您希望位于顶部的视图。

对于按钮而言,注意它们的高度受其stateListAnimator控制。Widget.MaterialComponents.Button的stateListAnimator具有默认高度@dimen/mtrl_btn_elevation(2dp)。因此,如果您想在按钮上方显示一个视图,则该视图的高度至少应为2dp。


你如何确保XML不会意外重排? - RamPrasadBismil
@ Cristan,最好提供一个代码片段或示例。谢谢 - blueware
1
我想知道为什么在这个问题中 ProgressBar 的定义在 Button 之后,但是 ProgressBar 没有在 Button 上面。 - Michael Osofsky
我也曾认为如此,但无论我在约束布局中的哪个位置放置ImageView,它总是出现在按钮后面。 - behelit
我终于弄明白为什么这对按钮似乎不起作用了。我已经更新了我的答案以反映这一点。 - Cristan

7
在约束布局中,您应该使用`translationZ`属性来控制要在其下方的视图比它更高。

5

虽然android:elevation="4dp"translationz会起作用,但是至少需要API级别21。如果由于某种原因无法实现,确保你想要置顶的视图在其他视图之后被提及。例如,如果我想将进度条放在ImageView的上方:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 
   xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto"
   xmlns:tools="http://schemas.android.com/tools"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   tools:context=".ImageActivity">

<ImageView
   android:id="@+id/image_view"
   android:layout_width="0dp"
   android:layout_height="0dp"
   app:layout_constraintBottom_toBottomOf="parent"
   app:layout_constraintDimensionRatio="6:4"
   app:layout_constraintEnd_toEndOf="parent"
   app:layout_constraintStart_toStartOf="parent"
   app:layout_constraintTop_toTopOf="parent" />

<ProgressBar
   android:id="@+id/progress_bar"
   style="?android:attr/progressBarStyle"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   app:layout_constraintBottom_toBottomOf="parent"
   app:layout_constraintEnd_toEndOf="parent"
   app:layout_constraintStart_toStartOf="parent"
   app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

2

使用高度(elevation)是有效的,但它有一些限制,例如需要API级别21+,而且如果高度较低(在我的情况下为2dp),则在长按时视图会变得不可见,因此您可以使用一个技巧,简单地将按钮替换为“View”或“TextView”,您可以使用这些视图来完成与buttonView相同的所有操作。


1

针对Android Studio 3.5的更新答案:

在更新的布局编辑器中,现在更容易选择前置视图,如Android Studio发布说明所示

此外,蓝色叠加层现在突出显示约束目标。当试图约束与另一个组件重叠的组件时,此突出显示特别有用。

https://developer.android.com/studio/releases

更简单的方法是,如果你将视图向上拖动(复制粘贴或从布局编辑器中的组件树中选择),它会获得较低的优先级(因此它会位于其他视图后面)。

1

按钮默认具有TranslationZ设置,因此您有两个选项

1- 使进度条的TranslationZ大于按钮的高度

ViewCompat.setTranslationZ(progressBar, 5)// to support older api <21

2 - 将按钮TranslateZ设置为0,使视图在您的约束布局中按顺序显示在彼此上方,您可以通过将样式设置为按钮来实现这一点。

style="@style/Widget.AppCompat.Button.Borderless"

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