Как связать два фрагмента с Android компонентом навигации? - PullRequest
0 голосов
/ 30 апреля 2020

Я использую Android Компонент навигации Jetpack с нижней панелью навигации , например:

Navigation graph:

Bottom navigation bar:

Давайте сосредоточимся на пунктах назначения для дома и панели мониторинга, на панели инструментов отображается список отделов, в каждом отделе отображается список продуктов, а для каждого продукта - подробное описание. , Пока все работает нормально.

Однако Home должен отображать полный список продуктов напрямую , и вот вопрос: как я могу отобразить фрагмент product_list непосредственно на Home, когда приложение запускается (и каждый раз при доступе к Home)?

Обратите внимание, что я не могу поместить код product_list непосредственно во фрагмент Home, потому что тогда навигация из Dashboard будет go к Home.

Кроме того, если я добавлю findNavController().navigate(HomeFragmentDirections.nextAction()) к фрагменту Home onCreateView(...), каждый раз, когда я go к Home, он отображает список продуктов, а также кнопку Up на панель приложения, которая никуда не денется (она переходит в Home, который снова перенаправляет на product_list).

App action bar:

Мне нужен только Кнопка «Вверх» при доступе к product_list через список отделов на информационной панели. product_list должен отображаться в Home, как если бы это был сам Home.

Итак, я ищу способ напрямую связать эти два фрагмента, без каких-либо транзакций или избегая Кнопка «Вверх» на панели приложения (возможно, за счет исключения добавления транзакции в стек транзакций).

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/bottom_nav"
    app:startDestination="@+id/navigation_home">

    <fragment
        android:id="@+id/navigation_home"
        android:name="cu.lcnicolau.ui.home.HomeFragment"
        android:label="@string/title_home"
        tools:layout="@layout/fragment_home">
        <action
            android:id="@+id/next_action"
            app:destination="@id/product_list">
            <argument
                android:name="departmentId"
                android:defaultValue="0" />
        </action>
    </fragment>

    <fragment
        android:id="@+id/navigation_departments"
        android:name="cu.lcnicolau.ui.departments.DepartmentsFragment"
        android:label="@string/title_departments"
        tools:layout="@layout/fragment_departments">
        <action
            android:id="@+id/next_action"
            app:destination="@id/product_list" />
    </fragment>

    <fragment
        android:id="@+id/product_list"
        android:name="cu.lcnicolau.ui.products.ItemListFragment"
        android:label="@string/title_products"
        tools:layout="@layout/item_list">
        <action
            android:id="@+id/next_action"
            app:destination="@id/product_detail" />
        <argument
            android:name="departmentId"
            app:argType="integer" />
    </fragment>

    <fragment
        android:id="@+id/product_detail"
        android:name="cu.lcnicolau.ui.products.ItemDetailFragment"
        android:label="@string/title_product_detail"
        tools:layout="@layout/item_detail">
        <argument
            android:name="item"
            app:argType="cu.lcnicolau.dummy.Product" />
    </fragment>

</navigation>

1 Ответ

0 голосов
/ 30 апреля 2020

Этот способ может удовлетворить ваши потребности:

1. Установите bottom_nav

  1. Создайте глобальное действие, которое можно использовать из любой точки навигационного графика. DepartmentsFragment будет использовать это для перехода к ItemListFragment.

  2. Создать действие внутри navigation_home. Важным свойством здесь является app:popUpTo="@+id/bottom_nav (идентификатор вашего графика), оно удалит HomeFragment из backstack и повлияет на BottomNavigationView при вызове onBackPressed из другого фрагмента. Мы сделаем ActivityCallback для решения этой проблемы.

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/bottom_nav"
    app:startDestination="@+id/navigation_home">
    
    <action
        android:id="@+id/to_product_list"
        app:destination="@id/product_list" />

    <fragment
        android:id="@+id/navigation_home" android:name="com.example.stackoverflowhelps.ui.home.HomeFragment"
        android:label="@string/title_home"
        tools:layout="@layout/fragment_home">
        <action
            android:id="@+id/home_to_product_list"
            app:destination="@id/product_list"
            app:popUpTo="@+id/bottom_nav" />
    </fragment>

    <fragment
        android:id="@+id/product_list" android:name="com.example.stackoverflowhelps.ui.products.ProductsFragment"
        android:label="@string/title_products"
        tools:layout="@layout/fragment_products" >
         <argument
            android:name="departmentId"
            app:argType="long" />
    </fragment>
    
    ...
</navigation>
Вызовите глобальное действие с DepartmentsFragment

findNavController().navigate(toProductList(departementId))
В любом месте при первоначальном обратном вызове HomeFragment

override fun onCreate(savedInstanceState: Bundle?) {
   super.onCreate(savedInstanceState)

   findNavController().navigate(homeToProductList(-1))
}

2. Настройка MainActivity и NavCallback

Целью этого обратного вызова является перемещение BottomNavigationView в Home, когда onBackPressed из двух других нижних меню. Так как мы потеряли HomeFragment в backstack каждый раз, когда мы вводим ItemListFragment из Home.

  1. NavCallback.java

    interface NavCallback {
        enum class Nav { HOME, DASHBOARD, OFFERS }
    
        fun navigateToMenu(nav: Nav)
    }
  2. MainActivity.java

    class MainActivity : AppCompatActivity(), NavCallback {
    
        private lateinit var navView: BottomNavigationView
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
            navView = findViewById(R.id.nav_view)
    
            val navController = findNavController(R.id.nav_host_fragment)
            
            // optional: if you want to permanently remove default ActionBar BackButton from ItemListFragment, add product_list navigation id to appBarConfiguration
            val appBarConfiguration = AppBarConfiguration(
                setOf(
                    R.id.navigation_home,
                    R.id.navigation_dashboard,
                    R.id.navigation_offers,
                    R.id.product_list
                )
            )
            setupActionBarWithNavController(navController, appBarConfiguration)
            navView.setupWithNavController(navController)
        }
    
        override fun navigateToMenu(nav: NavCallback.Nav) {
            val dest: Int = when(nav) {
                NavCallback.Nav.HOME -> R.id.navigation_home
                NavCallback.Nav.DASHBOARD -> R.id.navigation_home
                NavCallback.Nav.OFFERS -> R.id.navigation_notifications
            }
    
            navView.selectedItemId = dest
        }
    }
  3. Используйте NavCallback при переопределении onBackPressed внутри DepartmentsFragment и OffersFragment. Мы вручную выберем нижнее навигационное меню для Дома, см. NavCallback.Nav.HOME

class DepartmentsFragment : Fragment() {
    private var navCallback: NavCallback? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        val callback = object : OnBackPressedCallback(true) {
            override fun handleOnBackPressed() {
                navCallback?.navigateToMenu(NavCallback.Nav.HOME)
            }
        }
        requireActivity().onBackPressedDispatcher.addCallback(this, callback)
    }

    override fun onAttach(context: Context) {
        super.onAttach(context)
        try {
            navCallback = context as NavCallback
        } catch (e: ClassCastException) {
            activity.toString() + " must implements NavCallback"
        }
    }

    override fun onDetach() {
        navCallback = null
        super.onDetach()
    }


    ...
}

До этого момента мы получили желаемый поток пользовательского интерфейса.


3. Определите данные списка продуктов и видимость кнопки «Назад» в ItemListFragment

. Я предпочитаю использовать пользовательский вид панели инструментов и кнопку «Назад» для удобства. В настоящее время мы будем использовать аргумент departmentId для определения видимости кнопки возврата

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
   super.onViewCreated(view, savedInstanceState)
   
   val departmentId: Long = arguments?.getLong("departmentId") ?: 0
   if (departmentId > 0) {
       textView.text = departmentId.toString()
       back.visibility = View.VISIBLE
       back.setOnClickListener { requireActivity().onBackPressed() }
            
       // from fetch the data with given id 
    } else {
      back.visibility = View.GONE
      // come from HomeFragment, fetch all data
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...