I have a layout with TabLayout and ViewPager (file refuel_order_configuration.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"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/refuel_order_configuration"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/layout_corners_only_top"
android:gravity="center_vertical|start"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginTop="10dp"
android:layout_marginRight="20dp"
android:gravity="center_vertical|end"
android:orientation="horizontal">
<include layout="@layout/gas_station_info_back" />
<TextView
android:id="@+id/refuel_order_column_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginTop="9dp"
android:layout_weight="1"
android:textAlignment="center"
android:textColor="#545B6E"
android:textSize="24sp"
android:textStyle="bold"
tools:text="FUEL TYPE"
android:text="FUEL TYPE"/>
</LinearLayout>
<com.google.android.material.tabs.TabLayout
android:id="@+id/refuelOrderTabLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
app:tabTextColor="#00C2CA"
app:tabIndicatorColor="#00C2CA"
android:layout_marginEnd="16dp">
</com.google.android.material.tabs.TabLayout>
<androidx.viewpager.widget.ViewPager
android:id="@+id/refuelOrderViewPager"
android:layout_width="wrap_content"
android:layout_height="330dp"
/>
</LinearLayout>
And then in code I add two fragments with adapter. This is the code of one of the fragments (file refuel_order_configuration_tab.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:id="@+id/refuel_order_configuration_tab"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/layout_corners_only_top"
android:gravity="center_vertical|start"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginTop="10dp"
android:layout_marginRight="16dp"
android:gravity="center_vertical|end"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_order_sum"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textColor="#212121"
android:textSize="24sp"
tools:text="1050 P" />
<TextView
android:id="@+id/tv_order_litres"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="end"
android:textColor="@color/taxi_text"
android:textSize="24sp"
tools:text="22.9 л" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="4dp"
android:orientation="vertical">
<androidx.appcompat.widget.AppCompatSeekBar
android:id="@+id/params_seek_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:progress="500"
android:max="5000"
android:progressBackgroundTint="#000000"
android:progressTint="#00C2CA"
android:thumbTint="#00C2CA" />
<HorizontalScrollView
android:id="@+id/order_info_view"
android:layout_width="match_parent"
android:layout_marginStart="12dp"
android:layout_marginEnd="12dp"
android:layout_height="70dp"
android:layout_marginTop="16dp"
android:scrollbars="none">
<LinearLayout
android:id="@+id/sum_params_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal" />
<!-- <include layout="@layout/gas_column_number"/>-->
</HorizontalScrollView>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:baselineAligned="false"
android:orientation="horizontal">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/payment_account_label_text"
android:textColor="#666666" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:gravity="bottom"
android:orientation="horizontal">
<ImageButton
android:layout_width="20dp"
android:layout_height="20dp"
android:adjustViewBounds="true"
android:background="#00000000"
android:scaleType="centerCrop"
android:src="@mipmap/ic_wallet" />
<TextView
android:id="@+id/wallet_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:textColor="#000000"
android:textSize="18sp"
tools:text="Bill" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginEnd="10dp"
android:orientation="vertical">
<TextView
android:id="@+id/order_count_litres"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#666666"
android:textSize="18sp"
tools:text="50 " />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="vertical">
<ImageButton
android:id="@+id/bill_configuration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#FFFFFF"
android:minWidth="20dp"
android:minHeight="26dp"
android:src="@mipmap/arrow_right_gray" />
</LinearLayout>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="2dp"
android:layout_marginStart="16dp"
android:layout_marginTop="12dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="24dp"
android:background="#E6E6E6" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
android:orientation="horizontal">
<Button
android:layout_width="match_parent"
android:layout_height="match_parent"
android:width="56dp"
android:background="@drawable/empty_corner_background"
android:text="@string/finish_button_text"
android:textColor="#FFFFFF" />
</LinearLayout>
</LinearLayout>
When data changes in AppCompatSeekBar, I handle it and change data in TextView in current layout
My question: How I may handle data change in first tab and pass it changes into TextView on second tab?
There may be a mechanism with saving the state of the tab when switching tabs and transferring this state to another tab,but I don’t know about it
Update: I solved the problem in the following way
In kotlin class which initialize container Fragment (file refuel_order_configuration.xml) I initialize adapter
refuelOrderViewPager.adapter = RefuelOrderConfigAdapter(fragmentManager, view.context)
refuelOrderTabLayout.setupWithViewPager(refuelOrderViewPager)
In adapter class I initialize so-called DataManager and pass it into each kotlin class of tab.
class RefuelOrderConfigAdapter(fragmentManager: FragmentManager?,
val context: Context) : FragmentStatePagerAdapter(fragmentManager) {
private val titles: List<String> = listOf(SUM_TAB_HEADER, LITRES_TAB_HEADER)
private val dataManager = DataManager()
private val items: List<BaseFragment> = listOf(SumOrderConfigurationTab.instance(TabType.SUM, dataManager),
LitresOrderConfigurationTab.instance(TabType.LITRES, dataManager))
init {
dataManager.registerObserver(items)
}
//...other adapter methods
}
There is the code of DataManager. It is essentially part of the pattern Observer.
class DataManager {
private val observers: ArrayList<BaseFragment> = ArrayList()
fun registerObserver(observerList: List<BaseFragment>) {
observers.addAll(observerList)
}
fun notifyObservers(data: String, tabType: TabType) {
observers.forEach { observer -> observer.handleNotify(data, tabType) }
}
}
In each class of fragment when seekBar changed I notify observers about data changed and in method handleNotify I handle data changes.
class SumOrderConfigurationTab : BaseFragment() {
companion object {
private lateinit var tabType: TabType
private lateinit var dataManager: DataManager
fun instance(tabType: TabType, dataManager: DataManager): SumOrderConfigurationTab {
this.tabType = tabType
this.dataManager = dataManager
return SumOrderConfigurationTab()
}
}
//initializers, logic et.c.
override fun bindListeners(view: View) {
seekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
leftVariable.text = seekBar?.progress.toString()
dataManager.notifyObservers(seekBar?.progress.toString(), tabType)
}
override fun onStartTrackingTouch(seekBar: SeekBar?) {
leftVariable.text = seekBar?.progress.toString()
dataManager.notifyObservers(seekBar?.progress.toString(), tabType)
}
override fun onStopTrackingTouch(seekBar: SeekBar?) {
leftVariable.text = seekBar?.progress.toString()
dataManager.notifyObservers(seekBar?.progress.toString(), tabType)
}
})
}
override fun handleNotify(data: String, type: TabType) {
if (type != tabType) {
rightVariable.text = data
}
}
}
It works. Works as expected. But
I found a solution.
This solution based on popular library EventBus (source code here)
Algorithm is very simple.
In tab Fragments in method onCreateView I register widget for listen events
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
EventBus.getDefault().register(this)
return inflater.inflate(R.layout.refuel_order_configuration_tab, container, false)
}
Later in Fragment I create a method for receive events
@Subscribe(threadMode = ThreadMode.MAIN)
fun handleEvent(event: ChangeSumEvent) {
// set data from event
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun handleEvent(event: ChangeLitresEvent) {
// set data from event
}
Create simple POJO classes for events
class ChangeSumEvent(val data: Int?)
class ChangeLitresEvent(val data: Int?)
In Seekbar listener i send event
seekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
return
}
override fun onStartTrackingTouch(seekBar: SeekBar?) {
return
}
override fun onStopTrackingTouch(seekBar: SeekBar?) {
//...logic for current fragment
EventBus.getDefault().post(ChangeLitresEvent(progress)) //send event to another fragment
}
})
Finally, in method onDestroyView unregister listener.
override fun onDestroyView() {
super.onDestroyView()
EventBus().unregister(this)
}