BottomSheetDialog/BottomSheetDialogFragment — что использовать и как?

Я работаю над приложением для дизайна материалов. Одна функция, которую я хочу реализовать, — это своего рода опрос. Когда пользователь щелкает элемент списка, должно появиться постоянное диалоговое окно нижнего листа, которое выглядит следующим образом:

Постоянный диалог нижнего листа с вопросом и тремя кнопками.

Затем, когда пользователь нажимает любую кнопку, это диалоговое окно должно исчезнуть, и должно появиться модальное диалоговое окно нижнего листа, предоставляющее пользователю дополнительную информацию об элементе списка, который был нажат в начале. Это выглядит так:

Модальное диалоговое окно нижнего листа, которое появляется после нажатия одной из кнопок

Я не могу найти каких-либо четких объяснений о BottomSheetDialog и BottomSheetDialogFragment и о том, как их правильно использовать, даже после прочтения некоторой информации о диалогах AppCompat. Итак, мои вопросы:

  1. Чем они отличаются и какой из них я должен использовать для каждого случая?
  2. Как получить в активности данные о том, какая кнопка была нажата в диалоге?
  3. Любые ссылки на код реализаций или учебные пособия по их использованию?

person Gleb Sabirzyanov    schedule 19.04.2016    source источник


Ответы (2)


Наконец, я нашел решение, и оно работает. Скажи мне, если я делаю что-то не так. В основном он работает как DialogFragment из этого руководства, но я сделал немного по другому.

1) Их разница такая же, как у DialogFragment и Dialog, и оба они модальные. Если вам нужен постоянный диалог, используйте BottomSheetBehaviour вместо него (Я узнал, что оба диалога должны быть модальными в моем приложении).

2) Я должен сначала ответить на третий вопрос с помощью некоторого кода, а затем будет легко ответить на второй.

3) Создайте новый public class, который extends BottomSheetDialogFragment, я назвал его FragmentRandomEventPoll. Здесь нужно реализовать две вещи.

  • Переопределить метод onCreateView. Это почти то же самое, что и метод onCreate в Activity, за исключением того, что он возвращает View, который он должен раздувать:

    // 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;
    }
    
  • Статический метод, которому вы можете передать необходимые данные и получить новый экземпляр этого класса (возможно, я мог бы просто использовать обычный конструктор, мне придется еще немного поэкспериментировать с ним). URandomEventListItem — это класс модели данных.

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

2) Чтобы получить входные события в активности или любом другом месте, определите интерфейс с необходимыми методами и создайте метод установки для его экземпляра:

private PollButtonClickListener listener;

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

public interface PollButtonClickListener {
    void onAnyButtonClick(Object data)
}

И в том месте, где вы хотите получить свои данные (в макете был указан тег «dialog_event_poll»):

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");
}

Если что-то непонятно, файлы моего проекта можно найти на Github.

person Gleb Sabirzyanov    schedule 01.05.2016
comment
Вместо того, чтобы устанавливать прослушиватель таким образом (который, я думаю, будет отключен, если действие будет воссоздано), вы должны использовать шаблон обратного вызова (подробнее об этом на этом страница для разработчиков Android), что позволит избежать этой проблемы. Остальное круто. Это помогло мне реализовать диалог нижнего листа. Спасибо :) - person Sufian; 29.05.2020

Об обработке событий из DialogFragment/BottomSheetDialogFragment.

Для приложений с большим количеством действий этот метод отлично подходит:

context as MyDialogFragmentListener

Но у меня проблема с приложением с одной активностью и несколькими фрагментами. Так как фрагментов может быть очень много, кажется очень плохим вариантом передавать все события в нужные фрагменты через основную активность. Поэтому я решил сделать так:

  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
}

Код в DialogFragment:

  private val listeners by lazy { findListeners<MyDialogFragmentListener>() }

Конечно, фрагменты могут содержать сколько угодно других фрагментов и, вероятно, их нужно проверять через рекурсию, но в моем случае это лишнее.

person Pavel Shirokov    schedule 09.02.2021