Как изменить содержимое AppBarLayout в зависимости от места назначения библиотеки навигации - PullRequest
0 голосов
/ 25 декабря 2018

Мне нужно изменить свой AppBarLayout в зависимости от назначения компонента Навигация, например, у меня есть FragmentA и FragmentB. Я хочу, чтобы пользователь переходил во FragmentA, добавлял TabLayout в AppBarLayout, как приложение YouTube

Example

Я пытался добавить TabLayout к действию и скрыть / показать его в зависимости от места назначения навигации, но я нашел его бесполезным, потому что мне нужен доступ к Activity, и после этого мне нужно найти ViewById и установить ViewPager, но мне нужно сделать это с новой навигацией Androidкомпонент и чистый код

Вот как я реализую компонент Навигация

    bnvActivityMainNavigation.setupWithNavController(navController)
    setupWithNavController(vnActivityMain, navController)
    setupActionBarWithNavController(navController)
    setupActionBarWithNavController(navController, dlActivityMainRoot)
    toolbar?.setNavigationOnClickListener { onSupportNavigateUp() }

Есть предложения ??

1 Ответ

0 голосов
/ 28 января 2019

Вот предлагаемое решение, которое нацелено на ограничение связи фрагмента и активности до минимума.

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 для извлечения каждого представления.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...