[Android Jetpack] Usar vista personalizada en la navegación

Inserte la descripción de la imagen aquíLa navegación es uno de los componentes importantes de Jetpack, que se utiliza para diseñar y organizar los saltos de página de la aplicación. Dado que la recomendación oficial es usar Framgent para llevar la implementación de la página, lo primero que me viene a la mente cuando se trata de Navegación es Fragmento. Pero, de hecho, Navigation también admite otros tipos de implementación de páginas, como la vista personalizada. Este artículo presentará el uso de la vista personalizada en la navegación.

Antes de la introducción formal, repasemos el uso básico de Navigation:

Estructura básica de navegación


El uso de la navegación involucra principalmente los siguientes objetos

  • Graph
    usa XML para diseñar la página de la aplicación (destino) y la ruta de salto entre cada página. Android Studio proporciona un editor para editar Graph
  • NavHost
    NavHost es un contenedor que se utiliza para alojar todos los nodos del gráfico. La navegación proporciona una implementación predeterminada de NavHost para Fragmento NavHostFragment. Se puede entender que todos los Fragmentos en el gráfico son ChildFragment. En el escenario de Vista personalizada presentado hoy, también existe la necesidad de implementar NavHost para la Vista personalizada.
  • Controlador
    Cada NavHost tiene un controlador, que gestiona los saltos entre los nodos en el NavHost
  • Navigator
    Controller implementa saltos específicos llamando a Navigator, y Navigator realiza implementaciones de saltos específicos

principio de funcionamiento


Cada página en Navegación es un Destino, que puede ser Fragmento, Actividad o Vista. Vincule el Destino de origen con el Destino de destino a través de Acción, y salte del Destino actual al Destino de destino a través de Acción.

Al igual que en la Actividad de lanzamiento, cuando se inicia la APLICACIÓN, es necesario definir un Destino de inicio como la visualización de la página de inicio.

Como se mencionó anteriormente, NavHost tiene implementaciones específicas para diferentes destinos, y NavController también tiene diferentes métodos de adquisición según el tipo de destino, pero todos son similares:

  • Fragment.findNavController ()
  • View.findNavController ()
  • Activity.findNavController (viewId: Int)

Después de obtener el controlador, puede navigate(int)saltar, por ejemplo

findNavController().navigate(R.id.action_first_view_to_second_view)
findNavController().navigate(R.id.second_view)

Implementación


La composición básica y el principio de funcionamiento de la navegación se introdujeron anteriormente, y luego ingresaremos al tema para realizar la navegación basada en la vista personalizada.

Es necesario lograr lo siguiente:

  • ViewNavigator
  • Atributos de ViewNavigator
  • VerDestino
  • NavigationHostView
  • Archivo gráfico

ViewNavigator

Navigation proporciona una forma de personalizar Navigator: utilice @Navigator.Nameanotaciones.
Definimos un nombre para screen_viewel Navegador, en el xml Graph se puede definir con este nombre correspondiente NavDestination.
NavDestination y Navigator están restringidos por genéricos:Navigator<out NavDestination>

@Navigator.Name("screen_view")
class ViewNavigator(private val container: ViewGroup) : Navigator<ViewDestination>() {
    
    
    override fun navigate(...) {
    
    ...}
    override fun createDestination(): ViewDestination = ViewDestination(this)
    override fun popBackStack(): Boolean {
    
    ...}
}

Atributos de ViewNavigator

Definir atributos personalizados usados ​​en Xml para Navigator layoutId,

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <declare-styleable name="ViewNavigator">
        <attr name="layoutId" format="reference" />
    </declare-styleable>

</resources>

VerDestino

@NavDestination.ClassTypePermítanos definir el nuestroNavDestination

@NavDestination.ClassType(ViewGroup::class)
class ViewDestination(navigator: Navigator<out NavDestination>) : NavDestination(navigator) {
    
    

    @LayoutRes var layoutId: Int = 0

    override fun onInflate(context: Context, attrs: AttributeSet) {
    
    
        super.onInflate(context, attrs)
        context.resources.obtainAttributes(attrs, R.styleable.ViewNavigator).apply {
    
    
            layoutId = getResourceId(R.styleable.ViewNavigator_layoutId, 0)
            recycle()
        }
    }
}

En onInflate, recibe y analiza layoutIdel valor del atributo personalizado

NavigationHostView

Definir la implementación de NavHost NavigationHostFrame, que se utiliza principalmente para crear un controlador, registrar el tipo de navegador y configurar Graph para él.

class NavigationHostFrame(...) : FrameLayout(...), NavHost {
    
    
    private val navigationController = NavController(context)
    init {
    
    
        Navigation.setViewNavController(this, navigationController)
        navigationController.navigatorProvider.addNavigator(ViewNavigator(this))
        navigationController.setGraph(R.navigation.navigation)
    }
    override fun getNavController() = navigationController
}

Archivo gráfico

En el archivo Graph, <screen_view/>definiendo NavDestination

<?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/main_navigation"
    app:startDestination="@id/first_screen_view"
    tools:ignore="UnusedNavigation">

    <screen_view
        android:id="@+id/first_screen_view"
        app:layoutId="@layout/screen_view_first"
        tools:layout="@layout/screen_view_first">

        <action
            android:id="@+id/action_first_screen_view_to_second_screen_view"
            app:destination="@id/second_screen_view"
            app:launchSingleTop="true"
            app:popUpTo="@+id/first_screen_view"
            app:popUpToInclusive="false" />

        <action
            android:id="@+id/action_first_screen_view_to_last_screen_view"
            app:destination="@id/last_screen_view"
            app:launchSingleTop="true"
            app:popUpTo="@+id/first_screen_view"
            app:popUpToInclusive="false" />

    </screen_view>

    <screen_view
        android:id="@+id/second_screen_view"
        app:layoutId="@layout/screen_view_second"
        tools:layout="@layout/screen_view_second">

        <action
            android:id="@+id/action_second_screen_view_to_screen_view_third"
            app:destination="@id/screen_view_third"
            app:launchSingleTop="true"
            app:popUpTo="@+id/main_navigation"
            app:popUpToInclusive="true" />

    </screen_view>

    <screen_view
        android:id="@+id/last_screen_view"
        app:layoutId="@layout/screen_view_last"
        tools:layout="@layout/screen_view_last" />

    <screen_view
        android:id="@+id/screen_view_third"
        app:layoutId="@layout/screen_view_third"
        tools:layout="@layout/screen_view_third" />

</navigation>

Abra el editor de navegación de Android Studio y vea el resultado después de Xml:
Inserte la descripción de la imagen aquí

Configuración en actividad

Finalmente, use este NavigationHostView como un contenedor en el diseño de la Actividad y asocie NavController con NavHost en el código

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <com.my.sample.navigation.NavigationHostView
        android:id="@+id/main_navigation_host"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
private lateinit var navController: NavController
override fun onCreate(savedInstanceState: Bundle?) {
    
    
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    navController = Navigation.findNavController(mainNavigationHost)
    Navigation.setViewNavController(mainNavigationHost, navController)
}

Llame a NavController en onBackPressed` para permitir que cada NavDestination admita BackPress

override fun onSupportNavigateUp(): Boolean = navController.navigateUp()
override fun onBackPressed() {
    
    
      if (!navController.popBackStack()) {
    
    
          super.onBackPressed()
      }
}

Conclusión


La navegación basada en Fragment proporciona una implementación lista para usar, y al mismo tiempo reserva una interfaz extensible a través de anotaciones, lo que es conveniente para que los desarrolladores personalicen la implementación e incluso disfruten del recorrido que trae el editor de Android Studio.

En los primeros días de la inestabilidad de Fragment, aparecieron muchas alternativas a Fragment para la segmentación de la interfaz de usuario. Si estos marcos todavía se utilizan en su proyecto, ahora puede adaptar fácilmente Navigation para ellos ~

Supongo que te gusta

Origin blog.csdn.net/vitaviva/article/details/109281582
Recomendado
Clasificación