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)
        }
    }
}

這個網誌中的熱門文章

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

2022 最新入門零基礎 Flutter教學 【Flutter 程式設計入門實戰 30 天】Flutter 教學課程目錄 (IntelliJ IDEA 開發教學)

nano 文字編輯器

16天記下7000單字

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