【问题标题】:Get value from Bottom Sheet Dialog Fragment从底部工作表对话框片段中获取价值
【发布时间】:2018-09-22 11:59:37
【问题描述】:

我从片段 A 开始 bottomSheetDialogFragment。 我想从该bottomSheetDialogFragment中选择日期,然后将其设置在片段A中。

选择日期已经完成,我只是想在片段A中获取它以便在某些字段中设置它。

如何获得价值? 有什么建议吗?

【问题讨论】:

  • 分享你的代码
  • 创建一个接口。在 Fragment A 中实现该接口,然后在 BottomSheetDialog 中传递该接口的引用,当您更改日期时,在该方法中调用该接口方法并在方法参数中传递您的日期。现在你在 Fragment A 中有你的约会对象了。
  • 你能写一个例子吗?

标签: android fragment bottom-sheet dialogfragment


【解决方案1】:

像这样创建一个接口类

public interface CustomInterface {

    public void callbackMethod(String date);
}

在您的ActivityFragment 中实现此接口。并创建此接口的对象。

private CustomInterface callback;

onCreateonCreateView 中初始化它

callback=this;

现在,当您调用它时,在您的 BottomSheetDialogFragment 构造函数中传递此回调。

yourBottomSheetObject = new YourBottomSheet(callback);
yourBottomSheetObject.show(getSupportFragmentManager()," string");

现在在您的 BottomSheetFragment 的构造函数中

私有 CustomInterface 回调;

public SelectStartTimeSheet(CustomInterface callback){

this.callback=callback;

}

最后使用这个回调对象来设置你的日期

callback.callbackMethod("your date");

您将在您的 Fragment 或 callbackMethod 函数中的 Activity 中收到此日期。

【讨论】:

  • 这对我不起作用。当我在bottomsheetfragment中创建一个带有参数的构造函数时,它会抛出一个警告说“避免片段中的非默认构造函数”......任何解决方法?谢谢
  • 只需将这一行 @SuppressLint("ValidFragment") 放在你的类名上
  • 不要压制,可以这样做:fragment.setCallbackListener(listener)。但是,如果您从片段或活动中调用,这仍然不是首选方式。例如,在片段的情况下,您可以使用 getTargetFragment()
  • @AndreaAranguren 使用 getTargetFragment 提供了更好的解决方案。这应该是选择的答案
【解决方案2】:

如文档所述,覆盖片段的构造函数是一种不好的做法:

每个片段必须有一个 * 空的构造函数,所以在恢复它的时候可以实例化 * 活动的状态。

如果您使用另一个将回调作为参数传递的构造函数,则当框架恢复片段时,您的应用会崩溃

推荐的方式是使用 viewModel 和 livedata。

【讨论】:

    【解决方案3】:

    Android 导航架构组件

    例如:

    假设您使用 navController 从 Fragment A 打开 Fragment B。

    并且您想要从片段 B 到片段 A 的一些数据。

    class B :BottomSheetDialogFragment() {
    
    override fun onCreateView(
            inflater: LayoutInflater, container: ViewGroup?,
            savedInstanceState: Bundle?
        ): View? {
            val root = inflater.inflate(R.layout.your_layout, container, false)
    
            root.sampleButton.setOnClickListener {
                val navController = findNavController()
                navController.previousBackStackEntry?.savedStateHandle?.set("your_key", "your_value")
                dismiss()
    
            }
    }
    

    在您的片段 A 中:

    findNavController().currentBackStackEntry?.savedStateHandle?.getLiveData<String>("your_key")
                    ?.observe(viewLifecycleOwner) {
        
                        if (it == "your_value") {
                            //your code
        
                        }
        
                    }
    

    【讨论】:

      【解决方案4】:

      你可以使用如下方式:

      选择帐户片段代码

      
      class SelectAccountFragment(val clickListener: OnOptionCLickListener) : BottomSheetDialogFragment() {
      
      
          override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
              return inflater.inflate(R.layout.bottom_fragment_accounts, container, false)
          }
      
      
      
          override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
              super.onViewCreated(view, savedInstanceState)
      
              val list = DataProcessorApp(context).allUsers
      
              val rvAccounts = view.findViewById<RecyclerView>(R.id.rvAccounts)
      
              rvAccounts.layoutManager = LinearLayoutManager(context)
              rvAccounts.adapter = AccountsAdapter(context, list)
      
              Log.e(tag,"Accounts "+list.size);
      
              tvAccountAdd.setOnClickListener {
                  val intent = Intent(context,LoginActivity::class.java)
                  startActivity(intent)
              }
      
              tvManageAccounts.setOnClickListener {
                  Log.e(tag,"Manage Click")
                  clickListener.onManageClick()
              }
          }
      
      
          interface OnOptionCLickListener{
              fun onManageClick()
          }
      
      }
      
      
      

      现在显示并回调到另一个片段/活动,如下所示

       SelectAccountFragment accountFragment = new SelectAccountFragment(() -> {
      
                //get fragment by tag and dismiss it
      
                BottomSheetDialogFragment fragment = (BottomSheetDialogFragment) getChildFragmentManager().findFragmentByTag(SelectAccountFragment.class.getSimpleName();
                if (fragment!=null){
                     fragment.dismiss();
                }
      
      });
      
      accountFragment.show(getChildFragmentManager(),SelectAccountFragment.class.getSimpleName());
      

      【讨论】:

        【解决方案5】:

        如果您使用的是 BottomSheetDialogFragment ,因为它是一个片段,您应该创建您的接口并在片段的 onAttach 生命周期方法中绑定到它,对您的侦听器/回调类型进行适当的活动引用。

        在你的活动中实现这个接口,并在有人点击片段的内部recyclerview项目时调度更改,例如

        这是一个众所周知的模式,在 here 上有更好的解释

        一个重要的建议是重新考虑您的应用架构,因为最好的方法是始终通过 Bundle 在 Android 组件之间传递原始/简单/微小数据,并且您的组件稍后能够检索所需的状态及其依赖项。

        例如,您永远不应传递位图、数据类、DTO 或视图引用等大型对象。

        • 首先,Parcel 正在进行一些序列化过程,这会影响应用程序的响应能力
        • 其次,它会导致您出现TransactionTooLarge 类型的错误。

        希望有帮助!

        【讨论】:

          【解决方案6】:

          您也可以使用LocalBroadcastManager。正如 hglf 所说,如果您仍想使用接口回调方式,最好保留片段的空构造函数并使用 newInstance(Type value) 来实例化片段。

          【讨论】:

            【解决方案7】:

            您可以使用Navigation 库的好处:

            override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
                super.onViewCreated(view, savedInstanceState)
                val navController = findNavController();
                // After a configuration change or process death, the currentBackStackEntry
                // points to the dialog destination, so you must use getBackStackEntry()
                // with the specific ID of your destination to ensure we always
                // get the right NavBackStackEntry
                val navBackStackEntry = navController.getBackStackEntry(R.id.your_fragment)
            
                // Create our observer and add it to the NavBackStackEntry's lifecycle
                val observer = LifecycleEventObserver { _, event ->
                    if (event == Lifecycle.Event.ON_RESUME
                        && navBackStackEntry.savedStateHandle.contains("key")) {
                        val result = navBackStackEntry.savedStateHandle.get<String>("key");
                        // Do something with the result
                    }
                }
                navBackStackEntry.lifecycle.addObserver(observer)
            
                // As addObserver() does not automatically remove the observer, we
                // call removeObserver() manually when the view lifecycle is destroyed
                viewLifecycleOwner.lifecycle.addObserver(LifecycleEventObserver { _, event ->
                    if (event == Lifecycle.Event.ON_DESTROY) {
                        navBackStackEntry.lifecycle.removeObserver(observer)
                    }
                })
            }
            

            欲了解更多信息,请阅读the document

            【讨论】:

              【解决方案8】:

              接受的答案是错误的。

              你可以做的只是调用 show() 时用户 Fragment A 的 childFragmentManager。

              像这样:

              val childFragmentManager = fragmentA.childFragmentManager
              bottomSheetDialogFragment.show(childFragmentManager, "dialog") 
              

              【讨论】:

                猜你喜欢
                • 2020-08-02
                • 2020-05-15
                • 2020-02-28
                • 1970-01-01
                • 2021-12-02
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多