Al comenzar un nuevo proyecto, decidí tratar de abandonar por completo los archivos XML, en función de los diseños que se forman, y crear pantallas con la biblioteca Anko. Con un poco de experiencia en desarrollo para Android (aproximadamente 2 años) y aún menos experiencia escribiendo código en Kotlin (un poco más de seis meses), inmediatamente me encontré con el problema de incluir el Componente de Arquitectura de Navegación en la aplicación, o más bien de representar la Barra de Navegación Inferior creada por BottomNavigationView .
En primer lugar, recurrí a Internet para encontrar una posible solución. Pero todos los artículos que encontré con diversos grados de claridad hablaban sobre cómo trabajar con componentes de navegación y ninguno (de aquellos cuyos artículos estudié) lo hizo en Anko. Una vez resuelta la tarea, ofrezco a la comunidad mi opción de crear una barra de navegación inferior.
Todo el código se puede ver aquí.
Me salto la etapa de crear un nuevo proyecto en Android Studio, solo noto las siguientes dependencias para trabajar con Anko y Navigation Architecture Component en build.gradle a nivel de módulo:
implementation "org.jetbrains.anko:anko:$anko_version" implementation "org.jetbrains.anko:anko-constraint-layout:$anko_version" implementation "com.android.support.constraint:constraint-layout:2.0.0-alpha3" implementation 'android.arch.navigation:navigation-fragment:1.0.0-beta02' implementation 'android.arch.navigation:navigation-fragment-ktx:1.0.0-beta02' implementation 'android.arch.navigation:navigation-ui-ktx:1.0.0-beta02' implementation 'com.google.android.material:material:1.0.0'
El siguiente paso es crear la estructura de la futura aplicación. Para dibujar la actividad principal, en lugar del archivo xml, cree la clase MainActivityUI heredada de la interfaz AnkoComponent:
class MainActivityUI: AnkoComponent<MainActivity> { override fun createView(ui: AnkoContext<MainActivity>): View = with(ui) { constraintLayout { } } }
En la clase MainActivity, setContentView (R.layout.activity_main) se reemplaza por MainActivityUI (). SetContentView (this).
Luego creamos fragmentos de paquetes en los que nuestros fragmentos y la interfaz de usuario del paquete se ubicarán para colocar las clases responsables de representar las pantallas de los fragmentos correspondientes. Esta es la estructura del proyecto:
fragments ui HomeUI UsersUI DetailsUI MoreUI HomeFragment UsersFragment DetailsFragment MoreFragment
Ahora nos ocuparemos directamente de la navegación y la creación de la barra de navegación inferior.
Puede encontrar una descripción detallada de la inclusión de nuevos componentes de navegación y una descripción del trabajo en el Editor de navegación en la página de documentación aquí . Para crear un archivo (gráfico) para la navegación entre pantallas de aplicaciones, debe agregar otra carpeta a la carpeta res, es decir, navegación, y agregar el archivo navigation_graph.xml ya. Para este proyecto, será así:
<navigation xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/navigation_graph" app:startDestination="@id/homeFragment"> <fragment android:id="@+id/homeFragment" android:name="com.arsinde.ankobottomnavbar.fragments.HomeFragment" android:label="HomeFragment"> <action android:id="@+id/action_homeFragment_to_detailsFragment" app:destination="@id/detailsFragment"/> </fragment> <fragment android:id="@+id/detailsFragment" android:name="com.arsinde.ankobottomnavbar.fragments.DetailsFragment" android:label="DetailsFragment"> <action android:id="@+id/action_detailsFragment_to_usersFragment" app:destination="@id/usersFragment"/> </fragment> <fragment android:id="@+id/usersFragment" android:name="com.arsinde.ankobottomnavbar.fragments.UsersFragment" android:label="UsersFragment"> <action android:id="@+id/action_usersFragment_to_moreFragment" app:destination="@id/moreFragment"/> </fragment> <fragment android:id="@+id/moreFragment" android:name="com.arsinde.ankobottomnavbar.fragments.MoreFragment" android:label="MoreFragment"/> </navigation>
Para mostrar la barra en sí, debe crear otra carpeta de recursos, a saber, el menú. Contiene el archivo responsable de la parte visible de la barra. Así es como se ve en este proyecto:
<menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@id/homeFragment" android:icon="@drawable/ic_home" android:title="@string/menu_title_home"/> <item android:id="@id/usersFragment" android:icon="@drawable/ic_users" android:title="@string/menu_title_users"/> <item android:id="@id/detailsFragment" android:icon="@drawable/ic_info" android:title="@string/menu_title_details"/> <item android:id="@id/moreFragment" android:icon="@drawable/ic_more" android:title="@string/menu_title_more"/> </menu>
Es hora de poner todo junto y ver cómo funciona.
Agregue un contenedor para fragmentos en MainActivityUI y también defina un contenedor para la barra de navegación.
constraintLayout { val fragmentContainer = frameLayout { id = R.id.fragment_container }.lparams { width = matchParent height = matchConstraint } val bottomNavigation = bottomNavigation { id = R.id.bottom_nav_view inflateMenu(R.menu.bottom_navigation_menu) } applyConstraintSet { fragmentContainer { connect( START to START of PARENT_ID, END to END of PARENT_ID, TOP to TOP of PARENT_ID, BOTTOM to TOP of R.id.bottom_nav_view ) } bottomNavigation { connect( START to START of PARENT_ID, END to END of PARENT_ID, TOP to BOTTOM of R.id.fragment_container, BOTTOM to BOTTOM of PARENT_ID ) } } }
Cabe señalar especialmente que bottomNavigation en este ejemplo es una función existente, que tiene la siguiente forma:
inline fun ViewManager.bottomNavigation(init: BottomNavigationView.() -> Unit = {}) = ankoView({ BottomNavigationView(it) }, theme = 0, init = init)
Ahora en MainActivity necesita definir el objeto NavHostFragment (vea el dock):
private val host by lazy { NavHostFragment.create(R.navigation.navigation_graph) }
Y en el método onCreate (), defina:
supportFragmentManager.beginTransaction() .replace(R.id.fragment_container, host) .setPrimaryNavigationFragment(host) .commit()
El toque final: agregue a onStart () MainActivity un objeto de la clase NavController, que le permite realizar la transición entre fragmentos eligiendo uno u otro objeto de barra de navegación:
override fun onStart() { super.onStart() val navController = host.findNavController() findViewById<BottomNavigationView>(R.id.bottom_nav_view)?.setupWithNavController(navController) navController.addOnDestinationChangedListener{_, destination, _ -> val dest: String = try { resources.getResourceName(destination.id) } catch (e: Resources.NotFoundException) { Integer.toString(destination.id) } Log.d("NavigationActivity", "Navigated to $dest") } }
Inicie la aplicación y vois là ...