Roman Knyazev
Roman Knyazev

Reputation: 3

How to set Dialog width and height in percents in XML

I need my Dialog width and height fill 70% of screen space. I'm using ConstraintLayout as root layout and tried to achieve this by using app:layout_constraintWidth_percent but it's not working.

It would be great to achieve this in XML without Java code.

Here is my 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="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:background="@drawable/dialog_background_shape"
    android:padding="@dimen/app_padding">

    <TextView
        android:id="@+id/textView13"
        style="@style/text_plain3"
        android:textStyle="bold"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="0dp"
        android:layout_marginTop="0dp"
        android:text="@string/add_member_title"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/button_add_member_close"
        style="@style/text_title2"
        android:textStyle="bold"
        android:layout_width="28dp"
        android:layout_height="28dp"
        android:background="@drawable/button_dialog_close"
        android:gravity="center"
        android:text="X"
        android:textColor="@color/text_plain3"
        android:textSize="20sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:ignore="HardcodedText" />

    <TextView
        android:id="@+id/add_member_group_id"
        style="@style/text_group_id"
        android:layout_width="250dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="32dp"
        android:layout_marginTop="64dp"
        android:layout_marginEnd="32dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView13" />

    <TextView
        android:id="@+id/textView17"
        style="@style/text_card"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:text="@string/add_member_annotation"
        app:layout_constraintStart_toStartOf="@+id/add_member_group_id"
        app:layout_constraintTop_toBottomOf="@+id/add_member_group_id"/>

    <EditText
        android:id="@+id/add_member_user_id"
        android:layout_width="248dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:ems="10"
        android:hint="@string/add_member_hint_id"
        android:importantForAutofill="no"
        android:inputType="textPersonName"
        android:maxLength="28"
        app:layout_constraintEnd_toEndOf="@+id/add_member_group_id"
        app:layout_constraintStart_toStartOf="@+id/add_member_group_id"
        app:layout_constraintTop_toBottomOf="@+id/textView17" />

    <Button
        android:id="@+id/button_add_member"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="48dp"
        android:layout_marginBottom="48dp"
        android:text="@string/add_member_button_add"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="@+id/add_member_group_id"
        app:layout_constraintStart_toStartOf="@+id/add_member_group_id"
        app:layout_constraintTop_toBottomOf="@+id/add_member_user_id"/>
</androidx.constraintlayout.widget.ConstraintLayout>

Upvotes: 0

Views: 1067

Answers (2)

Zain
Zain

Reputation: 40878

In order to have a constraint width/height DialogFragment or (any specific width or height in general):

  1. wrap your ConstraintLayout into another ConstraintLayout in order to make the outer take the full size of the screen, and the inner get the desired width/height percentage:

  2. Make the android:background of the outer to be transparent

  3. Constraint the width & height of the inner ConstraintLayout, make it centered in parent, and add the percentage constraint to the width & height:

    app:layout_constraintHeight_percent="0.7"
    app:layout_constraintWidth_percent="0.7"    
    

Now the layout looks like:

<?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:id="@+id/root"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/transparent">
        
    <androidx.constraintlayout.widget.ConstraintLayout      
        android:id="@+id/main_layout"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_gravity="center"
        android:background="@drawable/dialog_background_shape"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHeight_percent="0.7"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintWidth_percent="0.7"        
        android:padding="@dimen/app_padding">

        <TextView
            android:id="@+id/textView13"
            style="@style/text_plain3"
            android:textStyle="bold"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="0dp"
            android:layout_marginTop="0dp"
            android:text="@string/add_member_title"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <TextView
            android:id="@+id/button_add_member_close"
            style="@style/text_title2"
            android:textStyle="bold"
            android:layout_width="28dp"
            android:layout_height="28dp"
            android:background="@drawable/button_dialog_close"
            android:gravity="center"
            android:text="X"
            android:textColor="@color/text_plain3"
            android:textSize="20sp"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            tools:ignore="HardcodedText" />

        <TextView
            android:id="@+id/add_member_group_id"
            style="@style/text_group_id"
            android:layout_width="250dp"
            android:layout_height="wrap_content"
            android:layout_marginStart="32dp"
            android:layout_marginTop="64dp"
            android:layout_marginEnd="32dp"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/textView13" />

        <TextView
            android:id="@+id/textView17"
            style="@style/text_card"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="8dp"
            android:text="@string/add_member_annotation"
            app:layout_constraintStart_toStartOf="@+id/add_member_group_id"
            app:layout_constraintTop_toBottomOf="@+id/add_member_group_id" />

        <EditText
            android:id="@+id/add_member_user_id"
            android:layout_width="248dp"
            android:layout_height="wrap_content"
            android:layout_marginTop="8dp"
            android:ems="10"
            android:hint="@string/add_member_hint_id"
            android:importantForAutofill="no"
            android:inputType="textPersonName"
            android:maxLength="28"
            app:layout_constraintEnd_toEndOf="@+id/add_member_group_id"
            app:layout_constraintStart_toStartOf="@+id/add_member_group_id"
            app:layout_constraintTop_toBottomOf="@+id/textView17" />

        <Button
            android:id="@+id/button_add_member"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="48dp"
            android:layout_marginBottom="48dp"
            android:text="@string/add_member_button_add"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="@+id/add_member_group_id"
            app:layout_constraintStart_toStartOf="@+id/add_member_group_id"
            app:layout_constraintTop_toBottomOf="@+id/add_member_user_id" />
    </androidx.constraintlayout.widget.ConstraintLayout>

</androidx.constraintlayout.widget.ConstraintLayout>
  1. In your custom DialogFragment:
  • Designate the width & height of the dialog to MATCH_PARENT:
dialog?.window?.setLayout(
    LinearLayout.LayoutParams.MATCH_PARENT,
    LinearLayout.LayoutParams.MATCH_PARENT
)
  • Set no background the theme:
<style name="NoBackgroundDialogTheme" parent="Theme.AppCompat.Light.Dialog">
    <item name="android:windowBackground">@null</item>
</style>

Custom Dialog Fragment:

Java:

public class MyDialogFragment extends DialogFragment {

    @Nullable
    @org.jetbrains.annotations.Nullable
    @Override
    public View onCreateView(@NonNull @NotNull LayoutInflater inflater, @Nullable @org.jetbrains.annotations.Nullable ViewGroup container, @Nullable @org.jetbrains.annotations.Nullable Bundle savedInstanceState) {
        return inflater.inflate(
                R.layout.dialog_layout, container,
                false
        );
    }

    @Override
    public int getTheme() {
        return R.style.NoBackgroundDialogTheme;
    }

    @Override
    public void onStart() {
        // Making the dialog full screen
        if (getDialog() != null)
            getDialog().getWindow().setLayout(
                    LinearLayout.LayoutParams.MATCH_PARENT,
                    LinearLayout.LayoutParams.MATCH_PARENT
            );
        super.onStart();
    }
}

Kotlin:

class MyDialogFragment : DialogFragment() {

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {

        return inflater.inflate(
            R.layout.dialog_layout, container,
            false
        )
    }

    override fun getTheme(): Int = R.style.NoBackgroundDialogTheme

    override fun onStart() {
        super.onStart()
        // Making the dialog full screen
        dialog?.window?.setLayout(
            LinearLayout.LayoutParams.MATCH_PARENT,
            LinearLayout.LayoutParams.MATCH_PARENT
        )

    }

}

Note: I am assuming that the dialog layout is R.layout.dialog_layout enter image description here

UPDATE

now if I click on empty space around the Dialog, it doesn't close.

This is because the dialog fragment consumes the entire screen size; you can solve this by the below workaround:

  • Add an ID to the outer most ConstraintLayout, assume it is root >> Updated on the top layout
  • Add an ID to the inner ConstraintLayout, assume it is main_layout >> Updated on the top layout
  • Dismiss the dialog when the root is clicked
  • Do nothing when the main_layout is clicked to consume the event so that it won't be dismissed:

So, update the onStart() of the MyDialogFragment to:

override fun onStart() {
    super.onStart()
    // Making the dialog full screen
    dialog?.window?.setLayout(
        LinearLayout.LayoutParams.MATCH_PARENT,
        LinearLayout.LayoutParams.MATCH_PARENT
    )

    
    val root = requireView().findViewById<ConstraintLayout>(R.id.root)
    root.setOnClickListener {
        dismiss() // Dismiss the dialog
    }
    
    val main = requireView().findViewById<ConstraintLayout>(R.id.main_layout)
    main.setOnClickListener {
        // Consume the event
    }

}

Upvotes: 2

Ole Pannier
Ole Pannier

Reputation: 3673

ConstraintLayout:

I see your "Dialog" Box contains a lot of different views. For that I made a simple example for you to show how to use Guideline for achieving percentages of Views. I suggest to learn how this works and rebuild your layout with better constraining on this Guidelines, because now everything is wired up really bad. The idea will be to wire the ConstraintLayout to the Guideline and everything beside that (e.g. TextView etc.) to the ConstraintLayout. (Without Hardcoding!, that's how relative design work).

My example shows a TextView (could be your ConstraintLayout (frame for everything) that has exactly 70% (app:layout_constraintGuide_percent="0.7") vertically and horizontal of the screen. Important is to set the TextViews width and height to 0dp and to attach to the Guideline:

<?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">

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/vertical_guideline"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintGuide_percent="0.7" />

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/horizontal_guideline"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layout_constraintGuide_percent="0.7" />

    <TextView
        android:id="@+id/textView"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="#2962FF"
        app:layout_constraintBottom_toTopOf="@+id/horizontal_guideline"
        app:layout_constraintEnd_toStartOf="@+id/vertical_guideline"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:text="TextView" />

</androidx.constraintlayout.widget.ConstraintLayout>

Result:

70% equal on both

In addition same for LinearLayout:

You can use android:layout_weight="" to give a percent amount. So 70% means a weight of .70.

Keep in mind to set the width or/and height to 0dp

<LinearLayout
    android:layout_width="match_parent" 
    android:layout_height="wrap_content"
    android:orientation="horizontal">

    <TextView
        android:text="70 percent of screen" 
        android:layout_width="0dp" 
        android:layout_height="wrap_content" 
        android:layout_weight=".70" /> 

</LinearLayout>

Upvotes: 0

Related Questions