4

AlertDialog displays the content and buttons perfectly until the contents grow to the point that scrolling is required to display it all. At that point the buttons disappear, even though the list shows in its entirety.

I see that in years gone by this question was asked (this one is essentially identical to mine (DialogFragment buttons pushed off screen API 24 and above), but the answers all seemed hit or miss, haphazard even: setting layout_weight, switching from setMessage() to setTitle(), and finally switching away from AlertDialog to Dialog.

None of these are working form me, and avoiding AlertDialog is NOT an appealing option because I am using the setMultiChoiceItems() method that seems (incredibly to me, perhaps given my extremely limited knowledge) available only to AlertDialog.

Thus in desperation and frustration I appeal directly to the collective brains of stackoverflow.

This is a pared down version of my DialogFragment:

public class SurfaceDialog extends DialogFragment {
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {

        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
        LayoutInflater inflater = requireActivity().getLayoutInflater();
        builder.setView(inflater.inflate(R.layout.surface_dialog, null))
                .setTitle(mMessage)
                .setMultiChoiceItems(mSurfaceList, mCheckedSurfaces, new DialogInterface.OnMultiChoiceClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which, boolean isChecked) {
                        if (isChecked) {
                            mCheckedSurfacesPositions.add(which);
                        } else {
                            mCheckedSurfacesPositions.remove(mCheckedSurfacesPositions.indexOf(which));
                        }
                    }
                });

        // builder.setCancelable(false);
        builder.setPositiveButton("Done", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                ProcessDialogSelections(mCheckedSurfacesPositions);
                dismiss();
            }

        }).setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                listener.onSurfaceDialogSelectedSent(mUnitSurfaces);
                dismiss();
            }
        });

        return builder.create();
    }

That not working, I then coded my own buttons and displayed them:

    public Dialog onCreateDialog(Bundle savedInstanceState) {
        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
        LayoutInflater inflater = requireActivity().getLayoutInflater();
        View dialogView = inflater.inflate(R.layout.surface_dialog, null);
        builder.setView(dialogView)
                .setTitle(mMessage)

                .setMultiChoiceItems(mSurfaceList, mCheckedSurfaces, new DialogInterface.OnMultiChoiceClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which, boolean isChecked) {
                        if (isChecked) {
                            mCheckedSurfacesPositions.add(which);
                        } else {
                            mCheckedSurfacesPositions.remove(mCheckedSurfacesPositions.indexOf(which));
                        }
                    }
                });

        Button positiveButton = dialogView.findViewById(R.id.positive_button);
        Button negativeButton = dialogView.findViewById(R.id.negative_button);

        positiveButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                ProcessDialogSelections(mCheckedSurfacesPositions);
                dismiss();
            }
        });
        negativeButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                listener.onSurfaceDialogSelectedSent(mUnitSurfaces);
                dismiss();
            }
        });

        return builder.create();

    }

and here is my revised XML file

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

    <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="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        android:orientation="vertical">

    </ScrollView>


    <Button
        android:id="@+id/positive_button"
        android:layout_height="wrap_content"
        android:layout_marginBottom="30dp"
        android:layout_width="wrap_content"
        android:text="Done"
        app:layout_constraintBaseline_toBaselineOf="@+id/negative_button"
        app:layout_constraintEnd_toStartOf="@+id/negative_button"
        app:layout_constraintStart_toStartOf="parent" />

    <Button
        android:id="@+id/negative_button"
        android:layout_height="wrap_content"
        android:layout_marginBottom="30dp"
        android:layout_width="wrap_content"
        android:text="Cancel"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/positive_button" />

</androidx.constraintlayout.widget.ConstraintLayout>

And with THAT not working, I then followed the advice of Vikas Singh (AlertDialog Buttons not visible when using Custom layout). This is what the new code looks like (essentially creating the layout in Java rather than XML.

    public Dialog onCreateDialog(Bundle savedInstanceState) {

        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());

        // New code from Vikas Singh
        LinearLayout rootLayout = new LinearLayout(getActivity());
        rootLayout.setOrientation(LinearLayout.VERTICAL);
        ScrollView scrollView = new ScrollView(getActivity());
        LinearLayout layout = new LinearLayout(getActivity());
        layout.setOrientation(LinearLayout.VERTICAL);

        scrollView.addView(layout);
        rootLayout.addView(scrollView);
        builder.setNegativeButton("Cancel", null);
        builder.setPositiveButton("Go", null);
        builder.setView(rootLayout);

        builder//.setView(dialogView)
                //.setTitle(mMessage)

                .setMultiChoiceItems(mSurfaceList, mCheckedSurfaces, new DialogInterface.OnMultiChoiceClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which, boolean isChecked) {
                        if (isChecked) {
                            mCheckedSurfacesPositions.add(which);
                        } else {
                            mCheckedSurfacesPositions.remove(mCheckedSurfacesPositions.indexOf(which));
                        }
                    }
                });
        return builder.create();
    }

Still no buttons when I have to scroll. Why not and what can I do about it?

LameDoc
  • 111
  • 5

1 Answers1

0

Here is the solution:

public class SurfaceDialog extends DialogFragment {
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {

        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
        //LayoutInflater inflater = requireActivity().getLayoutInflater();
        builder
               //.setView(inflater.inflate(R.layout.surface_dialog, null)) didn't work
               // nor did setView with android.R.layout.select_dialog_multichoice
               // nor android.R.layout.simple_list_item_multiple_choice work
                .setTitle(mMessage)
                .setMultiChoiceItems(mSurfaceList, mCheckedSurfaces, new DialogInterface.OnMultiChoiceClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which, boolean isChecked) {
                        if (isChecked) {
                            mCheckedSurfacesPositions.add(which);
                        } else {
                            mCheckedSurfacesPositions.remove(mCheckedSurfacesPositions.indexOf(which));
                        }
                    }
                });

        // builder.setCancelable(false);
        builder.setPositiveButton("Done", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                ProcessDialogSelections(mCheckedSurfacesPositions);
                dismiss();
            }

        }).setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                listener.onSurfaceDialogSelectedSent(mUnitSurfaces);
                dismiss();
            }
        });

        return builder.create();
    }

The multiChoiceItems DialogFragment now works like a charm! All I had to do was simply comment out the above lines. As a result, there is no layout explicitly inflated, no view set. But it works nonetheless.

Now I would love it if someone could explain to me

  1. the details of why this works,
  2. why the other did not, and
  3. in light of the earlier failure, how could a custom layout be implemented to achieve this result of not losing the action buttons when the view scrolled
LameDoc
  • 111
  • 5