preface

In mobile development, different people have different capabilities for developers. Just like reading a book, there are a thousand Hamlets for a thousand readers. But anyway, if you’re a software developer you have to learn how an operating system like Windows or Linux works. Let’s cut to the chase and get straight to it. Due to the longer length of the article, notice in advance: at the end of the article there is a large number of handwritten framework source code and framework thinking data, need to directly skip to the end of the article to get]

In actual combat

Before we do that, let’s take a look at the three key elements in Navigation. They are:

  • Navigation Graph (New XML Resource) As shown in our first diagram, this is a New resource file where the user can visually see the Destination he can reach (the screen interface the user can reach) and the process relationships.
  • NavHostFragment (Layou XML View) Container for the current Fragment
  • NavController (Kotlin/Javaobject) Controller of navigation

Maybe this is a little abstract, but to use a less appropriate metaphor, we can think of the Navigation Graph as a map, the NavHostFragment as a car, and the NavController as a steering wheel in the car, The Navigation Graph shows you the Destination and the path to each Destination. The NavHostFragment can go to any Destination on the map, but it’s the steering wheel NavController that decides where to go. Although it depends on the driver (user).

The first step is to add dependencies

The build.gradle file for the module layer needs to be added:

Ext. NavigationVersion = "2.0.0" dependencies {//... implementation "androidx.navigation:navigation-fragment- ktx:$rootProject.navigationVersion" implementation "androidx.navigation:navigation-ui-ktx:$rootProject.navigationVersion" }Copy the code

If you want to use the SafeArgs plugin, add it to the build.gradle file in your project directory:

Buildscript {ext navigationVersion = "2.0.0 dependencies {classpath androidx. Navigation: navigation - safe - the args - gradle -  plugin:$navigationVersion" } }Copy the code

And the build.gradle file below the module is added:

apply plugin: 'kotlin-android-extensions' 
apply plugin: 'androidx.navigation.safeargs'
Copy the code

Step 2 Create a navigation

  1. Create a navigation directory under the res directory -> right-click navigation directory and create a New navigation resource file
  2. To create a
Destination
Copy the code

If the

navigation
Copy the code

It’s our navigation tool,

Destination
Copy the code

It’s our destination. I’ve already written one down before

WelcomeFragment
Copy the code

,

LoginFragment
Copy the code

and

RegisterFragment
Copy the code

To add

Destination
Copy the code

After the operation is completed, it is shown as follows:

Add the Destination

In addition to the visual interface, it is still necessary to look at the composition of the content, login_navigation.xml:

<navigation ... android:id="@+id/login_navigation" app:startDestination="@id/welcome"> <fragment android:id="@+id/login" android:name="com.joe.jetpackdemo.ui.fragment.login.LoginFragment" android:label="LoginFragment" tools:layout="@layout/fragment_login" /> <fragment android:id="@+id/welcome" android:name="com.joe.jetpackdemo.ui.fragment.login.WelcomeFragment" android:label="LoginFragment" tools:layout="@layout/fragment_welcome"> <action ... /> <action ... /> </fragment> <fragment android:id="@+id/register" android:name="com.joe.jetpackdemo.ui.fragment.login.RegisterFragment" android:label="LoginFragment" tools:layout="@layout/fragment_register" > <argument ... /> </fragment> </navigation>Copy the code

I’ve omitted some unnecessary code here. Let’s look at the attributes of the Navigation tag:

App :startDestination Default starting location

The third step is to create NavHostFragment

We create a new LoginActivity in the activity_login.xml file:

<androidx.constraintlayout.widget.ConstraintLayout ... > <fragment android:id="@+id/my_nav_host_fragment" android:name="androidx.navigation.fragment.NavHostFragment" app:navGraph="@navigation/login_navigation" app:defaultNavHost="true" android:layout_width="match_parent" android:layout_height="match_parent"/> </androidx.constraintlayout.widget.ConstraintLayout>Copy the code

A few attributes need to be explained:

  • The android: name value must be androidx. Navigation. Fragments. NavHostFragment, this is a NavHostFragment declaration
  • App :navGraph stores the resource file that is used in the second step to set up the Navigation Graph
  • App :defaultNavHost=”true” is associated with the system’s return button

Step 4: Interface jump, parameter transfer and animation

On the WelcomeFragment, click the Login and Register buttons to jump to the LoginFragment and RegisterFragment, respectively.

WelcomeFragment. Here I implement the WelcomeFragment in two ways:

Method one uses ID navigation

Target: WelcomeFragment indicates the WelcomeFragment that displays the data whose key is name to the LoginFragment. Have a account ? The click events of the Login button are as follows:

BtnLogin. SetOnClickListener {/ / set the animation parameter val navOption = navOptions {anim {enter = state Richard armitage nim. Slide_in_right exit = Slide_in_left popExit = r.lem.slide_out_right}} val bundle = bundle ()  bundle.putString("name","TeaOf") findNavController().navigate(R.id.login, bundle,navOption) }Copy the code

The following LoginFragment receiving code is relatively simple. You can directly obtain the Bundle in the Fragment. The final result:

LoginFragment

Method two uses Safe Args **

Target: WelcomeFragment Sends data to the RegisterFragment through Safe Args. The RegisterFragment displays data after receiving the data. Take a look at the login_navigation.xml already shown:

<navigation ... > <fragment ... /> <fragment android:id="@+id/welcome" > <action android:id="@+id/action_welcome_to_login" app:destination="@id/login"/>  <action android:id="@+id/action_welcome_to_register" app:enterAnim="@anim/slide_in_right" app:exitAnim="@anim/slide_out_left" app:popEnterAnim="@anim/slide_in_left" app:popExitAnim="@anim/slide_out_right" app:destination="@id/register"/> </fragment> <fragment android:id="@+id/register" ... > <argument android:name="EMAIL" android:defaultValue="[email protected]" app:argType="string"/> </fragment> </navigation>Copy the code

You may have noticed the action and argument tags in the login_navigation.xml resource file in the navigation directory.

  • App :destination Indicates the Id of the fragment arrived after the hop is complete
  • App :popUpTo Popup the fragment from the stack to a fragment with an Id

Argument label

  • Android :name Tag name
  • App :argType Indicates the type of the tag
  • Android: defaultValue default values

By clicking the Make Project button in Android Studio, you can see that the system has generated two classes for us:

System generated classes

WelcomeFragment
Copy the code

In the

JOIN US
Copy the code

Button click event:

btnRegister.setOnClickListener {
        val action = WelcomeFragmentDirections
              .actionWelcomeToRegister()
              .setEMAIL("[email protected]")
        findNavController().navigate(action)
}
Copy the code

Receive in RegisterFragment:

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        // ...
        val safeArgs:RegisterFragmentArgs by navArgs()
        val email = safeArgs.email
        mEmailEt.setText(email)
}
Copy the code

And the effect:

RegisterFragment needs to be mentioned if not

Safe Args
Copy the code

.

action
Copy the code

Can be caused by

Navigation.createNavigateOnClickListener(R.id.next_action, null)
Copy the code

Mode generation, interested can write their own.

More and more

Navigation can be bound with menus, drawers, and bottom Navigation, for example, bottom Navigation. I created main_navigation.xml in the navigation directory, MainActivity, and activity_main.xml:

<LinearLayout ... > <fragment android:id="@+id/my_nav_host_fragment" android:name="androidx.navigation.fragment.NavHostFragment" android:layout_width="match_parent" app:navGraph="@navigation/main_navigation" app:defaultNavHost="true" android:layout_height="0dp" android:layout_weight="1"/> <com.google.android.material.bottomnavigation.BottomNavigationView android:id="@+id/navigation_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@android:color/white" app:itemIconTint="@color/colorAccent" app:itemTextColor="@color/colorPrimary" app:menu="@menu/menu_main"/> </LinearLayout>Copy the code

Processing in MainActivity is also quite simple:

class MainActivity : AppCompatActivity() {
          
          lateinit var bottomNavigationView: BottomNavigationView
          
          override fun onCreate(savedInstanceState: Bundle?) {
              //...
              val host: NavHostFragment =
          supportFragmentManager.findFragmentById(R.id.my_nav_host_fragment) as NavHostFragment
              val navController = host.navController
              initWidget()
              initBottomNavigationView(bottomNavigationView,navController)
          }

          private fun initBottomNavigationView(bottomNavigationView: BottomNavigationView, navController: NavController) {
              bottomNavigationView.setupWithNavController(navController)
          }
          private fun initWidget() {
              bottomNavigationView = findViewById(R.id.navigation_view)
          }
}
Copy the code

Effect: