When trying to inflate and set my presenter to my databinding component in this way my presenter methods are not called.
val fragmentBinding = FragmentListEditBinding.inflate(layoutInflater)
fragmentBinding.presenter = ListEditorPresenter(this, requireContext())
but when using this
val fragmentBinding = DataBindingUtil.setContentView<FragmentListEditBinding(requireActivity(), R.layout.fragment_list_edit)
fragmentBinding.presenter = ListEditorPresenter(this, requireContext())
It works fine, but then the layout is covering the full screen.
Any ideas how to fix this issue?
Please tell me if more context is needed.
The second method is for activity, not for the fragment, For fragment, you have to do it in the first method.
Before DataBinding and ViewBinding, In and activity we call setContentView(R.layout.activity_main) to set the view for the activity, but for fragment, we override the onCreateView method and inflate a view and return it.
So the way of setting view for activity and fragment is different from the beginning.
So the DataBindingUtil.setContentView is made for activity, while the FragmentListEditBinding.inflate custom/manual inflation is made for fragment. As i have already mentioned it above.
Related
I'm using navigation component and want to connect drawer layout with toolbar in each fragment, not the activity.
I tried this answer which is called on onViewCreated() but any view referenced from the activity is null. I guess it's because fragment is inflated in the layout before returning from the activity's onCreate method.
I use this extension function to connect the drawer with the fragment's toolbar, I tried to call it from onCreateView() and onViewCreated() but did't work and the activity's drawer layout is always null. I works only if it's called from onStart() but I don't think it's the right way:
private fun AppCompatActivity.setToolbar() {
setSupportActionBar(binding.toolbar)
setHasOptionsMenu(true)
val drawer = findViewById<DrawerLayout>(R.id.drawer)
binding.toolbar.setupWithNavController(findNavController(), drawer)
}
What's the right place to call this function?
When you call setContentView(R.id.activity_layout), the entire view hierarchy is first inflated, then attached to the Activity. It is only after setContentView() returns that findViewById() will find any of the newly inflated views.
When you use the <fragment> tag, the Fragment's view and the views of all of its child fragments are synchronously created as part of that inflation call. This means that setContentView() has not completed by the time the onCreateView() and onViewCreated() methods are called. This is why that calling findViewById() returns null - the activity's view hasn't actually finished being created.
FragmentContainerView was specifically built to avoid these special cases and instead use the same mechanisms as other fragments - namely, it just uses a normal FragmentTransaction to add your Fragment - the same as if you called beginTransaction()+commitNow() in your onCreate() method yourself. This means that the Fragment is not forced to synchronously create its view as part of setContentView(), but can do it alongside every other Fragment after setContentView() returns. This is what allows findViewById() from onCreateView() or onViewCreated() work.
You can achieve this by simply using an interface which you need to implement in activity. No need to reference activity's drawerLayout from fragment.
Interface like this:
interface DrawerWithToolbar {
fun setupToolbarDrawer(toolbar: MaterialToolbar)
}
Then in activity:
override fun setupToolbarDrawer(toolbar: MaterialToolbar) {
toolbar.setupWithNavController(navController,drawerLayout)
}
In fragment:
(activity as DrawerWithToolbar).setupToolbarDrawer(toolbar)
I'm using navigation component and want to connect drawer layout with toolbar in each fragment, not the activity.
I tried this answer which is called on onViewCreated() but any view referenced from the activity is null. I guess it's because fragment is inflated in the layout before returning from the activity's onCreate method.
I use this extension function to connect the drawer with the fragment's toolbar, I tried to call it from onCreateView() and onViewCreated() but did't work and the activity's drawer layout is always null. I works only if it's called from onStart() but I don't think it's the right way:
private fun AppCompatActivity.setToolbar() {
setSupportActionBar(binding.toolbar)
setHasOptionsMenu(true)
val drawer = findViewById<DrawerLayout>(R.id.drawer)
binding.toolbar.setupWithNavController(findNavController(), drawer)
}
What's the right place to call this function?
When you call setContentView(R.id.activity_layout), the entire view hierarchy is first inflated, then attached to the Activity. It is only after setContentView() returns that findViewById() will find any of the newly inflated views.
When you use the <fragment> tag, the Fragment's view and the views of all of its child fragments are synchronously created as part of that inflation call. This means that setContentView() has not completed by the time the onCreateView() and onViewCreated() methods are called. This is why that calling findViewById() returns null - the activity's view hasn't actually finished being created.
FragmentContainerView was specifically built to avoid these special cases and instead use the same mechanisms as other fragments - namely, it just uses a normal FragmentTransaction to add your Fragment - the same as if you called beginTransaction()+commitNow() in your onCreate() method yourself. This means that the Fragment is not forced to synchronously create its view as part of setContentView(), but can do it alongside every other Fragment after setContentView() returns. This is what allows findViewById() from onCreateView() or onViewCreated() work.
You can achieve this by simply using an interface which you need to implement in activity. No need to reference activity's drawerLayout from fragment.
Interface like this:
interface DrawerWithToolbar {
fun setupToolbarDrawer(toolbar: MaterialToolbar)
}
Then in activity:
override fun setupToolbarDrawer(toolbar: MaterialToolbar) {
toolbar.setupWithNavController(navController,drawerLayout)
}
In fragment:
(activity as DrawerWithToolbar).setupToolbarDrawer(toolbar)
I have 1 activity which contains parent fragment. Inside the parent fragment is 2 child fragments. I want to only create one viewmodel instance and use it in both child fragment.
This is my code in parent fragment:
val factory = ViewModelFactory.getInstance(requireContext())
viewModel = ViewModelProvider(this, factory)[FavoriteViewModel::class.java]
And this one in child fragment:
viewModel = (requireParentFragment() as FavoriteParentFragment).viewModel // force close
It force close without error in logcat.
When i try to move the parent fragment's code to the activity (without changing the code) and change the child fragment's code to:
viewModel = (activity as MainActivity).viewModel // works
It works.
So is it possible to do the first method (that is force closed)? If so, how to do that properly and why i did not get any logcat error.
Instead of trying to access the viewmodel from the parent directly, use the scope of the parent to get a shared viewmodel.
Inside your child fragments, use this code
val factory = ViewModelFactory.getInstance(requireContext())
val viewModel = ViewModelProvider(requireParentFragment(), factory).get(FavoriteViewModel::class.java)
Using the above code, you no longer need to store an instance of the viewmodel in the parent fragment.
I'm using navigation component and want to connect drawer layout with toolbar in each fragment, not the activity.
I tried this answer which is called on onViewCreated() but any view referenced from the activity is null. I guess it's because fragment is inflated in the layout before returning from the activity's onCreate method.
I use this extension function to connect the drawer with the fragment's toolbar, I tried to call it from onCreateView() and onViewCreated() but did't work and the activity's drawer layout is always null. I works only if it's called from onStart() but I don't think it's the right way:
private fun AppCompatActivity.setToolbar() {
setSupportActionBar(binding.toolbar)
setHasOptionsMenu(true)
val drawer = findViewById<DrawerLayout>(R.id.drawer)
binding.toolbar.setupWithNavController(findNavController(), drawer)
}
What's the right place to call this function?
When you call setContentView(R.id.activity_layout), the entire view hierarchy is first inflated, then attached to the Activity. It is only after setContentView() returns that findViewById() will find any of the newly inflated views.
When you use the <fragment> tag, the Fragment's view and the views of all of its child fragments are synchronously created as part of that inflation call. This means that setContentView() has not completed by the time the onCreateView() and onViewCreated() methods are called. This is why that calling findViewById() returns null - the activity's view hasn't actually finished being created.
FragmentContainerView was specifically built to avoid these special cases and instead use the same mechanisms as other fragments - namely, it just uses a normal FragmentTransaction to add your Fragment - the same as if you called beginTransaction()+commitNow() in your onCreate() method yourself. This means that the Fragment is not forced to synchronously create its view as part of setContentView(), but can do it alongside every other Fragment after setContentView() returns. This is what allows findViewById() from onCreateView() or onViewCreated() work.
You can achieve this by simply using an interface which you need to implement in activity. No need to reference activity's drawerLayout from fragment.
Interface like this:
interface DrawerWithToolbar {
fun setupToolbarDrawer(toolbar: MaterialToolbar)
}
Then in activity:
override fun setupToolbarDrawer(toolbar: MaterialToolbar) {
toolbar.setupWithNavController(navController,drawerLayout)
}
In fragment:
(activity as DrawerWithToolbar).setupToolbarDrawer(toolbar)
Hello i create class that implement BottomSheetDialogFragment with dynamic content. The content is a Fragment. So when initialize the BottomSheet i passing fragment object, and attach it to specific Container ID inside this BottomSheetDialogFragment. Looks like this :
private fun attachContentFragment() {
val transaction = childFragmentManager.beginTransaction()
transaction.apply {
replace(R.id.flContent, state.layoutContent)
commit()
}
}
state.layoutContent is my attached Fragment
I need to dismiss the BottomSheet if every action called in that fragment.
As far as i know, i need to get the object of BottomSheet that hold me(Fragment) and dismiss it.
But how i can get that BottomSheet object?
Thanks
So, technically it is a fragment inside fragment situation. I think there is several solutions here:
Call Activity from your child fragment. BottomSheetDialogFragment will subscribe to Activity for such events and react on them.
Get the instance of a BottomSheetDialogFragment by calling proper FragmentManager (which possible is an Activity one). You can get an instance of a fragment byTag for example.
Or you can call getParentFragment from a child Fragment.