Android Jetpack navigationUI , how to pass data to view pager fragment - android

I am first time working with Navigation UI Architecture Component
I am trying to use ViewPager with it. I wanted to pass argument to Fragments that's is added to viewpager
I didn't found any solution related to viewpager
My code
class StoriesPagerAdapter(fragmentManager: FragmentManager?)
:FragmentPagerAdapter(fragmentManager){
private val sections= arrayListOf("science","technology","business","world","movies","travel")
override fun getItem(position: Int): Fragment {
val bundle=Bundle()
bundle.putString("section",sections[position])
Navigation.createNavigateOnClickListener(R.id.action_masterFragment_to_timesListFragment,bundle)
return TimesListFragment()
}
override fun getCount(): Int {
return sections.size
}
override fun getPageTitle(position: Int): CharSequence? {
return sections[position]
}
}
My navigation graph
MasterFragment -> contains TabLayout , ViewPager
passes section key to ListFragment via FragmentPagerAdapter
ListFragment -> shows api response based on section key
DetailsFragmenst

You can pass data in fragment instance:
class StoriesPagerAdapter(fragmentManager: FragmentManager?)
:FragmentPagerAdapter(fragmentManager){
private val sections= arrayListOf("science","technology","business","world","movies","travel")
override fun getItem(position: Int): Fragment {
return TimesListFragment().newInstance(sections)
}
override fun getCount(): Int {
return sections.size
}
override fun getPageTitle(position: Int): CharSequence? {
return sections[position]
}
}
You have to manage viewPager like old method with navigation architecture according to this answer.

Related

How to deal with the error: "Design assumption violated." when using FragmentStateAdapter

Hi guys I am using ViewPager with FragmentStateAdapter. I have an option for the user, in one of the added fragments, to recreate the activity (a method calls: activity.recreate()). However if the activity is recreated I get the following error:
java.lang.IllegalStateException: Design assumption violated.
at androidx.viewpager2.adapter.FragmentStateAdapter.placeFragmentInViewHolder(FragmentStateAdapter.java:287)
at androidx.viewpager2.adapter.FragmentStateAdapter.onViewAttachedToWindow(FragmentStateAdapter.java:276)
at androidx.viewpager2.adapter.FragmentStateAdapter.onViewAttachedToWindow(FragmentStateAdapter.java:67)
at androidx.recyclerview.widget.RecyclerView.dispatchChildAttached(RecyclerView.java:7556)
at androidx.recyclerview.widget.RecyclerView$5.addView(RecyclerView.java:860)
at androidx.recyclerview.widget.ChildHelper.addView(ChildHelper.java:107)
at androidx.recyclerview.widget.RecyclerView$LayoutManager.addViewInt(RecyclerView.java:8601)
Here is my FragmentStateAdapter:
class MainViewPagerAdapter(fragmentActivity: FragmentActivity) :
FragmentStateAdapter(fragmentActivity) {
var fragmentList: ArrayList<Fragment> = arrayListOf()
override fun getItemCount(): Int = fragmentList.size
//Put all the fragments needed based on position
override fun createFragment(position: Int): Fragment {
return fragmentList[position]
}
fun add(fragment: Fragment) {
fragmentList.add(fragment)
notifyDataSetChanged()
}
fun addByPosition(position: Int, fragment: Fragment) {
fragmentList.add(position, fragment)
notifyDataSetChanged()
}
fun remove(index: Int) {
fragmentList.removeAt(index)
notifyDataSetChanged()
}
override fun getItemId(position: Int): Long {
return fragmentList[position].hashCode().toLong()
}
override fun containsItem(itemId: Long): Boolean {
return fragmentList.contains(itemId)
}}
I am using:
implementation "androidx.viewpager2:viewpager2:1.0.0"
and I have tried the followig:
remove getItemId() -> works but I need this method to be overridden in order to retain a proper position of all the elements when add/remove a fragment from the adapter
tried to save the list of fragments inside onSaveInstanceState(outState: Bundle) and pass it back to the adapter but I get the same error.
What am I doing wrong? What is the best way to deal with this error?

In tab layout fragments not showing their layout in androidX

I have a tab layout in which I have included five fragments, but when i click on tabs, the fragments layout is not showed. In my adapter I've extended FragmentPagerAdapter which has FragmentManager and a variable behaviour.
class ViewPagerAdapter(#NonNull fm:FragmentManager, behaviour:Int):
FragmentPagerAdapter(fm, behaviour) {
private val tabs:Array<Fragment> = arrayOf(
Category1Fragment(),
Category2Fragment(),
Category3Fragment(),
Category4Fragment(),
Category5Fragment()
)
#NonNull
override fun getItem(position: Int): Fragment {
return tabs[position]
}
override fun getCount(): Int {
return tabs.size
}
#Nullable
override fun getPageTitle(position: Int): CharSequence? {
return when (position) {
0 -> "Bags"
1 -> "Watches"
2 -> "Shoes"
3 -> "Glasses"
4 -> "Audio"
else -> null
}
}
}
and in my activity I've called adapter through viewpager, but when I debug is telling me that adapter is null, here's my activity code:
val adapter = ViewPagerAdapter(supportFragmentManager, tab_layout.selectedTabPosition)
val viewPager = findViewById<ViewPager>(R.id.view_pager)
viewPager.adapter = adapter
val tab = findViewById<TabLayout>(R.id.tab_layout)
tab.setupWithViewPager(view_pager)
// -------------------------------------------------------------------------------- //
tab.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
override fun onTabReselected(p0: TabLayout.Tab?) {
}
override fun onTabUnselected(p0: TabLayout.Tab?) {
}
override fun onTabSelected(p0: TabLayout.Tab?) {
viewPager.currentItem = tab.selectedTabPosition
}
})
In the previous versions of android I did the same, but in androidX things are something different. I tried also to use ViewPager2, but it was confusing.
Any help is appreciated!

How to implement View Pager same Fragment in Kotlin?

I wanna ask if there any best way to implement view pager with only one fragment in Kotlin?
Like if you have a ViewPager Adapter like below
class ViewPagerAdapter(fragmentManager: FragmentManager) : FragmentPagerAdapter(fragmentManager) {
val fragments:MutableList<Fragment> = ArrayList()
val titles:MutableList<String> = ArrayList()
fun addFragment(fragment: Fragment, title:String){
fragments.add(fragment)
titles.add(title)
}
override fun getItem(p0: Int): Fragment = fragments[p0]
override fun getCount(): Int = fragments.size
override fun getPageTitle(position: Int): CharSequence? {
return titles[position]
}
override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) {
super.destroyItem(container, position, `object`)
}
}
Now if you have fragment, SampleFragment (say)
Just call the method with whichever fragment you want,
adapter.addFragment(SampleFragment(),"Sample Fragment")
..
..
adapter.addFragment(SampleFragment(),"Sample Fragment 2")
Create model class FragmentConfig where you going to keep parameters for fragment.
Add array of configs fragmentConfigs to your FragmentPagerAdapter
and in adapter:
override fun getItem(position: Int): Fragment {
val fragmentConfig = fragmentConfigs[position]
return UniversalListFragment.newInstance(fragmentConfig)
}

fragment inside fragment {Kotlin}

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.

How to open Fragment from View Pager Fragment

I have Implemented TabLayout. It contains three tabs. The first tab contains Listing of data. when User clicks on list item I want to show another Fragment. I have tried but not got success. Please help for find solution
ViewPager Adapter
inner class ViewPagerAdapter(manager: FragmentManager) : FragmentPagerAdapter(manager) {
val mFragmentList: ArrayList<Fragment> = ArrayList()
private val mFragmentTitleList: ArrayList<String> = ArrayList()
override fun getItem(position: Int): Fragment {
return mFragmentList.get(position)
}
override fun getCount(): Int {
return mFragmentList.size
}
fun addFrag(fragment: Fragment, title: String) {
mFragmentList.add(fragment)
mFragmentTitleList.add(title)
}
override fun getPageTitle(position: Int): CharSequence? {
return mFragmentTitleList.get(position)
}
override fun instantiateItem(container: ViewGroup, position: Int): Any {
val createdFragment = super.instantiateItem(container, position) as Fragment
mFragmentList[position] = createdFragment
return createdFragment
}
}
Fragment Adapter
class MyAdapter(private val mActivity: FragmentActivity?, private var mMyModelList: ArrayList<MyModel>) : RecyclerView.Adapter<MyAdapter.MyViewHolder>() {
private var mItemBinding: ItemBinding? = null
inner class MyViewHolder(val mBinding: ItemBinding) : RecyclerView.ViewHolder(mBinding.getRoot())
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val inflater = LayoutInflater.from(mActivity)
mItemBinding = DataBindingUtil.inflate(inflater, R.layout.item, null, false)
return MyViewHolder(mItemBinding!!)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val mMyModel: MyModel = mMyModelList[position]
holder.mBinding.txtTitle.setTextColor(mActivity!!.resources.getColor(R.color.light_green))
holder.mBinding.txtTitle.setText(mMyModel.lbl)
holder.mBinding.txtDateDay.setText(mMyModel.Day + " - " + mMyModel.date)
holder.mBinding.txtCircle.setBackgroundResource(R.drawable.green_circle)
holder.mBinding.constraintLayout.setOnClickListener {
var mSecondFragment: SecondFragment = SecondFragment()
//Below code is not working
mSecondFragment.onClickItem(mMyModel.id)
/*Here I want to show another Fragment*/
}
}
override fun getItemCount(): Int {
return mMyModelList.size
}
}
Fragment should open from Viewpager's Fragment.
there is no need for fragment adapter. just setup the view pager in activity.
then initiate your fragment in activity as well. There is no need on click listener in fragment adapter. Hope it helps you !
HistoryOnGoingFragment historyOnGoingFragment = new HistoryOnGoingFragment();
HistoryPastFragment historyPastFragment = new HistoryPastFragment();
private void setUpViewPager(int tabPosition) {
TabLayoutViewPagerAdapter adapter = new TabLayoutViewPagerAdapter(getFragmentManager());
adapter.addFragment(historyOnGoingFragment,"UPCOMING");
adapter.addFragment(historyPastFragment,"COMPLETED");
historyViewPager.setAdapter(adapter);
historyViewPager.setCurrentItem(tabPosition);
historyTabLayout.setupWithViewPager(historyViewPager);
}
After many tried I found custom Navigation Bar and applied changes which I needed for call nested fragment. It's working perfectly for me. Hope It'll help others too.
https://github.com/adib2149/BottomNavBar

Categories

Resources