Search code examples
androidandroid-alertdialogdivider

Add Divider to AlertDialog with CustomView


I'd like to add a divider to an alert dialog at the bottom, similar to the one it shows when there are long list views (see image). A not-customized alertdialog However, I've added a customized view, because I want to be able to use a generic layout for all my AlertDialogs in the whole app. Now there is a very huge space between view and buttons. Additionally the listview, which used to have the divider (from the original AlertDialog view), is not available anymore and my layout has it's own recyclerview. (Because they are recommended nowadays.) My current state I tried adding a divider in my custom view, but this divider is bound to the padding of it's parent and therefore doesn't fill the whole dialog (and is still heavily spaced from the buttons). enter image description here

So I'd basically like to access the area of the buttons in the alertdialog to add a divider at the top of this view. (Which then would be full width and below the padding of the custom view.) It would be great, if this was possible with the Builder, because I sometimes use positive and negative buttons and sometimes only negative or only positive and customizing all that in a generic layout as well would be a huge effort.

Here's my custom layout (with divider). I'm using the MaterialAlertDialogBuilder. Note: I could remove the padding at the bottom to remove the space, but then it looks smashed and the problem with the width of the divider still isn't fixed.

<?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"
    style="@style/AppCompatAlertDialogTheme"
    android:padding="?dialogPreferredPadding"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/alert_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="to"
        android:textAppearance="@style/TFAlertDialogStyle"
        android:textColor="@color/black"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/alert_explanation"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="@dimen/padding_small"
        android:text="@string/lorem"
        android:textColor="@color/black"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/alert_title"
        tools:visibility="visible" />

    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/alert_options"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="@dimen/padding_small"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/alert_explanation">
        <!--In here will be the options for every alert dialog-->
        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/alert_options_recycler"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    </androidx.constraintlayout.widget.ConstraintLayout>
    <View
        android:id="@+id/alertDivider"
        style="@style/Divider"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintBottom_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

Goal: enter image description here

Edit 1: It should also work with the recyclerview being filled, so it has to scroll, where the current solutions let the recyclerview disappear in the padding. There's 1 1/2 items left, but I can't scroll any further. (Image is without marginTop on Divider, with margin it actually disappears as well) enter image description here

Solution: If you don't have a scrolling recyclerview with many items, @shraddha patel s approach works just fine. However, if you have one, to avoid cutting off the last items, you need to use a LinearLayout instead of a ConstraintLayout for the contentview, as shown in this somewhat related bug report: https://github.com/material-components/material-components-android/issues/1336 However, if you have items below the recyclerview, the parent layout still needs to stay a constraint layout or the divider will disappear in scrolling lists. So the working solution for me now is:

<?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
        <!--Don't ever refactor that to constraint layout.
        There's some weird magic making it work only with a LinearLayout.-->
        <androidx.appcompat.widget.LinearLayoutCompat
            android:orientation="vertical"
            android:id="@+id/alert_content_view"
            style="@style/AppCompatAlertDialogTheme"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:padding="?dialogPreferredPadding">

            <TextView
                android:id="@+id/alert_title"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="TextView"
                android:textAppearance="@style/TFAlertDialogStyle"
                android:textColor="@color/black"/>

            <TextView
                android:id="@+id/alert_explanation"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="@dimen/padding_small"
                android:text="@string/desc"
                android:textColor="@color/black"
                tools:visibility="visible" />

            <androidx.constraintlayout.widget.ConstraintLayout
                android:id="@+id/alert_options"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="@dimen/padding_small">
                <!--In here will be the options for every alert dialog-->
                <androidx.recyclerview.widget.RecyclerView
                    android:id="@+id/alert_options_recycler"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    app:layout_constraintBottom_toBottomOf="parent"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toTopOf="parent" />
            </androidx.constraintlayout.widget.ConstraintLayout>
        //Some views set to visibility = gone
        </androidx.appcompat.widget.LinearLayoutCompat>

        <View
            android:id="@+id/alertDivider"
            style="@style/Divider"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"/>
    </androidx.constraintlayout.widget.ConstraintLayout>

Solution

  • If you have to implement the above UI using the ConstraintLayout layout then you can use the below code,

    <?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="wrap_content">
    
        <androidx.constraintlayout.widget.ConstraintLayout
            style="@style/AppCompatAlertDialogTheme"
            android:padding="?dialogPreferredPadding"
            android:layout_width="match_parent"
            android:id="@+id/csLayout"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            android:layout_height="wrap_content">
        <androidx.appcompat.widget.AppCompatTextView
            android:id="@+id/alert_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/Title"
            android:textColor="@color/black"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    
        <androidx.appcompat.widget.AppCompatTextView
            android:id="@+id/alert_explanation"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:text="@string/desc"
            android:textColor="@color/black"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@id/alert_title"
            tools:visibility="visible" />
    
        <androidx.constraintlayout.widget.ConstraintLayout
            android:id="@+id/alert_options"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/alert_explanation">
            <!--In here will be the options for every alert dialog-->
            <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/alert_options_recycler"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent" />
        </androidx.constraintlayout.widget.ConstraintLayout>
        </androidx.constraintlayout.widget.ConstraintLayout>
        <View
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:layout_marginTop="10dp"
            app:layout_constraintTop_toBottomOf="@+id/csLayout"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            android:background="@color/black" />
    </androidx.constraintlayout.widget.ConstraintLayout>
    

    enter image description here