如何在约束布局中叠加视图?

时间:2017-11-06 15:46:18

标签: android android-constraintlayout

我有登录活动的这种布局。我希望覆盖progressBar,就像使用FrameLayout一样。如何使用ConstraintLayout

执行此操作
<layout>

    <data>

        <variable
            name="vm"
            type="com.app.android.login.vm" />
    </data>

    <ScrollView 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"
        android:fillViewport="true"
        tools:context="com.app.android.login.LoginActivity"
        tools:ignore="missingPrefix">

        <android.support.constraint.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:paddingBottom="@dimen/default_view_margin_bottom_8dp">

            <android.support.design.widget.TextInputLayout
                android:id="@+id/til_login_email"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginEnd="@dimen/default_view_margin_right_8dp"
                android:layout_marginStart="@dimen/default_view_margin_left_8dp"
                android:textColorHint="@color/colorSecondaryText"
                app:hintTextAppearance="@style/AppTheme.InputLayoutStyle"
                app:layout_constraintBottom_toTopOf="@+id/til_login_password"
                app:layout_constraintTop_toTopOf="parent"
                app:layout_constraintVertical_chainStyle="packed">

                <android.support.design.widget.TextInputEditText
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:hint="@string/login_email"
                    android:imeOptions="actionNext"
                    android:singleLine="true"
                    android:text="@={vm.emailField}"
                    android:textColor="@color/colorPrimaryText" />
            </android.support.design.widget.TextInputLayout>

            <android.support.design.widget.TextInputLayout
                android:id="@+id/til_login_password"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginEnd="@dimen/default_view_margin_right_8dp"
                android:layout_marginStart="@dimen/default_view_margin_left_8dp"
                android:textColorHint="@color/colorSecondaryText"
                app:hintTextAppearance="@style/AppTheme.InputLayoutStyle"
                app:layout_constraintBottom_toTopOf="@+id/btn_login_login"
                app:layout_constraintTop_toBottomOf="@+id/til_login_email"
                app:layout_constraintVertical_chainStyle="packed">

                <android.support.design.widget.TextInputEditText
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:hint="@string/login_password"
                    android:imeOptions="actionDone"
                    android:inputType="textPassword"
                    android:singleLine="true"
                    android:text="@={vm.passwordField}"
                    android:textColor="@color/colorPrimaryText" />
            </android.support.design.widget.TextInputLayout>

            <Button
                android:id="@+id/btn_login_login"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginEnd="@dimen/default_view_margin_right_8dp"
                android:layout_marginStart="@dimen/default_view_margin_left_8dp"
                android:layout_marginTop="48dp"
                android:onClick="@{vm::login}"
                android:text="@string/login_btn_text"
                android:textColor="@color/colorWhite"
                app:layout_constraintBottom_toTopOf="@+id/textview_login_forgot_password"
                app:layout_constraintTop_toBottomOf="@+id/til_login_password"
                app:layout_constraintVertical_chainStyle="packed" />

            <TextView
                android:id="@+id/textview_login_forgot_password"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginEnd="@dimen/default_view_margin_right_8dp"
                android:layout_marginStart="@dimen/default_view_margin_left_8dp"
                android:layout_marginTop="36dp"
                android:gravity="center"
                android:text="@string/login_forgot_password"
                app:layout_constraintBottom_toTopOf="@+id/btn_login_register"
                app:layout_constraintTop_toBottomOf="@+id/btn_login_login"
                app:layout_constraintVertical_chainStyle="packed" />

            <Button
                android:id="@+id/btn_login_register"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginEnd="@dimen/default_view_margin_right_8dp"
                android:layout_marginStart="@dimen/default_view_margin_left_8dp"
                android:text="@string/login_sign_up"
                android:textColor="@color/colorWhite"
                app:layout_constraintBottom_toBottomOf="parent" />

            <ProgressBar
                android:id="@+id/progressBar"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:visibility="@{vm.progressVisibility}"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintLeft_toLeftOf="parent"
                app:layout_constraintRight_toRightOf="parent"
                app:layout_constraintTop_toTopOf="parent" />

        </android.support.constraint.ConstraintLayout>
    </ScrollView>
</layout>

看起来像这样:

enter image description here

我正在寻找适用于API级别19+的解决方案。我不希望通过将ButtonProgressBar包裹在ViewGroup左右来在我的布局中添加更多层次结构。

14 个答案:

答案 0 :(得分:16)

有两个选项,在每种情况下,您都会在<ProgressBar/>标记中添加一个属性。它要么是

android:translationZ="2dp"

android:elevation="2dp"

API级别必须> = 21。

答案 1 :(得分:12)

如果要100%覆盖目标视图,请将覆盖视图的所有边约束到目标视图的相应边,并将覆盖视图的高度和宽度设置为0dp,如下所示:

    <View
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="@id/animation_view"
        app:layout_constraintLeft_toLeftOf="@id/animation_view"
        app:layout_constraintRight_toRightOf="@id/animation_view"
        app:layout_constraintTop_toTopOf="@id/animation_view"/>

这是一个工作示例。在下图中,红色稀松布放在图像上。 XML遵循图像。

enter image description here

<android.support.constraint.ConstraintLayout 
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:id="@+id/animation_view"
        android:layout_width="250dp"
        android:layout_height="250dp"
        android:src="@mipmap/ic_launcher"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <View
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="#AAFF0000"
        app:layout_constraintBottom_toBottomOf="@id/animation_view"
        app:layout_constraintLeft_toLeftOf="@id/animation_view"
        app:layout_constraintRight_toRightOf="@id/animation_view"
        app:layout_constraintTop_toTopOf="@id/animation_view" />
</android.support.constraint.ConstraintLayout>

有关详情,请参阅ConstraintLayout override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) // Count the number contacts to get the correct number of lines in the table let ref_table = ref.child("users").child((user?.uid)!).child("emergencyContacts") print("Starting observing") ref_table.observe(.value, with: { (snapshot: DataSnapshot!) in print("Got snapshot") print(snapshot.childrenCount) let count = snapshot.childrenCount self.numberOfContact = Int(count) self.UI_contactsTableView.reloadData() ref_table.removeAllObservers() }) print("Returning count") }

答案 2 :(得分:2)

ProgressBar 2dp上设置高程似乎有效。

android:elevation="2dp"

您还可以尝试按照answer中的建议设置translationZsimilar question。对我来说,这适用于运行API 17的模拟器,进度条按预期显示在顶部。如果您收到任何警告,请检查您的构建版本

答案 3 :(得分:1)

我想为您提供XML解决方案的替代方案 您还可以以编程方式将视图添加到根视图。 (ConstraintLayout

  

ViewGroupOverlay是一个额外的图层,位于ViewGroup(&#34;主机视图&#34;)之上,该视图是在该视图中的所有其他内容之后绘制的(包括视图组&#39; s儿童)。通过添加和删除视图和drawable来完成与覆盖层的交互。

<android.support.constraint.ConstraintLayout
            android:id="@+id/root_layout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:paddingBottom="@dimen/default_view_margin_bottom_8dp">

如果您在代码中引用根,则可以添加ProgressBar 像这样:

rootLayout.overlay.add(ProgressBar(context).apply {
    measure(View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.EXACTLY))
    layout(0, 0, 100, 100)
})

您还可以查看此link以获取更多信息 这个SO问题也可以提供帮助。

答案 4 :(得分:1)

您可以尝试以下选项之一: 1.在布局外添加相对布局here

 <RelativeLayout
   android:id="@+id/relativelayout_progress"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:visibility="gone"
   android:background="#aa000022" >

   <ProgressBar 
       android:layout_centerInParent="true"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:indeterminateOnly="true" />

</RelativeLayout>
  1. 在此活动的onCreate中添加视图叠加层,如Android 4.3 User Interface View overlays
  2. 所述

答案 5 :(得分:1)

解决此问题的另一种简单方法是将Button更改为View,更改背景和大小。用TextView覆盖它以替换旧Button文本,将其覆盖View以便稍后点击

答案 6 :(得分:1)

这是您的API 19解决方案。它会在您的CircularProgressDrawable顶部放置一个ConstraintLayout

这就是它的样子:

enter image description here

你要做的是:

  1. 摆脱XML ProgressBar

  2. 为您的XML ConstraintLayout提供ID,例如:

    android:id="@+id/cl"
    
  3. 将此代码添加到您的MainActivity:

    public class MainActivity extends AppCompatActivity implements View.OnClickListener {
        boolean toggle;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            final ConstraintLayout cl = findViewById(R.id.cl);
            cl.setOnClickListener(this);
        }
    
        @Override
        public void onClick(final View view) {
            toggle ^= true;
            if (toggle) {
                startProgress();
            } else {
                stopProgress();
            }
        }
    
        void startProgress() {
            final ConstraintLayout cl = findViewById(R.id.cl);
            final CircularProgressDrawable progressDrawable = new CircularProgressDrawable(this);
            progressDrawable.setColorSchemeColors(Color.MAGENTA);
            progressDrawable.setCenterRadius(50f);
            progressDrawable.setStrokeWidth(12f);
            progressDrawable.setStrokeCap(Paint.Cap.BUTT);
            cl.post(new Runnable() {
                @Override
                public void run() {
                    progressDrawable.setBounds(0, 0, cl.getWidth(), cl.getHeight());
                    cl.getOverlay().add(progressDrawable);
                }
            });
            progressDrawable.start();
        }
    
        void stopProgress() {
            final ConstraintLayout cl = findViewById(R.id.cl);
            final CircularProgressDrawable progressDrawable = new CircularProgressDrawable(this);
            progressDrawable.setColorSchemeColors(Color.MAGENTA);
            progressDrawable.setCenterRadius(50f);
            progressDrawable.setStrokeWidth(12f);
            progressDrawable.setStrokeCap(Paint.Cap.BUTT);
            cl.post(new Runnable() {
                @Override
                public void run() {
                    cl.getOverlay().clear();
                }
            });
            progressDrawable.stop();
        }
    }
    

答案 7 :(得分:0)

您可以通过为视图设置Z翻译来实现目标。

将此方法放在辅助类中(例如:UIUtils)并将其用于您的视图:

/**
 * Set the 'Z' translation for a view
 *
 * @param view         {@link View} to set 'Z' translation for
 * @param translationZ 'Z' translation as float
 */
public static void setTranslationZ(View view, float translationZ) {
    ViewCompat.setTranslationZ(view, translationZ);
}

<强> USAGE:

UIUTils.setTranslationZ(YOUR_VIEW, 5);

答案 8 :(得分:0)

在我的观察中,Android沿z轴按“堆叠”它们在xml文件中出现的顺序,因为文件开始处的视图位于z轴的顶部,视图位于文件的末尾将在底部。当然,一旦开始设置仰角和z平移等,z轴堆栈顺序就会受到影响...

因此将progressBar声明移到ConstraintLayout的顶部应该使它出现在其他视图的上方,这对我有用。

答案 9 :(得分:0)

2020年更新的解决方案

科林语

我有2种情况,第一种是普通按钮,第二种是 防止点击动作导致按钮中心的进度

如果您想知道我如何处理按钮和进度条,这里只是简码

如果您想了解一个想法,请使用jsut这两种方法

private fun disableButton() {
    button.run {
        preservedButtonText = text.toString()
        text = ""
        isClickable = true
        isEnabled = false
    }
    progressBar.visibility = View.VISIBLE

}

private fun enableButton() {
    button.run {
        text = preservedButtonText
        isClickable = false
    }
    progressBar.visibility = View.INVISIBLE
}

让您感到惊讶的是,该类可以完成您刚使用的所有工作 我处理创建父约束布局,它是孩子的​​约束(按钮,进度栏) 以编程方式

 /**
 * Created by Amirahmad Adibi.
 * XProject | Copyrights 2019-12-16.
 */

class ZProgressButton(context: Context, var attributeSet: AttributeSet) :
    ConstraintLayout(context, attributeSet) {
    var isLoading: Boolean = false
        set(value) {
            handelShowing(value)
            field = value
        }

    var preservedButtonText: String = ""
    var button: Button
    var progressBar: ProgressBar

    init {
        resetPadding()

        button = getButton(context, attributeSet)
        progressBar = getProgressBar(context, attributeSet)
        preservedButtonText = button.text.toString()

        addView(button)
        addView(progressBar)
        @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
        progressBar.elevation = 2f
        ViewCompat.setTranslationZ(progressBar, 5f)
        ViewCompat.setTranslationZ(button, 1f)
        handleConstraint(this, button, progressBar)
    }

    private fun handleConstraint(
        view: ConstraintLayout,
        button: Button,
        progressBar: ProgressBar
    ) {
        with(ConstraintSet()) {
            clone(view)
            connect(button.id, ConstraintSet.RIGHT, view.id, ConstraintSet.RIGHT)
            connect(button.id, ConstraintSet.LEFT, view.id, ConstraintSet.LEFT)
            connect(button.id, ConstraintSet.TOP, view.id, ConstraintSet.TOP)
            connect(button.id, ConstraintSet.BOTTOM, view.id, ConstraintSet.BOTTOM)
            connect(progressBar.id, ConstraintSet.RIGHT, view.id, ConstraintSet.RIGHT)
            connect(progressBar.id, ConstraintSet.LEFT, view.id, ConstraintSet.LEFT)
            connect(progressBenter code herear.id, ConstraintSet.TOP, view.id, ConstraintSet.TOP)
            connect(progressBar.id, ConstraintSet.BOTTOM, view.id, ConstraintSet.BOTTOM)
            applyTo(view)
        }
    }

    private fun getButton(context: Context, attributeSet: AttributeSet): Button {
        return ZButton(context, attributeSet).run {
            id = View.generateViewId()
            text = "text"
            layoutParams = ViewGroup.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT
            )
            isClickable = true
            return@run this
        }
    }

    private fun getProgressBar(context: Context, attributeSet: AttributeSet): ProgressBar {
        return ProgressBar(context, attributeSet).run {
            id = View.generateViewId()
            visibility = View.VISIBLE
            layoutParams = ViewGroup.LayoutParams(
                ViewGroup.LayoutParams.WRAP_CONTENT,
                ViewGroup.LayoutParams.WRAP_CONTENT
            )
            setPadding(4, 4, 4, 4)
            return@run this
        }
    }


    fun resetPadding() {
        setPadding(0, 0, 0, 0)
    }


    fun handelShowing(value: Boolean) {
        removeView(button)
        removeView(progressBar)
        if (value) {
            disableButton()
        } else {
            enableButton()
        }
        addView(button)
        addView(progressBar)
    }

    private fun disableButton() {
        button.run {
            preservedButtonText = text.toString()
            text = ""
            isClickable = true
            isEnabled = false
        }
        progressBar.visibility = View.VISIBLE

    }

    private fun enableButton() {
        button.run {
            text = preservedButtonText
            isClickable = false
        }
        progressBar.visibility = View.INVISIBLE
    }
}

用法:

buttonLoading.setOnClickListener {
    progressButton.isLoading = true
}
buttonDone.setOnClickListener {
    progressButton.isLoading = false
}

答案 10 :(得分:0)

android:elevation在API级别19中不起作用。一个简单的技巧将用于使用卡片视图并设置该卡片的高度

 <androidx.cardview.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/white"
        android:padding="@dimen/padding_10"
        app:contentPadding="16dp"/>

答案 11 :(得分:0)

在上述情况下,我以这种方式解决了

<FrameLayout
        android:layout_marginTop="16dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <ProgressBar
            android:id="@+id/progress_reset_password"
            android:visibility="visible"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:indeterminateTint="@color/colorAccent"
            android:layout_gravity="center_horizontal"
            android:translationZ="2dp"
            android:elevation="2dp"/>

        <Button
            android:id="@+id/btnGetOTP"
            style="@style/styleButton"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="80dp"
            android:layout_marginRight="80dp"
            android:text="@string/check_email"
            android:textColor="@color/colorWhite"
            android:textSize="16sp"
            android:textStyle="bold"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />


    </FrameLayout>

Open the image above here

答案 12 :(得分:0)

我使用额外的图像向图像视图布局添加了叠加层。此外,将额外的叠加图像视图放在主图像视图的正下方。

<?xml version="1.0" encoding="utf-8"?>
<layout 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">

    <androidx.cardview.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:cardCornerRadius="@dimen/spacing_small"
        android:layout_marginTop="@dimen/spacing_normal">

        <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <androidx.appcompat.widget.AppCompatImageView
                android:id="@+id/imageViewBlog"
                android:layout_width="match_parent"
                android:layout_height="@dimen/blog_post_height"
                android:scaleType="centerCrop"
                app:layout_constraintTop_toTopOf="parent"
                app:srcCompat="@drawable/ic_placeholder" />

            <androidx.appcompat.widget.AppCompatImageView
                android:layout_width="0dp"
                android:layout_height="0dp"
                android:scaleType="fitXY"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent"
                app:srcCompat="@drawable/black_overlay" />

            <androidx.appcompat.widget.AppCompatTextView
                android:id="@+id/tvBlogTopTitle"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginBottom="@dimen/spacing_small"
                android:ellipsize="end"
                android:fontFamily="sans-serif-medium"
                android:maxLines="1"
                android:textColor="@color/pale_grey"
                app:layout_constraintBottom_toTopOf="@+id/tvBlogBigTitle"
                app:layout_constraintEnd_toEndOf="@+id/tvBlogBigTitle"
                app:layout_constraintStart_toStartOf="@id/tvBlogBigTitle"
                tools:text="Travel Inspiration" />

            <androidx.appcompat.widget.AppCompatTextView
                android:id="@+id/tvBlogBigTitle"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginStart="@dimen/spacing_normal"
                android:layout_marginLeft="@dimen/spacing_normal"
                android:layout_marginEnd="@dimen/spacing_normal"
                android:layout_marginRight="@dimen/spacing_normal"
                android:layout_marginBottom="@dimen/spacing_normal"
                android:ellipsize="end"
                android:maxLines="2"
                android:textColor="@color/white"
                android:textSize="@dimen/font_tiny"
                app:layout_constraintBottom_toBottomOf="@+id/imageViewBlog"
                app:layout_constraintEnd_toEndOf="@id/imageViewBlog"
                app:layout_constraintStart_toStartOf="@id/imageViewBlog"
                tools:text="This Photographer is Selling Prints of Her Wildlife Photos to \n in the Masai Mara…" />

        </androidx.constraintlayout.widget.ConstraintLayout>

    </androidx.cardview.widget.CardView>

看起来像下图。

enter image description here

叠加图像:

enter image description here

答案 13 :(得分:-1)

这里有很多关于如何在xml中设置z顺序的例子,都很棒。但是,如果您最终需要以编程方式调整视图叠加层,并且这些视图恰好是按钮,请确保在您的 xml 布局文件中将 stateListAnimator 设置为 null。 stateListAnimator 是 android 的底层 -单击按钮时调整按钮平移Z的引擎盖过程,因此单击的按钮最终会在顶部可见。这并不总是您想要的...对于完整的 Z 顺序控制,请执行以下操作:

enter image description here