Zolly
Zolly

Reputation: 131

Android: Custom Dialog's sizing is unprecise

I am trying to create a custom dialog view for my application. When running the program, the result is far different from what I expect.

XML file:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="@color/colorPrimaryDark">

<LinearLayout
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="200dp"
    android:background="@color/colorAccent">
</LinearLayout>

<LinearLayout
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/colorPrimary">

    <Button
        android:id="@+id/button10"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Button" />
</LinearLayout>
</LinearLayout>

The Java class:

public class SinglePSettings extends AppCompatDialogFragment {

    @Override
    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
        LayoutInflater inflater = getActivity().getLayoutInflater();

        View view = inflater.inflate(R.layout.layout_singlepsettings, null);
        builder.setView(view)
               .setTitle("Settings");

        return builder.create();
    }

    public void onResume()
    {
        super.onResume();
        Window window = getDialog().getWindow();
        Point size = new Point();
        Display display = window.getWindowManager().getDefaultDisplay();
        display.getSize(size);
        int width = (int)(size.x * 0.90);
        int height = (int)(size.y * 0.90);
        window.setLayout(width, height);
        window.setGravity(Gravity.CENTER);
    }

Expectation and result

I do not fully understand why the main LinearLayout is 'invisible'. It also seems that the items inside do not depend on it. Is there a way to fill up the full-size of the dialog block with a layout?

(What of course later I can further customize.)

Upvotes: 0

Views: 155

Answers (1)

ansh sachdeva
ansh sachdeva

Reputation: 1179

This is because the root layout of your dialogue is of height match_parent and the total size of content is 200dp for the first child Linearlayout + ~24 dp for the second child Linearlayout which is smaller than the total size of the dialog.

You should either change the height of the parent LinearLayout to wrap_content or add android:weight=1 to either of the child LinearLayouts.


Let me try to explain how linear layout works. Note that these are all from experience and you should read the official documentation for better understanding.

The dimension which is in line with the orientation plays a crucial role for a linear layout's children. Thus, if the orientation is horizontal, then all the children will stack horizontally, and their width attribute would be needed to be controlled.

Imagine a horizontal linear layout as a home. For the time being, assume that you always have to keep your crucial attribute as match_parent in parent linear layout. Thus our Linear layout/ home has width=match_parent. There can be three major ways by which the children could be added:

Keeping each child as wrap_content

  • This means each child will take the amount of screen space equal to its own size.

  • if the number of items is less or the screen size is big enough, this approach works.

  • But if there are a lot of big items, then the total space required by them = sum of all of their individual widths. If this sum is greater than the screen size, then some of the items will go out of the screen.

  • In our home analogy, it is like we are stacking all the tables, chairs, beds, etc. in a straight line. If they take up less space than the space between two end walls, then it's great, but if they need more horizontal space, then we must break the wall to adjust them.

  • Thus it's not advisable to keep your all items as wrap content

Enter image description here

Keeping one or more children as match_parent

  • This is a very wrong approach. When you keep a child's width as match_parent, you are basically telling the compiler to provide complete screen space to this single view.

  • And the compiler would definitely do so. Even if it's a button, it would stretch out on the complete screen and other views will not be visible, because they are virtually out of the screen.

  • When there are multiple views with width=match_parent, it will simply allocate the whole screen space to the first view from the left.

  • In our home analogy, it's like as soon as you changed the width attribute of your chair to match_parent, the room magically expanded it to take complete space, and thus your bed, table, etc. are now all squashed up at the side of room.

Enter image description here

Keeping layout_weight=x for one or more children

  • This is the best approach to be used in linear layout. I think of it as assigning a percentage of screen to a view.

  • If your child view has weight=x, then it will not be affected by the value present in your view's crucial attribute. That means you can have width= match_parent or wrap_content or even 1000000dp, if it has weight=x, it's going to render as full screen view. Note that I am only talking about a crucial attribute, i.e., width in this case.

  • It is also very interesting to know how a view with weight is going to affect other views.

    • if another view has width = match_parent (and no weight attribute), that view is going to take the whole screen space, but this time our view WITH weight would not be squashed out. Instead, this gets the minimum space it should be getting (i.e., either wrap_content or the fixed value we passed for width=x). It would be like we added weight attribute to our chair and match_parent attribute to our bed. The bed squashed out all the other items, but the chair still took the space it requires.

Enter image description here

  • Something similar goes when other items has wrap_content as the values of their crucial attribute (but no weight attribute). This time, the view with weight is going to take all space, except the space required by other view (compare the below image with the first case, and notice how the circle is now taking all the remaining space without squashing the other views) Enter image description here

  • When every attribute has a weight, then this becomes a fun game of percentages. If we have two items, and every item has layout_weight=1, then no matter whatever their width is, both will take 50% of the space. If one of them has layout_weight=2, then distribution would be 2:1, i.e., 66%:33%. This makes the views responsive in different screen sizes and orientations.

Enter image description here


Thus, the best way to use children views in a Linear layout is to have wrap_content in their crucial dimension attribute and layout_weight=x. This will make it much responsive and easier to control. Also I did not talk much about having fixed weights in the crucial dimension attribute, because they are always a mess to handle. I won't get into details (you can try for yourself), but they will always end up either getting squashed or squashing other views.

Upvotes: 2

Related Questions