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)
Related
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.
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) {
I have an Activity with a ViewPager containing Fragments that are summoned with custom buttons. Currently, my custom adapter's getItem method is being called, but the pager is going blank rather than going to the new fragment
Here is my adapter :
class ScreenSlidePagerAdapter(fragmentManager: FragmentManager) : FragmentStatePagerAdapter(fragmentManager) {
private val NUM_FRAGMENTS = 2
override fun getCount(): Int = NUM_FRAGMENTS
override fun getItem(position: Int): Fragment {
var fragment: Fragment = WelcomeFragment.newInstance()
when (position) {
0 -> fragment = WelcomeFragment.newInstance()
1 -> fragment = LanguageSelectFragment.newInstance()
}
println(position)
return fragment
}
}
Here is the method that gets called on button click. The views are given a tag corresponding to their Fragment's position in the adapter, and this is retrieved on click to pull up the right fragment.
private fun switchScreens(view: View) {
val fragment = mPagerAdapter.getItem(view.getTag().toString().toInt())
val fragmentManager = supportFragmentManager
val fragmentTransaction = fragmentManager.beginTransaction()
fragmentTransaction.replace(R.id.main_view_pager, fragment)
fragmentTransaction.commit()
}
And my fragment:
class LanguageSelectFragment : Fragment() {
private var listener: OnFragmentInteractionListener? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_language_select, container, false)
}
fun onButtonPressed(uri: Uri) {
listener?.onFragmentInteraction(uri)
}
override fun onAttach(context: Context) {
super.onAttach(context)
if (context is OnFragmentInteractionListener) {
listener = context
} else {
}
}
override fun onDetach() {
super.onDetach()
listener = null
}
interface OnFragmentInteractionListener {
fun onFragmentInteraction(uri: Uri)
}
companion object {
#JvmStatic
fun newInstance() =
LanguageSelectFragment().apply {
arguments = Bundle().apply {
}
}
}
}
Do you have a ViewPager container for your framgents ?
If yes, that's not the way to use the pagerAdapter. You should see this link. It's in Java but you can easily adapt it to kotlin.
If no, I'm not sure what you are trying to do but I think the
ViewPager is what you need.
If you just want to switch fragments on a click, just use a FrameLayout to display the fragment you want and switch between them with transactions. I'm not familiar with kotlin but something like this should work.
private fun switchScreens(i: Integer) {
val fragment;
when (i) {
0 -> fragment = WelcomeFragment.newInstance()
1 -> fragment = LanguageSelectFragment.newInstance()
}
val fragmentManager = supportFragmentManager
val fragmentTransaction = fragmentManager.beginTransaction()
fragmentTransaction.replace(R.id.main_view_pager, fragment)
fragmentTransaction.commit()
}
If you want to slide to one fragment to another, you can use a ViewPager (see the link above).
Best
I am trying to implement a simple swiping action between the three main screens of my app (feed, forum & profile).
I've been looking for guides online but they all seem to take the same approach and show how to implement the adapter using fragments that are simple instances of a basic class that for example just inflates a title and a number on the screen.
In my case, the fragments are not all instances of the same class and are completely different.
M problem lays in the FragmentPagerAdapter. I am not sure how to return each fragment in the getItem method.
I have tried the following but it doesn't except it as a valid return statement and is still expecting one:
class PagesPagerAdapter(fragmentManager: FragmentManager) : FragmentPagerAdapter(fragmentManager) {
override fun getItem(p0: Int): Fragment? {
return when (p0){
0 -> FeedFragment.newInstance()
1 -> BoardFragment.newInstance()
2 -> ProfileFragment.newInstance()
else -> FeedFragment.newInstance()
}
}
override fun getCount(): Int {
return 3
}
}
This is an example of one of my fragments:
class FeedFragment : Fragment() {
val galleryAdapter = GroupAdapter<ViewHolder>()
private fun setUpGalleryAdapter() {
feed_gallary.adapter = galleryAdapter
val galleryLayoutManager = GridLayoutManager(this.context, 3)
feed_gallary.layoutManager = galleryLayoutManager
val dummyUri =
"https://firebasestorage.googleapis.com/v0/b/dere-3d530.appspot.com/o/20150923_100950.jpg?alt=media&token=97f4b02c-75d9-4d5d-bc86-a3ffaa3a0011"
val imageUri = Uri.parse(dummyUri)
if (imageUri != null) {
galleryAdapter.add(FeedImage(imageUri))
galleryAdapter.add(FeedImage(imageUri))
galleryAdapter.add(FeedImage(imageUri))
galleryAdapter.add(FeedImage(imageUri))
galleryAdapter.add(FeedImage(imageUri))
}
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
setUpGalleryAdapter()
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? =
inflater.inflate(R.layout.fragment_feed, container, false)
companion object {
fun newInstance(): FeedFragment = FeedFragment()
}
}
And this is my main activity:
class MainActivity : AppCompatActivity() {
private lateinit var viewPager: ViewPager
private lateinit var pagerAdapter: PagesPagerAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewPager = findViewById<ViewPager>(R.id.view_pager)
pagerAdapter = PagesPagerAdapter(supportFragmentManager)
viewPager.adapter = pagerAdapter
}
}
I have also tried to define a variable currentFragment, have it reassigned for each of the when statements and have it be the return value, but as all my fragments are unique I am getting a type mismatch when trying to assign them all to one variable.
Is there some Array I can store the fragments in and then return the array position?
I feel like there is probably a simple elegant and common solution here.
Without seeing all of your code I cannot be sure but one thing to note is you must return an instance of your fragment not a reference to the class. Ex: FeedFragment() instead of FeedFragment.
Also, your when statement does not have a default case resulting in a compile error for the getItem method as you have a code path that doesn't return anything. Try the following code for getItem
override fun getItem(p0: Int): Fragment {
when(p0){
0 -> return FeedFragment.newInstance()
1 -> return BoardFragment.newInstance()
else -> return ProfileFragment.newInstance()
}
}
Unfortunately, there is no elegant solution for this case. You can store created fragment in array and then use this array when you need to access related fragment instance.
class PagesPagerAdapter(fragmentManager: FragmentManager) : FragmentPagerAdapter(fragmentManager) {
private val fragments = SparseArray<WeakReference<Fragment>>()
override fun getCount() = 3
override fun getItem(position: Int): Fragment? {
val fragmentReference = fragments[position]
return if (fragmentReference?.get() != null) {
fragmentReference.get()
} else {
return when (position) {
0 -> FeedFragment.newInstance()
1 -> BoardFragment.newInstance()
2 -> ProfileFragment.newInstance()
else -> error("Incorrect position: $position")
}
}
}
override fun instantiateItem(container: ViewGroup, position: Int): Any {
val fragment = super.instantiateItem(container, position) as Fragment
fragments.put(position, WeakReference(fragment))
return fragment
}
is there any possible way to put a fragment inside a fragment?
I tried to put a viewPager in a fragment and write the code on OnCreatedView but it gives me error!!!
I tried this one but the fragments goes for every fragment in the activity!
pageradapter.kt
class pagerAdapter(fm:FragmentManager):FragmentStatePagerAdapter(fm){
override fun getItem(position: Int): Fragment? {
return when(position){
0-> Fragment1()
1-> Fragment2()
else -> null
}
}
override fun getCount(): Int {
return 2
}
fun rotatePosition(position: Int):Int{
return (count -1)-position
}
class pagerAdapter(fm:FragmentManager):FragmentStatePagerAdapter(fm){
override fun getItem(position: Int): Fragment? {
return when(position){
0-> Fragment1()
1-> Fragment2()
else -> null
}
}
override fun getCount(): Int {
return 2
}
fun rotatePosition(position: Int):Int{
return (count -1)-position
}
pageradapter2.kt
class pagerAdapter2(fm: FragmentManager):FragmentStatePagerAdapter(fm){
override fun getItem(position: Int): Fragment? {
return when(position){
0-> BlankFragment()
else->null
}
}
/**
* Return the number of views available.
*/
override fun getCount(): Int {
return 1
}
MainActivity.kt
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val pagerAdapter2 = pagerAdapter2(supportFragmentManager)
val pager1= findViewById<View>(R.id.pager2) as ViewPager
pager1.adapter = pagerAdapter2
val adapter = pagerAdapter(supportFragmentManager)
val pager = findViewById<View>(R.id.pager) as ViewPager
pager.adapter = adapter
pager.setCurrentItem(adapter.rotatePosition(0), false)
}
P.S. The first Answer solved my problem.
If you are adding fragment for an activity you use either fragmentManager or supportFragmentManager.
If you are adding fragment for a fragment - you should use childFragmentManager, accessing fragmentManager from fragment will lead to using the same one that activity does.