Jetpack Compose 教學上課講義【從零開始學 Jetpack Compose 程式設計】Navigation 頁面跳轉

 

【從零開始學 Jetpack Compose 程式設計】

線上教學課程目錄: https://bit.ly/3JF4SFA
Youtube 課程播放清單:https://bit.ly/3tFjRbx
Udemy 線上課程:https://bit.ly/3MbVnhO


導航原則

https://developer.android.com/guide/navigation/navigation-principles

頁面跳轉範例

https://i.imgur.com/FUP0Voq.jpeg

依賴庫

implementation "androidx.navigation:navigation-compose:2.4.2"

Navigation 基本頁面切換

*先帶大家看 APP 畫面

package com.example.myapplication

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.*
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController


class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            Demo()
        }
    }
}

sealed class Routes(val route: String) {
    object APage : Routes("a_page")
    object BPage : Routes("b_page")
    object CPage : Routes("c_page")
}

@Composable
fun Demo(startDestination: String = Routes.APage.route) {
    val navController = rememberNavController()

    NavHost(
        navController = navController,
        startDestination = startDestination
    ) {
        composable(
            Routes.APage.route
        ) {
            APage(navController)
        }

        composable(
            Routes.BPage.route
        ) {
            BPage(navController)
        }

        composable(
            Routes.CPage.route
        ) {
            CPage(navController)
        }
    }

}

@Composable
fun APage(navController: NavHostController) {
    BasePage("A 頁面內容", "前往") {
        navController.navigate(Routes.BPage.route)
    }
}

@Composable
fun BPage(navController: NavHostController) {
    BasePage("B 頁面內容", "前往") {
        navController.navigate(Routes.CPage.route)
    }
}

@Composable
fun CPage(navController: NavHostController) {
    BasePage("C 頁面內容", "返回") {
        navController.navigateUp()
    }
}

@Composable
fun BasePage(pageContent: String, btnContent: String, onClick: () -> Unit) {
    Column(
        modifier = Modifier.fillMaxSize(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally,
    ) {
        Text(
            pageContent,
            fontSize = 30.sp,
            modifier = Modifier.padding(bottom = 100.dp)
        )
        Button(
            modifier = Modifier
                .width(150.dp)
                .height(100.dp),
            onClick = {
                onClick()
            }
        ) {
            Text(btnContent)
        }
    }
}

返回上一頁

//navigate 會 push 放入 Stack
//navController.navigate(Routes.APage.route)

//navigateUp 會把當下這一頁 pop 出來 
navController.navigateUp

移除過場頁

類似註冊頁,註冊成功移除註冊相關流程頁面,即可以使用 popUpTo

A->B->C->A->A
popUpTo 移除過場頁,返回A頁,可以 pop up 移除B、C頁

A->B->C->A
popUpToInclusive = true 可以減少兩個 A 頁產生。

@Composable
fun CPage(navController: NavHostController) {
    BasePage("C 頁面內容", "返回") {

        navController.navigate(Routes.APage.route){
            popUpTo(Routes.APage.route) {
                inclusive = true
            }
        }
    }
}

完整範例

package com.example.myapplication

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.*
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController


class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            Demo()
        }
    }
}

sealed class Routes(val route: String) {
    object APage : Routes("a_page")
    object BPage : Routes("b_page")
    object CPage : Routes("c_page")
}

@Composable
fun Demo(startDestination: String = Routes.APage.route) {
    val navController = rememberNavController()

    NavHost(
        navController = navController,
        startDestination = startDestination
    ) {
        composable(
            Routes.APage.route
        ) {
            APage(navController)
        }

        composable(
            Routes.BPage.route
        ) {
            BPage(navController)
        }

        composable(
            Routes.CPage.route
        ) {
            CPage(navController)
        }
    }

}

@Composable
fun APage(navController: NavHostController) {
    BasePage("A 頁面內容", "前往") {
        navController.navigate(Routes.BPage.route)
    }
}

@Composable
fun BPage(navController: NavHostController) {
    BasePage("B 頁面內容", "前往") {
        navController.navigate(Routes.CPage.route)
    }
}

@Composable
fun CPage(navController: NavHostController) {
    BasePage("C 頁面內容", "返回") {

        navController.navigate(Routes.APage.route){
            popUpTo(Routes.APage.route) {
                inclusive = true
            }
        }

    }
}

@Composable
fun BasePage(pageContent: String, btnContent: String, onClick: () -> Unit) {
    Column(
        modifier = Modifier.fillMaxSize(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally,
    ) {
        Text(
            pageContent,
            fontSize = 30.sp,
            modifier = Modifier.padding(bottom = 100.dp)
        )
        Button(
            modifier = Modifier
                .width(150.dp)
                .height(100.dp),
            onClick = {
                onClick()
            }
        ) {
            Text(btnContent)
        }
    }
}

Navigation 基本資料傳遞

package com.example.myapplication

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.*
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavHostController
import androidx.navigation.NavType
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import androidx.navigation.navArgument


class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            NavGraph()
        }
    }
}

sealed class Routes(val route: String) {
    object APage : Routes("a_page")
    object BPage : Routes("b_page")
}

@Composable
fun NavGraph(startDestination: String = Routes.APage.route) {
    val navController = rememberNavController()

    NavHost(
        navController = navController,
        startDestination = startDestination
    ) {
        composable(
            Routes.APage.route
        ) {
            APage(navController)
        }

        composable(
            Routes.BPage.route + "/{student_name}/{student_score}",
            arguments = listOf(
                navArgument("student_name") { type = NavType.StringType },
                navArgument("student_score") { type = NavType.IntType },
            ),
        ) {
            BPage(
                navController,
                it.arguments?.getString("student_name", "") ?: "",
                it.arguments?.getInt("student_score") ?: 0,
            )
        }
    }

}

@Composable
fun APage(navController: NavHostController) {
    BasePage("A頁面內容", "前往") {
        navController.navigate(Routes.BPage.route + "/HKT/100")
    }
}

@Composable
fun BPage(navController: NavHostController, student_name: String, student_score: Int) {
    BasePage("B頁面內容 \n 學生姓名:$student_name \n 成績:$student_score", "返回") {
//        navController.navigate(Routes.APage.route)
        navController.navigateUp()
    }
}

@Composable
fun BasePage(pageContent: String, btnContent: String, onClick: () -> Unit) {
    Column(
        modifier = Modifier.fillMaxSize(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally,
    ) {
        Text(
            pageContent,
            fontSize = 30.sp,
            modifier = Modifier.padding(bottom = 100.dp)
        )
        Button(
            modifier = Modifier
                .width(150.dp)
                .height(100.dp),
            onClick = {
                onClick()
            }
        ) {
            Text(btnContent)
        }
    }
}

Navigation 可選參數資料傳遞

package com.example.myapplication

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.*
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavHostController
import androidx.navigation.NavType
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import androidx.navigation.navArgument


class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            NavGraph()
        }
    }
}

sealed class Routes(val route: String) {
    object APage : Routes("a_page")
    object BPage : Routes("b_page")
}

@Composable
fun NavGraph(startDestination: String = Routes.APage.route) {
    val navController = rememberNavController()

    NavHost(
        navController = navController,
        startDestination = startDestination
    ) {
        composable(
            Routes.APage.route
        ) {
            APage(navController)
        }

        composable(
            Routes.BPage.route + "?student_name={student_name}&student_score={student_score}",
            arguments = listOf(
                navArgument("student_name") {
                    type = NavType.StringType
                    defaultValue = "資料錯誤"
                },navArgument("student_score") {
                    type = NavType.IntType
                    defaultValue = -1
                },
            ),
        ) {
            BPage(
                navController,
                it.arguments?.getString("student_name", "資料錯誤") ?: "",
                it.arguments?.getInt("student_score") ?: -1,
            )
        }
    }

}

@Composable
fun APage(navController: NavHostController) {
    BasePage("A頁面內容", "前往") {
//        navController.navigate(Routes.BPage.route + "?student_name=HKT&student_score=100")
        navController.navigate(Routes.BPage.route)
    }
}

@Composable
fun BPage(navController: NavHostController, student_name: String, student_score: Int) {
    BasePage("B頁面內容 \n 學生姓名:$student_name \n 成績:$student_score", "返回") {
//        navController.navigate(Routes.APage.route)
        navController.navigateUp()
    }
}

@Composable
fun BasePage(pageContent: String, btnContent: String, onClick: () -> Unit) {
    Column(
        modifier = Modifier.fillMaxSize(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally,
    ) {
        Text(
            pageContent,
            fontSize = 30.sp,
            modifier = Modifier.padding(bottom = 100.dp)
        )
        Button(
            modifier = Modifier
                .width(150.dp)
                .height(100.dp),
            onClick = {
                onClick()
            }
        ) {
            Text(btnContent)
        }
    }
}

傳遞整包資料

依賴庫

implementation 'com.google.code.gson:gson:2.8.6'

完整範例

package com.example.myapplication

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.*
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavHostController
import androidx.navigation.NavType
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import androidx.navigation.navArgument
import com.google.gson.Gson


class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            NavGraph()
        }
    }
}

data class Student(val name: String, val score: String)

sealed class Routes(val route: String) {
    object APage : Routes("a_page")
    object BPage : Routes("b_page")
}

@Composable
fun NavGraph(startDestination: String = Routes.APage.route) {
    val navController = rememberNavController()

    NavHost(
        navController = navController,
        startDestination = startDestination
    ) {
        composable(
            Routes.APage.route
        ) {
            APage(navController)
        }

        composable(
            Routes.BPage.route + "/{student}",
            arguments = listOf(
                navArgument("student") { type = NavType.StringType }
            ),
        ) {
            val defaultStudent = it.arguments?.getString("student", "") ?: ""
            val student = Gson().fromJson(defaultStudent, Student::class.java)
            BPage(
                navController,
                student
            )
        }
    }

}

@Composable
fun APage(navController: NavHostController) {
    val student = Student("HKT", "100")
    val gson = Gson().toJson(student)

    BasePage("A頁面內容", "前往") {
        navController.navigate(Routes.BPage.route + "/$gson")
    }
}

@Composable
fun BPage(navController: NavHostController, student: Student) {

    BasePage("B頁面內容 \n 學生姓名:${student.name}  \n 成績:${student.score}", "返回") {
        navController.navigateUp()
    }
}

@Composable
fun BasePage(pageContent: String, btnContent: String, onClick: () -> Unit) {
    Column(
        modifier = Modifier.fillMaxSize(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally,
    ) {
        Text(
            pageContent,
            fontSize = 30.sp,
            modifier = Modifier.padding(bottom = 100.dp)
        )
        Button(
            modifier = Modifier
                .width(150.dp)
                .height(100.dp),
            onClick = {
                onClick()
            }
        ) {
            Text(btnContent)
        }
    }
}

這個網誌中的熱門文章

nano 文字編輯器

16天記下7000單字

2023 最新入門零基礎 Kotlin教學【從零開始學 Kotlin 程式設計】Kotlin 教學課程目錄 (Android Kotlin, IntelliJ IDEA, Android Studio, Android APP 開發教學)

最新入門零基礎 Java 教學【從零開始學 Java 程式設計】Java教學課程目錄 (IntelliJ IDEA 開發教學)

Android Studio 歷代版本下載點