I have an app that uses NavigationComponents
among with ViewPager 2
.
I'd like to use ViewPager
for switching between fragments. I've made my ActivityMain
as FragmentContainerView
, and I'd like to have ViewPager
implemented in one of my fragments.
The problem is, the ViewPager
doesn't work at all. It doesn't change fragments, don't know why. What should I change in the code?
ActivityMain
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.fragment.app.FragmentContainerView
android:id="@ id/fragmentContainerView"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_graph" />
</androidx.constraintlayout.widget.ConstraintLayout>
First fragment
class BlankFragment : Fragment() {
private var mPag: ViewPager2? = null
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_blank, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
mPag = view.findViewById(R.id.pager123)
val adapter = PagerAdapter(this)
val list = mutableListOf<Fragment>()
list.add(BlankFragment())
list.add(BlankFragment2())
mPag?.adapter = adapter
}
}
.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".BlankFragment"
android:orientation="vertical">
<TextView
android:id="@ id/test123"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="111111111" />
<androidx.viewpager2.widget.ViewPager2
android:id="@ id/pager123"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#a1a1"/>
</LinearLayout>
Second fragment
class BlankFragment2 : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_blank2, container, false)
}
}
.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".BlankFragment2">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="222222222222222" />
</FrameLayout>
Nav graph
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@ id/nav_graph"
app:startDestination="@id/blankFragment">
<fragment
android:id="@ id/blankFragment"
android:name="com.example.myapplication.BlankFragment"
android:label="fragment_blank"
tools:layout="@layout/fragment_blank" />
<fragment
android:id="@ id/blankFragment2"
android:name="com.example.myapplication.BlankFragment2"
android:label="fragment_blank2"
tools:layout="@layout/fragment_blank2" />
</navigation>
Pager adapter
class PagerAdapter(fragment: Fragment) : FragmentStateAdapter(fragment) {
val mFragments = mutableListOf<Fragment>()
override fun getItemCount(): Int {
return mFragments.size
}
override fun createFragment(position: Int): Fragment {
when (position){
0 -> return BlankFragment()
1 -> return BlankFragment2()
}
return mFragments[position]
}
}
CodePudding user response:
What you are essentially missing is what I tried to explain in the previous question.
You need to use Navigation component
and ViewPager2
as two separate entities.
There is also issue with your PagerAdapter
. Fragment adapters are not similar to other Adapters you might have experience with(mFragments
).
They shouldn't hold a reference to those fragments. There are two main Fragment adapters(more here).
class PagerAdapter(fragment: Fragment) : FragmentStateAdapter(fragment) {
override fun getItemCount(): Int = 2
override fun createFragment(position: Int): Fragment {
return when (position){
0 -> BlankFragment1()
1 -> BlankFragment2()
else -> throw IllegalArgumentException("Out of fragments, will depend on getItemCount")
}
}
}
You need to have Fragments
that are solely in the Navigation component(e.g. FirstFragment
& SecondFragment
) and Fragments
that belong to the ViewPager2
(e.g. BlankFragment1
& BlankFragment2
)
<?xml version="1.0" encoding="utf-8"?>
<navigation android:id="@ id/nav_graph"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
app:startDestination="@id/FirstFragment">
<fragment
android:id="@ id/FirstFragment"
android:name="com.example.myapplication.FirstFragment"
android:label="@string/first_fragment_label"
tools:layout="@layout/fragment_first" >
<action
android:id="@ id/action_FirstFragment_to_SecondFragment"
app:destination="@id/SecondFragment" />
</fragment>
<fragment
android:id="@ id/SecondFragment"
android:name="com.example.myapplication.SecondFragment"
android:label="@string/second_fragment_label"
tools:layout="@layout/fragment_second" />
</navigation>
Fragments for ViewPager2:
class BlankFragment1: Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_blank_1, container, false)
}
}
class BlankFragment2: Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_blank_2, container, false)
}
}
The FirstFragment
is going to host the ViewPager2
that will allow you to swipe between BlankFragment1
and BlankFragment2
.
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,savedInstanceState: Bundle?): View? {
val view = inflater.inflate(R.layout.fragment_first, container, false)
view.findViewById<ViewPager2>(R.id.vp2)?.let { viewPager2 ->
val pagerAdapter = PagerAdapter(this)
viewPager2.adapter = pagerAdapter
}
return view
}
Now the only thing you need to do in any of the fragments to use Navigation component
is to simply findNavControler
and navigate
to destination
you want.
class BlankFragment1: Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view = inflater.inflate(R.layout.fragment_blank_1, container, false)
view.findViewById<MaterialButton>(R.id.blank_1_button).setOnClickListener {
findNavController().navigate(R.id.action_FirstFragment_to_SecondFragment)
}
return view
}
}