我需要根据导航组件的目标位置更改AppBarLayout,例如,我有FragmentA和FragmentB,当用户转到FragmentA时,要将TabLayout像YouTube应用程序一样添加到AppBarLayout中
我试图将TabLayout添加到活动并根据导航目标隐藏/显示它,但是我发现它没用,因为我需要访问Activity,然后需要查找ViewById并设置ViewPager,但是我需要这样做新的android导航组件和简洁代码
这就是我实现导航组件的方式
bnvActivityMainNavigation.setupWithNavController(navController)
setupWithNavController(vnActivityMain, navController)
setupActionBarWithNavController(navController)
setupActionBarWithNavController(navController, dlActivityMainRoot)
toolbar?.setNavigationOnClickListener { onSupportNavigateUp() }
有什么建议吗?
答案 0 :(得分:0)
这里是一个建议的解决方案,旨在将片段和活性的耦合限制到最小。
基于Boolean LiveData对象显示或隐藏TabLayout,该对象托管在活动和每个片段目标共享的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
}
}
这些示例利用了几个jetpack组件(LiveData,ViewModel和Binding),它们是从Google提供的sunflower sample app中衍生出来的。
LiveData解决方案的灵感来自this answer。
此处给出的示例是针对TabLayout的,但是通过获取对整个AppBarLayout的引用并调用findViewById来检索每个视图,我已经成功地将其应用于其他视图(进度条和固定的表头)。>