BottomSheetDialog/BottomSheetDialogFragment — which to use and how?

Gleb Sabirzyanov picture Gleb Sabirzyanov · Apr 19, 2016 · Viewed 15k times · Source

I'm working on a Material design app. One feature I want to implement is some kind of a poll. When a user clicks an element of a list, the persistent bottom sheet dialog, which looks like this should show up:

Persistent bottom sheet dialog with question and three buttons.

Then, when user clicks any button, this dialog should go away and the modal bottom sheet dialog should show up, providing a user with more information about the list item which was clicked at the beginning. It looks like this:

A modal bottom sheet dialog which shows up after one of the buttons is clicked

I can't find any clear explanations about BottomSheetDialog and BottomSheetDialogFragment, and how to use them correctly, even after reading some information about AppCompat dialogs. So, my questions are:

  1. In what way are they different and which one should I use for each case?
  2. How to get data in the activity about which button was pressed in the dialog?
  3. Any links to the code of implementations or tutorials about using them?

Answer

Gleb Sabirzyanov picture Gleb Sabirzyanov · May 2, 2016

Finally, I've found the solution and it works. Tell me if I'm doing something wrong. It basically works like DialogFragment from this guide, but I've done it a bit different.

1) Their difference is the same as it of DialogFragment and Dialog, and they both are modal. If you need persistent dialog, use BottomSheetBehaviour instead (I found out that both dialogs had to be modal in my app).

2) I have to answer the third question with some code first, and then it will be easy to answer the second one.

3) Create a new public class, which extends BottomSheetDialogFragment, I called it FragmentRandomEventPoll. There are two two things which have to be implemented here.

  • Override method onCreateView. It is nearly the same as onCreate method in Activities, except for that it returns the View it should inflate:

    // We will need it later
    private static String headerItem;
    
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                 Bundle savedInstanceState) {
    
    View v = inflater.inflate(R.layout.fragment_random_event_poll, container, false);
        header = (TextView) v.findViewById(R.id.uRnd_fragment_bottom_sheet_poll_header);
        skip = (Button) v.findViewById(R.id.uRnd_fragment_bottom_sheet_button_skip);
        header.setText(...);
    
        // I implemented View.OnClickListener interface in my class
        skip.setOnClickListener(this);
        return v;
    }
    
  • Static method which you can pass necessary data to and get new instance of this class (Probably I could have just used a regular constructor, I'll have to experiment with it a bit more). URandomEventListItem is the data model class.

    public static FragmentRandomEventPoll newInstance(URandomEventListItem item) {
        FragmentRandomEventPoll fragment = new FragmentRandomEventPoll();
        headerItem = item.getHeader();
        return fragment;
    } 
    

2) To get input events in activity or any other place, define an interface with necessary methods and create setter method for it's instance:

private PollButtonClickListener listener;

public void setListener(PollButtonClickListener listener) {
    this.listener = listener;
}

public interface PollButtonClickListener {
    void onAnyButtonClick(Object data)
}

And in the place you want to get your data ("dialog_event_poll" tag was specified in the layout):

FragmentRandomEventPoll poll = FragmentRandomEventPoll.newInstance(events.get(id));
poll.setListener(new FragmentRandomEventPoll.PollButtonClickListener() {
        @Override
        public void onAnyButtonClick(Object data) {
            // Do what you want with your data
        }
    });
    poll.show(getSupportFragmentManager(), "dialog_event_poll");
}

If there is anything unclear, my project files could be found on Github.