BottomSheetDialog/BottomSheetDialogFragment — which to use and how?
About handling events from DialogFragment/BottomSheetDialogFragment.
For applications with many activities, this method is great:
context as MyDialogFragmentListener
But I have a problem with an application with single activity and multiple fragments. Since there can be a lot of fragments, it seems like a very bad option to transfer all events to the necessary fragments through the main activity. Therefore, I decided to do this:
private inline fun <reified T> findListeners(): ArrayList<T> {
val listeners = ArrayList<T>()
context?.let {
if (it is T) listeners.add(it)
if (it is AppCompatActivity) {
it.supportFragmentManager.fragments.forEach { fragment ->
if (fragment is T) listeners.add(fragment)
fragment.childFragmentManager.fragments.forEach { childFragment ->
if (childFragment is T) listeners.add(childFragment)
}
}
}
}
return listeners
}
Code in DialogFragment:
private val listeners by lazy { findListeners<MyDialogFragmentListener>() }
Of course, fragments can contain as many other fragments as you like and probably need to be checked through recursion, but in my case this is superfluous.
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 asonCreate
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.