SharedViewModel from viewpager2 and my parent Fragment - android

So, I have one fragment, lets call it Fragment A, in which I need it to be the main host of my sharedviewmodel.
So I have it like this
class FragmentA:Fragment() {
private val model: SharedViewModel by viewModels()
}
Now, inside Fragment A, I set viewpager2 Adapter
private fun setupViewPagerWithTabLayout(
productList: MutableList<Producto>,
drinkList: MutableList<Producto>
) {
val fragmentList = listOf(
FragmentProducts.newInstance(productList),
FragmentProducts.newInstance(drinkList))
viewPager2.adapter = MyViewPageAdapter(requireActivity(),fragmentList)
val tabLayoutMediator = TabLayoutMediator(tabLayout, viewPager2,
TabLayoutMediator.TabConfigurationStrategy { tab, position ->
when (position) {
0 -> {
tab.text = "Option1"
}
1 -> {
tab.text = "Option2"
}
}
})
tabLayoutMediator.attach()
}
Here I instantiate my FragmentProduct which is inside Fragment A in a viewpager, but my adapter needs a FragmentActivity
class MyViewPageAdapter(fragmentActivity: FragmentActivity,private val fragmentList: List<FragmentProducts>) :
FragmentStateAdapter(fragmentActivity) {
override fun getItemCount(): Int {
return fragmentList.size
}
override fun createFragment(position: Int): Fragment {
return fragmentList[position]
}
}
So, from FragmentProducts that is contained inside FragmentA, I need to share data with this viewmodel, but when I do this to share data from this fragment to FragmentA
class FragmentProducts:Fragment(){
private val model: SharedViewModel by viewModels ({requireParentFragment()})
}
I get the followin error
java.lang.IllegalStateException: Fragment FragmentProducts{6953da8}
(3a2f5cbb-113d-4ed2-8f85-56e04fcea356) f0} is not a child Fragment, it
is directly attached to com.example.MainActivity#dcc2679
so , this is telling me that FragmentProducts references to my MainActivity, and thats logic because the instance of the adapter takes requireActivity() for FragmentActivity at
viewPager2.adapter = MyViewPageAdapter(requireActivity(),fragmentList)
So, I need to pass instead of requireActivity() my FragmentA as the host of this viewpager fragment but at my ViewPagerAdapter, I cant pass FragmentStatePagerAdapter or something else to pass my FragmentA as the context for that viewpager
Since Im using viewpager2, is there a way to let FragmentA host FragmentProducts viewpager so I can get it in my FragmentProducts like this
private val model: SharedViewModel by viewModels ({requireParentFragment()})
Thanks

You're using FragmentStateAdapter(fragmentActivity). Don't do that. Pass your parent Fragment to MyViewPageAdapter and pass that to FragmentStateAdapter.
class MyViewPageAdapter(
parentFragment: Fragment,
private val fragmentList: List<FragmentProducts>
) : FragmentStateAdapter(parentFragment) {

Related

Why are all fragments affected when data is updated by using viewpager2?

I'm using viewpager 2 now.
The views of the fragments are all the same, so I'm using the same fragments.
And the data is shown through recyclerview in the fragment.
All fragments set different data list.
OnResume retrieves new data through a network call and performs recyclerviewAdapter.submitlist.
It shows the same data view during swiping.
If onResume does not update the data, it shows a different view during swiping.
class CommunityViewPagerAdapter(
fragmentManager: FragmentManager,
lifecycle: Lifecycle,
) : FragmentStateAdapter(fragmentManager, lifecycle) {
private val fragments = listOf(
TechCommunityFragment.newInstance("Backend"),
TechCommunityFragment.newInstance("Frontend"),
TechCommunityFragment.newInstance("Android"),
TechCommunityFragment.newInstance("IOS"),
TechCommunityFragment.newInstance("DataScience"),
TechCommunityFragment.newInstance("DataAnalysis"),
TechCommunityFragment.newInstance("Algorithm"),
TechCommunityFragment.newInstance("DataStructure"),
TechCommunityFragment.newInstance("Network"),
TechCommunityFragment.newInstance("OperatingSystem"),
)
override fun getItemCount(): Int {
return fragments.size
}
override fun createFragment(position: Int): Fragment {
return fragments[position]
}
}
private fun initView() = with(binding) {
viewPager.adapter= CommunityViewPagerAdapter(childFragmentManager, lifecycle)
TabLayoutMediator(techTablayout, viewPager) { tab, position ->
tab.text = mainTabArray[position]
}.attach()
}
override fun onResume() {
super.onResume()
techStack = arguments?.getString(TECH_STACK) ?: ""
callAPI()
}

RecyclerView in ViewPager2 redraws content after fragment with ViewPager navigates to another fragment

What i have: Application with BottomNavigation using Android Navigation Component. One of fragments - fragment with other two fragments with recyclerviews in viewPager2. When i navigating to another tab and go back, recyclerview is fully redrawing content
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
binding.schedulePager.apply {
isSaveFromParentEnabled = true
offscreenPageLimit = 2
adapter = ScheduleViewPager(childFragmentManager, lifecycle)
setPageTransformer(ZoomOutPageTransformer())
}
... other stuff
}
class ScheduleViewPager(
fragmentManager: FragmentManager,
lifecycle: Lifecycle
) : FragmentStateAdapter(fragmentManager,lifecycle) {
override fun getItemCount(): Int = 2
override fun createFragment(position: Int): Fragment = PageFragment().apply { arguments = SchedulePageFragmentArgs.bundle(position) }
}
if i'm using FragmentActivity instead of FragmentManager, content in fragments is not redrawing, but i need to use FragmentManager fof access ViewModel from fragment with viewPager
class PageFragment : BaseFragment<FragmentPageBinding>(), SharedPreferences.OnSharedPreferenceChangeListener {
private val viewModel: ScheduleViewModel by viewModels({requireParentFragment()})

How to get Current Fragment in ViewPager2 [duplicate]

This question already has answers here:
Get current fragment with ViewPager2
(18 answers)
Closed 1 year ago.
i used this ViewPager2 dependency:
implementation 'androidx.viewpager2:viewpager2:1.0.0'
then i wrote code and make Adapter for FragmentStateAdapter like below:
private inner class ViewPagerAdapter(fragmentManager: FragmentManager,
lifecycle: Lifecycle, config: TribunConfig?)
: FragmentStateAdapter(fragmentManager, lifecycle) {
private val config: TribunConfig?
override fun createFragment(position: Int): Fragment {
return TribunNewsFragment.newInstance(if (menuTribun!!.get(position) == "News") "home"
else menuTribun!!.get(position)!!.replace(" ", "").toLowerCase(), config)!!
}
override fun getItemCount(): Int {
return menuTribun!!.size
}
init {
this.config = config
}
}
an in method onCreate i implement some code related viewpager2 and its adapter like below:
viewPager2!!.offscreenPageLimit = 1
viewPager2!!.adapter = ViewPagerAdapter(supportFragmentManager, lifecycle, config)
TabLayoutMediator(tabLayout!!, viewPager2!!, TabLayoutMediator.TabConfigurationStrategy { tab: TabLayout.Tab?, position: Int -> tab!!.text = menuTribun!!.get(position) }).attach()
But i have problem when i want to make swipeRefresh. My swipeRefresh needs current fragment to access the method inside fragment. But there is NO METHOD getItem in FragmentStateAdapter. Anyone can help me?
Create property in your adapter to save all your fragments
Save current position
Get fragment from fragment list (property) by position when you need it
Something like this:
val fragments: MutableList<Fragment> = mutableListOf()
private val config: TribunConfig?
override fun createFragment(position: Int): Fragment {
val fragment = TribunNewsFragment.newInstance(if (menuTribun!!.get(position) == "News") "home"
else menuTribun!!.get(position)!!.replace(" ", "").toLowerCase(), config)!!
fragments.add(fragment)
return fragment
}
Parent:
yourTabLayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
override fun onTabSelected(tab: TabLayout.Tab?) {
val fragment = adapter.fragments[tab!!.position]
// cast fragment to your fragment class and do what you want
}
override fun onTabUnselected(tab: TabLayout.Tab?) {
}
override fun onTabReselected(tab: TabLayout.Tab?) {
}
})
Also you can use when or if-else for your fragments position or create base class with methods you need and cast getting fragment to it.
Following #Oleg's answer, you can access the Fragments like this in your Adapter instead of creating a local list and adding each fragment on createFragment method:
private val fragmentList: List<TribunNewsFragment>
get() {
return fragment.childFragmentManager.fragments.filterIsInstance<TribunNewsFragment>()
}
It's important to use childFragmentManager instead of fragmentManager if you are creating the ViewPager inside another fragment.
And it survives configuration changes, regarding #lawonga's comment on the answer's topic.

Is it possible to addtoBackStack(null) in PagerAdapter?

I have a Pager Adapter to load server images as like below:
class ImagePagerAdapter(var imageList: List<ProductImageModel>, var fragmentManager: FragmentManager) :
FragmentPagerAdapter(fragmentManager) {
override fun getItem(position: Int): Fragment {
val fragment = ImagePagerFragment()
fragment.arguments = Bundle().apply {
putString(PAGER_IMAGE_URL, imageList[position].image)
}
return fragment
}
override fun getCount(): Int {
return imageList.size
}
}
I want to know any option to addtoBackStack(null) while creating a new Fragment inside the pagerAdapter.
The current code, automatically adding the fragments to the backstack. So it's making a huge issue while the user presses the back button. I have added another logic to filter the fragments in the back press.

FragmentManager in kotlin not recognized

I want in my application to set A viewPager and pager adapter, but I cant implement it because I cant use fragmentManager.
i get the following err:
"Error:(45, 38) Classifier 'FragmentManager' does not have a companion object, and thus must be initialized here"
my code is:
import android.support.v4.app.Fragment
import android.support.v4.app.FragmentManager
private lateinit var pagerAdapter: mPagerAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main2)
pagerAdapter = mPagerAdapter(FragmentManager) // err is here
viewPager.adapter = pagerAdapter
}
class mPagerAdapter(fragmentManager: FragmentManager) :
FragmentStatePagerAdapter(fragmentManager) {
// 2
override fun getItem(position: Int): Fragment {
when (position) {
0 -> return Tab1() as Fragment
1 -> return Tab2() as Fragment
2 -> return Tab3() as Fragment
}
return Tab1() as Fragment
}
// 3
override fun getCount(): Int {
return 3
}
}
what should I do to solve this?
FragmentManager is the class name. fragmentManager, with a lowercase 'f', is the property reference to the getFragmentManager() method.
You want to instead use supportFragmentManager (as getFragmentManager() returns the Framework FragmentManager, not the Support Library FragmentManager):
pagerAdapter = mPagerAdapter(supportFragmentManager)

Categories

Resources