32

我正在开发一个材料设计应用程序。我想要实现的一个功能是某种民意调查。当用户单击列表的元素时,应该显示如下所示的持久底部工作表对话框:

带有问题和三个按钮的持久底部工作表对话框。

然后,当用户单击任何按钮时,该对话框应该消失,并且应该显示模态底部工作表对话框,为用户提供有关在开始时单击的列表项的更多信息。它看起来像这样:

单击其中一个按钮后显示的模态底部工作表对话框

即使在阅读了有关 AppCompat 对话框的一些信息之后,我也找不到关于 BottomSheetDialog 和 BottomSheetDialogFragment 以及如何正确使用它们的任何明确解释。所以,我的问题是:

  1. 它们有什么不同,每种情况我应该使用哪一种?
  2. 如何在活动中获取有关在对话框中按下了哪个按钮的数据?
  3. 有关使用它们的实现代码或教程的任何链接?
4

2 回答 2

20

最后,我找到了解决方案并且它有效。告诉我我是否做错了什么。它基本上像本指南中的 DialogFragment 一样工作,但我做了一些不同的事情。

1)它们的区别与DialogFragment和Dialog一样,都是模态的。如果您需要持久对话框,请改用BottomSheetBehaviour(我发现两个对话框在我的应用程序中都必须是模态的)。

2)我必须先用一些代码回答第三个问题,然后再回答第二个问题。

3) 创建一个新public class的,extends BottomSheetDialogFragment我称之为 FragmentRandomEventPoll。这里有两两件事必须实现。

  • 覆盖方法onCreateView。它与活动中的方法几乎相同onCreate,除了它返回它应该膨胀的视图:

    // 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)要在活动或任何其他地方获取输入事件,请定义具有必要方法的接口并为其实例创建setter方法:

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上找到。

于 2016-05-01T22:58:24.557 回答
2

关于处理来自 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>() }

当然,片段可以包含任意数量的其他片段,并且可能需要通过递归进行检查,但在我的情况下这是多余的。

于 2021-02-09T11:59:27.103 回答