Android:处理 TabLayout 中的数据变化
Andoid: handle data change in TabLayout
我有一个包含 TabLayout 和 ViewPager 的布局(文件 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>
然后在代码中我添加了两个带有适配器的片段。这是其中一个片段的代码(文件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>
当 AppCompatSeekBar 中的数据发生变化时,我会处理它并在当前布局的 TextView 中更改数据
我的问题:
我如何处理第一个选项卡中的数据更改并将其更改传递到第二个选项卡上的 TextView?
可能有一种机制可以在切换标签时保存标签的状态并将此状态转移到另一个标签,但我不知道
更新:
我通过以下方式解决了问题
在 kotlin class 中初始化容器片段(文件 refuel_order_configuration.xml)我初始化适配器
refuelOrderViewPager.adapter = RefuelOrderConfigAdapter(fragmentManager, view.context)
refuelOrderTabLayout.setupWithViewPager(refuelOrderViewPager)
在适配器 class 中,我初始化所谓的 DataManager 并将其传递到选项卡的每个 kotlin class。
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
}
有DataManager的代码。它本质上是观察者模式的一部分。
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) }
}
}
在 seekBar 更改时的每个 class 片段中,我通知观察者数据已更改,并在方法 handleNotify 中处理数据更改。
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()
}
}
//初始化器,逻辑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
}
}
}
有效。按预期工作。但是
- 我认为这不是正确而优雅的解决方案。
- 此实现几乎没有扩展空间。解决方案不灵活。
我找到了解决办法。
这个解决方案基于流行的库 EventBus (source code here)
算法很简单
在 onCreateView 方法中的选项卡 Fragments 中,我为侦听事件注册了小部件
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)
}
稍后在片段中我创建了一个接收事件的方法
@Subscribe(threadMode = ThreadMode.MAIN)
fun handleEvent(event: ChangeSumEvent) {
// set data from event
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun handleEvent(event: ChangeLitresEvent) {
// set data from event
}
为事件创建简单的 POJO 类
class ChangeSumEvent(val data: Int?)
class ChangeLitresEvent(val data: Int?)
在 Seekbar 侦听器中我发送事件
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
}
})
最后,在 onDestroyView 方法中注销监听器。
override fun onDestroyView() {
super.onDestroyView()
EventBus().unregister(this)
}
我有一个包含 TabLayout 和 ViewPager 的布局(文件 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>
然后在代码中我添加了两个带有适配器的片段。这是其中一个片段的代码(文件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>
当 AppCompatSeekBar 中的数据发生变化时,我会处理它并在当前布局的 TextView 中更改数据
我的问题: 我如何处理第一个选项卡中的数据更改并将其更改传递到第二个选项卡上的 TextView?
可能有一种机制可以在切换标签时保存标签的状态并将此状态转移到另一个标签,但我不知道
更新: 我通过以下方式解决了问题
在 kotlin class 中初始化容器片段(文件 refuel_order_configuration.xml)我初始化适配器
refuelOrderViewPager.adapter = RefuelOrderConfigAdapter(fragmentManager, view.context) refuelOrderTabLayout.setupWithViewPager(refuelOrderViewPager)
在适配器 class 中,我初始化所谓的 DataManager 并将其传递到选项卡的每个 kotlin class。
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 }
有DataManager的代码。它本质上是观察者模式的一部分。
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) } }
}
在 seekBar 更改时的每个 class 片段中,我通知观察者数据已更改,并在方法 handleNotify 中处理数据更改。
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() } }
//初始化器,逻辑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 } }
}
有效。按预期工作。但是
- 我认为这不是正确而优雅的解决方案。
- 此实现几乎没有扩展空间。解决方案不灵活。
我找到了解决办法。
这个解决方案基于流行的库 EventBus (source code here)
算法很简单
在 onCreateView 方法中的选项卡 Fragments 中,我为侦听事件注册了小部件
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) }
稍后在片段中我创建了一个接收事件的方法
@Subscribe(threadMode = ThreadMode.MAIN) fun handleEvent(event: ChangeSumEvent) { // set data from event } @Subscribe(threadMode = ThreadMode.MAIN) fun handleEvent(event: ChangeLitresEvent) { // set data from event }
为事件创建简单的 POJO 类
class ChangeSumEvent(val data: Int?) class ChangeLitresEvent(val data: Int?)
在 Seekbar 侦听器中我发送事件
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 } })
最后,在 onDestroyView 方法中注销监听器。
override fun onDestroyView() { super.onDestroyView() EventBus().unregister(this) }