ViewPager2 doesn't switch fragments - android

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]
}
}

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
}
}

Related

FragmentArgs class in not generated while passing value of one fragment to another by using Navigation components

This is my FragmentTwo fragment class code.
class FragmentTwo : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?,
): View? {
// Inflate the layout for this fragment
val binding : FragmentTwoBinding = DataBindingUtil.inflate(inflater,R.layout.fragment_two, container, false)
var args = FragmentTwoArgs.fromBundle(arguments)
setHasOptionsMenu(true)
return binding.root
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
super.onCreateOptionsMenu(menu, inflater)
inflater?.inflate(R.menu.overflow_menu,menu)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return NavigationUI.onNavDestinationSelected(item!!,findNavController())
|| super.onOptionsItemSelected(item)
}
}
This is my FragmentOne fragment class code:
class FragmentOne : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
// return inflater.inflate(R.layout.fragment_one, container, false)
val binding: FragmentOneBinding =
DataBindingUtil.inflate(inflater, R.layout.fragment_one, container, false)
binding.clickable = this
return binding.root
}
fun onClicking() {
//Toast.makeText(activity, "You clicked me.", Toast.LENGTH_SHORT).show()
//findNavController().navigate(R.id.action_fragmentOne_to_fragmentTwo)
findNavController().navigate(FragmentOneDirections.actionFragmentOneToFragmentTwo())
}
}
And this is my Navigation xml code.
<?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/navigation"
app:startDestination="#id/fragmentOne">
<fragment
android:id="#+id/fragmentOne"
android:name="com.example.fragmentpractise1.FragmentOne"
android:label="fragment_one"
tools:layout="#layout/fragment_one" >
<action
android:id="#+id/action_fragmentOne_to_fragmentTwo"
app:destination="#id/fragmentTwo" />
<argument
android:name="numViews"
app:argType="integer"
android:defaultValue="18" />
</fragment>
<fragment
android:id="#+id/fragmentTwo"
android:name="com.example.fragmentpractise1.FragmentTwo"
android:label="fragment_two"
tools:layout="#layout/fragment_two" />
<fragment
android:id="#+id/aboutFragment"
android:name="com.example.fragmentpractise1.AboutFragment"
android:label="fragment_about"
tools:layout="#layout/fragment_about" />
</navigation>
Now I am getting an error in FragmentTwo class code as FragmentTwoArgs class is not generated while assigning it to args variable. I am using Nav safe args and defined argument value through Nav graph in FragmentOne.
Any help would be appreciated.
You're using wrong Fragment to declare the arguments. If you want FragmentTwo to have arguments you should use the fragment in the navigation xml:
<fragment
android:id="#+id/fragmentTwo"
android:name="com.example.fragmentpractise1.FragmentTwo"
android:label="fragment_two"
tools:layout="#layout/fragment_two">
<argument
android:name="numViews"
app:argType="integer"
android:defaultValue="18" />
</fragment>
You might also want to use the lazy delegate navArgs():
private val args: FragmentTwoArgs by navArgs()

On click of the Button I want Fragment 1 layout to be replaced with Fragment 2 layout but its throwing: java.lang.NullPointerException

First Fragment's code
class MainFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val mainInflater = inflater.inflate(R.layout.fragment_main, container, false)
return mainInflater
}
fun thisdata():String{
return "Hello from MainFragment"
}
}
First Fragment XML
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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=".MainFragment">
<EditText
android:id="#+id/etSavedData"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="60dp"
android:hint="Enter the Text"/>
<Button
android:id="#+id/btnSaveData"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="120dp"
android:text="Save"/>
</RelativeLayout>
Main Activity's code
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//Set replace Main Activity content with the Fragment1 content
val mainFragment = MainFragment()
supportFragmentManager.beginTransaction().add(R.id.contain_fragment, mainFragment).commit()
val thedata = mainFragment.thisdata()
Log.e("Main Frag to Activity", thedata)
btnSaveData.setOnClickListener {
val secondFragment = SecondFragment()
supportFragmentManager.beginTransaction().add(R.id.contain_fragment, secondFragment).commit()
}
}
}
Main Activity XML
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
android:id="#+id/contain_fragment"
tools:context=".MainActivity">
</RelativeLayout>
Second Fragment's code
class SecondFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val secondInflater = inflater.inflate(R.layout.fragment_second, container, false)
return secondInflater
}
}
Second Fragment 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"
android:background="#android:color/holo_blue_dark"
tools:context=".SecondFragment">
<!-- TODO: Update blank fragment layout -->
<TextView
android:id="#+id/tvDisplayText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:text="Text displayed here." />
</FrameLayout>
Following Exception showing up in Logcat
Caused by: java.lang.NullPointerException: Attempt to invoke virtual
method 'void
android.widget.Button.setOnClickListener(android.view.View$OnClickListener)'
on a null object reference
at com.example.demo2.MainActivity.onCreate(MainActivity.kt:22)*
You either need to move your btnSaveData button into the MainActivity, or you should move the onClickListener into the MainFragment, along with some other changes. Something like:
class MainFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val mainInflater = inflater.inflate(R.layout.fragment_main, container, false)
btnSaveData.setOnClickListener {
val secondFragment = SecondFragment()
activity.supportFragmentManager.beginTransaction().add(R.id.contain_fragment, secondFragment).commit()
}
return mainInflater
}
fun thisdata():String{
return "Hello from MainFragment"
}
}
**Thanks Tash, that actually make sense, unfortunately it was still showing the same exception but I finally manage to resolve the issue by doing the following. **
class MainFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val mainInflater = inflater.inflate(R.layout.fragment_main, container, false)
mainInflater.btnSaveData.setOnClickListener {
val secondFragment = SecondFragment()
secondFragment?.let {
activity?.supportFragmentManager?.beginTransaction()?.replace(R.id.contain_fragment, secondFragment)?.commit()
}
}
return mainInflater
}
fun thisdata():String{
return "Hello from MainFragment"
}
}

android BaseFragment with it's own xml and inherited fragment's view inside a parent's frameLayout

I have an abstract fragment that has it's own view (views the are common for inherited fragments)
I'm creating a fragment that inherit from that base fragment and it has it's own view (layout)
How can it be done?
I'm getting an error that says that I need to call remove view first...
The inherited Fragment's view should go into the: (Found in the parent's xml)
<FrameLayout
android:id="#+id/gamePadContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toTopOf="#+id/gamePadHistoryScroller"
app:layout_constraintTop_toTopOf="parent" />
Base Fragment (abstract):
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val rootView = inflater.inflate(R.layout.fragment_gamepad, container, false)
val gamePadView = inflater.inflate(onFragmentLayoutRequest(), null)
gamePadView.viewTreeObserver.addOnGlobalLayoutListener(object :
ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
joystickLeftCenter[0] = 0
joystickLeftCenter[1] = 0
joystickRightCenter[0] = 0
joystickRightCenter[1] = 0
gamePadButtonsMap[KeyEvent.KEYCODE_BUTTON_THUMBL]?.let {
joystickLeftCenter[0] = it.buttonView.left
joystickLeftCenter[1] = it.buttonView.top
}
gamePadButtonsMap[KeyEvent.KEYCODE_BUTTON_THUMBR]?.let {
joystickRightCenter[0] = it.buttonView.left
joystickRightCenter[1] = it.buttonView.top
}
gamePadView.viewTreeObserver.removeOnGlobalLayoutListener(this)
}
})
gamePadButtonsMap = onGamePadButtonMapRequest(gamePadView)
return rootView
}
Base fragment XML:
<?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">
<FrameLayout
android:id="#+id/gamePadContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toTopOf="#+id/gamePadHistoryScroller"
app:layout_constraintTop_toTopOf="parent" />
<!-- Buttons History -->
<HorizontalScrollView
android:id="#+id/gamePadHistoryScroller"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginTop="28dp"
android:layout_marginBottom="24dp"
android:fillViewport="true"
android:scrollbars="none"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintVertical_bias="0.265"
tools:layout_editor_absoluteX="0dp">
<androidx.appcompat.widget.LinearLayoutCompat
android:id="#+id/gamePadHistoryContainer"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_marginBottom="52dp"
android:background="#color/bg_buttons_history"
android:gravity="left"
android:orientation="horizontal" />
</HorizontalScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>
Inherit fragment:
class PS4Fragment : GamePadFragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
super.onCreateView(inflater, container, savedInstanceState)
return inflater.inflate(R.layout.fragment_ps4, container, false)
}
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val rootView = inflater.inflate(R.layout.fragment_gamepad, container, false)
val gamePadView = LayoutInflater.from(requireContext()).inflate(onFragmentLayoutRequest(), rootView.gamePadContainer, true)
gamePadButtonsMap = onGamePadButtonMapRequest(gamePadView)
rootView.gamePadContainer.addView(gamePadView)
return rootView
}
I've been using the same inflater.. now it's working as expected.
In the child fragment (Inherit fragment) there is no "onCreateView"
Now,
I have a base fragment with some views and component that all fragments have, and a unique view to each fragment :)
Thanks!

Back button closes app instead of going to previous fragment android navigation component

While creating a very simple sample app, I couldn't wrap my head around why my app is closing when I press the hardware back button on my emulator.
I have 1 mainActivity and 2 fragments.
When I am on the NavigationFragment and press back, the app closes instead of going back to IntermediateFragment.
MainActivity:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
toolbar.setTitle(R.string.app_name)
}
}
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context="com.exampleapplication.MainActivity">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_constraintTop_toTopOf="parent"
/>
<fragment
android:id="#+id/my_nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
app:navGraph="#navigation/main_nav"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintTop_toBottomOf="#+id/toolbar"
app:layout_constraintBottom_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
navigation_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"
android:id="#+id/main_nav"
app:startDestination="#+id/intermediateFragment">
<fragment
android:id="#+id/intermediateFragment"
android:name="com.exampleapplication.IntermediateFragment">
<action
android:id="#+id/action_intermediate_to_navigation"
app:destination="#+id/navigationFragment"
/>
</fragment>
<fragment
android:id="#+id/navigationFragment"
android:name="com.exampleapplication.NavigationFragment"
/>
</navigation>
IntermediateFragment:
class IntermediateFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_intermediate, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
btn_next_fragment.setOnClickListener {
findNavController().navigate(R.id.action_intermediate_to_navigation)
}
}
}
NavigationFragment:
class NavigationFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_navigation, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
btn_first_library.setOnClickListener {
findNavController().setGraph(R.navigation.first_library_nav)
}
btn_download_pdf.setOnClickListener {
findNavController().setGraph(R.navigation.download_pdf_nav)
}
}
}
Any ideas?
You're missing one line on your <fragment>:
app:defaultNavHost="true"
As per the Navigation Getting Started guide:
The app:defaultNavHost="true" attribute ensures that your NavHostFragment intercepts the system Back button.
Since you don't set that, Navigtion does not intercept the back button and hence, you only get the default activity behavior (which is closing your activity).

How to click a button in a fragment to switch to other Tab in Kotlin?

The following code is based by Android Studio Wizard 3.2.1 for creating Tabbed Activity.
There is a button1 on PlaceholderFragment1 connected Tab1, and a button2 on PlaceholderFragment2 connected Tab2
I hope to click button1 to switch to Tab2, and click button2 to switch to Tab1, How can I do ?
BTW, I have read How to change tab on button click in Android? and How to programmatically switch tabs using buttonclick in Android
Code
class MainActivity : AppCompatActivity() {
private var mSectionsPagerAdapter: SectionsPagerAdapter? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
mSectionsPagerAdapter = SectionsPagerAdapter(supportFragmentManager)
container.adapter = mSectionsPagerAdapter
container.addOnPageChangeListener(TabLayout.TabLayoutOnPageChangeListener(tabs))
tabs.addOnTabSelectedListener(TabLayout.ViewPagerOnTabSelectedListener(container))
}
inner class SectionsPagerAdapter(fm: FragmentManager) : FragmentPagerAdapter(fm) {
override fun getItem(position: Int): Fragment {
val fragment: Fragment
when (position) {
0 -> fragment = PlaceholderFragment1() //Tab1
1 -> fragment = PlaceholderFragment2() //Tab2
else -> throw IllegalArgumentException("Invalid section number")
}
return fragment
}
override fun getCount(): Int {
return 2
}
}
class PlaceholderFragment1 : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val rootView = inflater.inflate(R.layout.fragment_main1, container, false)
return rootView
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
button1.setOnClickListener {
//Switch to Tab2
}
}
}
class PlaceholderFragment2 : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val rootView = inflater.inflate(R.layout.fragment_main2, container, false)
return rootView
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
button2.setOnClickListener {
//Switch to Tab1
}
}
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".MainActivity">
<android.support.design.widget.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="#dimen/appbar_padding_top"
android:theme="#style/AppTheme.AppBarOverlay">
<android.support.design.widget.TabLayout
android:id="#+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.design.widget.TabItem
android:id="#+id/tabItem"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/tab_text_1"/>
<android.support.design.widget.TabItem
android:id="#+id/tabItem2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/tab_text_2"/>
</android.support.design.widget.TabLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"/>
</android.support.design.widget.CoordinatorLayout>
fragment_main1.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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:id="#+id/constraintLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<Button
android:text="Button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/button1"/>
</android.support.constraint.ConstraintLayout>
My way
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
...
setControl(view)
}
private fun setControl(view: View){
button1.setOnClickListener {
var viewPager=view.parent as ViewPager
viewPager.setCurrentItem(1,true)
}
}
manually binding these events is not required...
you just have to setup the TabLayout with the Viewpager:
container.adapter = mSectionsPagerAdapter
tabs.setupWithViewPager(container);
then these events are being handled by the framework, in a rather convenient way.
PS: container is a rather unfortunate variable name for a ViewPager.
I think you should use Livedata and ViewModel.
Create View Model class with livedata.
Observer Livedata in MainActivity.
Update livedata value from your fragment.
For example:
class TabChangerViewModel : ViewModel() {
val colorResource = MutableLiveData<Int>()
.........
}
In your MainActivity class:
val tabChangerViewModel = ViewModelProviders.of(this).get(TabChangerViewModel::class.java) // initialize view model
tabChangerViewModel.colorResource.observe(this, android.arch.lifecycle.Observer {
//mViewPager.setCurrentItem(it)
})
Now update live data value from your fragment:
val tabChangerViewModel = ViewModelProviders.of(activity).get(TabChangerViewModel::class.java) // initialize view model
tabChangerViewModel.colorResource.value = TAB_POSITION_WANT_TO_SELECT

Categories

Resources