Android Kotlin / Fragment & Navigation

目錄

Fragment

Create a fragment

Create a binding object (Make the fragment compile)

Add the fragment to the main layout file

Create the NavHostFragment

Add fragments to the navigation graph

Add conditional navigation

Change the back button's destination (back stack)

Add an Up button in the app bar

Add an options menu

Add the navigation drawer


Fragment


Create a fragment

Select File > New > Fragment > Fragment (Blank) and create

There is a new fragment file containing the onCreateView() method, which is one of the methods that's called during a fragment's lifecycle.

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                         savedInstanceState: Bundle?): View? {
}

Create a binding object (Make the fragment compile)

In the onCreateView(), create a binding variable.

Call the DataBindingUtil.inflate() method on the fragment's Binding object (FragmentTitleBinding).

Assign the binding that DataBindingUtil.inflate() returns to the binding variable.

val binding = DataBindingUtil.inflate<FragmentTitleBinding>(inflater,
           R.layout.fragment_title,container,false)

Return binding.root from the method, which contains the inflated view.


Add the fragment to the main layout file

Open res > layout > activity_main.xml

Add a fragment element inside LinearLayout element

<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">
            <fragment
                android:id="@+id/titleFragment"
                android:name="com.example.android.navigation.TitleFragment"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                />
        </LinearLayout>

</layout>


Create the NavHostFragment

In activity_main.xml file, change the name of the existing title fragment to androidx.navigation.fragment.NavHostFragment

Change the ID to myNavHostFragment

Add the app:navGraph attribute and set it to @navigation/navigation 

Add the app:defaultNavHost and set it to true (the default host will intercept the system back button)

<!-- The NavHostFragment within the activity_main layout -->
            <fragment
                android:id="@+id/myNavHostFragment"
                android:name="androidx.navigation.fragment.NavHostFragment"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                app:navGraph="@navigation/navigation"
                app:defaultNavHost="true" />

Add fragments to the navigation graph

If the preview shows a "Preview Unavailable" message, add tools:layout="@layout/fragment_game" to fragment element.

<!-- The game fragment within the navigation XML, complete with tools:layout. -->
<fragment
   android:id="@+id/gameFragment"
   android:name="com.example.android.navigation.GameFragment"
   android:label="GameFragment"
   tools:layout="@layout/fragment_game" />

Add a setOnClickListener{} in the TitleFragment.kt

binding.playButton.setOnClickListener{}

Add code to access the Play button through the binding class and navigate to the game fragment

//The complete onClickListener with Navigation
binding.playButton.setOnClickListener { view : View ->
       view.findNavController().navigate(R.id.action_titleFragment_to_gameFragment)
}

Add conditional navigation

Add fragments to the navigation graph and connect the fragments

Add code the navigate from one fragment to the next

        // Set the onClickListener for the submitButton
        binding.submitButton.setOnClickListener @Suppress("UNUSED_ANONYMOUS_PARAMETER")
        { view: View ->
            ...
                // answer matches, we have the correct answer.
                if (answers[answerIndex] == currentQuestion.answers[0]) {
                    questionIndex++
                    // Advance to the next question
                    if (questionIndex < numQuestions) {
                        currentQuestion = questions[questionIndex]
                        setQuestion()
                        binding.invalidateAll()
                    } else {
                        // We've won!  Navigate to the gameWonFragment.
                        view.findNavController()
                                .navigate(R.id.action_gameFragment_to_gameWonFragment)
                    }
                } else {
                    // Game over! A wrong answer sends us to the gameOverFragment.
                    view.findNavController()
                            .navigate(R.id.action_gameFragment_to_gameOverFragment)
                }
            }
        }

Change the back button's destination (back stack)

Each time the user goes to a new destination on the device, Android adds that destination to the back stack.

When the user presses the Back button, the app goes to the destination that's at the top of the back stack.

If popUpToInclusive is set to true, the popUpTo attribute removes all destinations up to and including the given destination from the back stack.

If popUpToInclusive is false or is not set, popUpTo removes destination up to the specified desination, but leaves the specified destination in the back stack.


Add an Up button in the app bar

The navigation controller integrates with the app bar to implement the behavior of the Up button, so you don't have to do it yourself.

Open the MainActivity.kt, inside the onCreate() method, add code to find the navigation controller object.

val navController = this.findNavController(R.id.myNavHostFragment)

Also inside the onCreate() method, add code to link the navigation controller to the app bar;

NavigationUI.setupActionBarWithNavController(this,navController)

After the onCreate() method, override the onSupportNavigateUp() method to call navigateUp() in the navigation controller:

override fun onSupportNavigateUp(): Boolean {
        val navController = this.findNavController(R.id.myNavHostFragment)
        return navController.navigateUp()
    }

Add an options menu

Right-click on the res, select New > Android Resource File.

In the New Resource File dialog, name the file options_menu.

Select Menu as the Resource type and click OK.

Open the TitleFragment.kt, inside the onCreateView() method, call the setHasOptionsMenu() method and pass in true.

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                         savedInstanceState: Bundle?): View? {
   ...
   setHasOptionsMenu(true)
   return binding.root
}

After the onCreateView() method, override the onCreateOptionsMenu() method.

override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {
   super.onCreateOptionsMenu(menu, inflater)
   inflater?.inflate(R.menu.options_menu, menu)
}

Override the onOptionsItemSelected() method to take the appropriate action when the menu item is tapped.

The action is to navigate to the fragment that has the same id as the selected menu item.

override fun onOptionsItemSelected(item: MenuItem?): Boolean {
   return NavigationUI.onNavDestinationSelected(item!!,
           view!!.findNavController())
           || super.onOptionsItemSelected(item)
}

Add the navigation drawer

In the app-level Gradle build file, add the dependency for the Material library:z

dependencies {
    ...
    implementation "com.google.android.material:material:$supportlibVersion"
    ...
}

Right-click on the res, select New Resource File.

Name the file navdrawer_menu, set the resource type to Menu.

Open the activity_main.xml, add a DrawerLayout as the root view.

<layout xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto">
   <androidx.drawerlayout.widget.DrawerLayout
       android:id="@+id/drawerLayout"
       android:layout_width="match_parent"
       android:layout_height="match_parent">

   <LinearLayout
       . . . 
       </LinearLayout>
   </androidx.drawerlayout.widget.DrawerLayout>
</layout>

Add the following code after the </LinearLayout> element

<com.google.android.material.navigation.NavigationView
   android:id="@+id/navView"
   android:layout_width="wrap_content"
   android:layout_height="match_parent"
   android:layout_gravity="start"
   app:headerLayout="@layout/nav_header"
   app:menu="@menu/navdrawer_menu" />

Open the MainAcitivity.kt. In onCreate(), add the code that allows user to display the navigation drawer by calling setupWithNavController().

NavigationUI.setupWithNavController(binding.navView, navController)

In the MainActivity.kt, add the lateinit drawerLayout member variable to represent the drawer layout.

private lateinit var drawerLayout: DrawerLayout

Inside the onCreate() method, initialize drawerLayout, after the binding variable has been initialized.

val binding = DataBindingUtil.setContentView<ActivityMainBinding>(this,
                R.layout.activity_main)

drawerLayout = binding.drawerLayout

Add the drawerLayout to the setupActionBarWithNavController() method

NavigationUI.setupActionBarWithNavController(this, navController, drawerLayout)

Edit the onSupportNavigateUp() method to return NavigationUI.navigateUp. Pass the navigation controller and the drawer layout.

override fun onSupportNavigateUp(): Boolean {
   val navController = this.findNavController(R.id.myNavHostFragment)
   return NavigationUI.navigateUp(navController, drawerLayout)
}
import androidx.drawerlayout.widget.DrawerLayout

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章