Вот предлагаемое решение, которое нацелено на ограничение связи фрагмента и активности до минимума.
TabLayout отображается или скрывается на основе логического объекта LiveData, размещенного в ViewModel, совместно используемойдействие и назначение каждого фрагмента.
Каждый пункт назначения отвечает за установку соответствующего логического значения для объекта LiveData, а действие наблюдает за объектом LiveData, чтобы показать или скрыть TabLayout.
Чтобы иметь возможность использоватьTabLayout, фрагмент объявляет интерфейс, который Activity должен реализовать, и который содержит единственный метод, используемый для получения ссылки на TabLayout.
Вот соответствующие примеры кода в Kotlin.
MainActivityViewModel
class MainActivityViewModel internal constructor() : ViewModel() {
val tabLayoutDestination = MutableLiveData<Boolean>()
fun setTabLayoutDestination(newValue : Boolean) {
//If the new value is the same, do not trigger an update
if (Objects.equals(tabLayoutDestination.value, newValue)) return
tabLayoutDestination.value = newValue
}
}
ExampleFragment
class ExampleFragment : Fragment() {
private lateinit var viewPager: ViewPager
private lateinit var activityViewModel : MainActivityViewModel
private var tabLayout: TabLayout? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
...
val binding = FragmentExampleBinding.inflate(inflater, container, false)
val context = context ?: return binding.root
//Get the activity's ViewModel and specify that this destination requires a TabLayout
val mainViewModelFactory = InjectorUtils.provideMainActivityViewModelFactory()
activityViewModel = ViewModelProviders.of(activity!!, mainViewModelFactory)
.get(MainActivityViewModel::class.java)
activityViewModel.setTabLayoutDestination(true)
viewPager = binding.viewpager
return binding.root
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
//If the parent activity implements the interface, get a reference to its TabLayout
val parentActivity = if(activity is TabLayoutHost) activity as TabLayoutHost else return
tabLayout = parentActivity.getTabLayoutReference()
//Setup the TabLayout and ViewPager
tabLayout?.setupWithViewPager(viewPager)
viewPager.addOnPageChangeListener(TabLayout.TabLayoutOnPageChangeListener(tabLayout))
}
//The interface which must be implemented by the parent activity
interface TabLayoutHost {
fun getTabLayoutReference() : TabLayout
}
}
MainActivity
class MainActivity : AppCompatActivity(), ExampleFragment.TabLayoutHost {
private lateinit var activityViewModel : MainActivityViewModel
private lateinit var tabLayout: TabLayout
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding: ActivityMainBinding = DataBindingUtil.setContentView(this,
R.layout.activity_main)
//Get the viewmodel
val mainViewModelFactory = InjectorUtils.provideMainActivityViewModelFactory()
activityViewModel = ViewModelProviders.of(this, mainViewModelFactory)
.get(MainActivityViewModel::class.java)
//Get a reference to the TabLayout
TabLayout = binding.tabLayout
//Subscribe to the boolean livedata, to be able to make
//the appropriate UI changes according to the fragment displayed
activityViewModel.tabLayoutDestination.observe(this, Observer {
if(it == true ) updateUiForTabLayoutDestination()
else updateUiForOtherDestination()
})
}
override fun getTabLayoutReference() = tabLayout
private fun updateUiForTabLayoutDestination() {
tabLayout.visibility = View.VISIBLE
}
private fun updateUiForOtherDestination() {
tabLayout.visibility = View.GONE
}
}
Эти образцы делаютиспользование нескольких компонентов реактивного ранца (LiveData, ViewModel и Binding) и были получены из образца подсолнечника p предоставлено Google.
Решение LiveData было вдохновлено этим ответом .
Приведенный здесь пример для TabLayout, но я успешно применилэто для других представлений (индикатор выполнения и фиксированный заголовок таблицы), получая ссылку на весь AppBarLayout и вызывая findViewById для извлечения каждого представления.