09_화면 전환_NavHost/NavController/네비게이션

소정·2024년 7월 18일
0

Android_with_compose

목록 보기
9/17

1. build.gradle에 임포트

네비게이션을 사용하기 위해선 디팬던시 필요
Kotlin 1.8.22 버전에 사용할 수 있는 navigation 버전은 2.5.3

implementation 'androidx.navigation:navigation-compose:2.5.3'

2. NavController 만들기

탐색 컨트롤러를 만든다. 탐색 그래프를 보유하고 앱이 그래프(NavHost)의 대상 간에 이동할 수 있는 메서드를 노출한다.
사용자가 방문한 대상을 추적하고 화면을 이동할 수 있도록 허용한다.
앱 화면을 만드는 백 스택과 각 화면의 상태를 유지한다.

@Composable
fun myApp() {
    //NavController는 중심이 되는 API다
    //앱 화면을 만드는 백 스택과 각 화면의 상태를 유지함
    val navController = rememberNavController()
}

3. NavHost만들기

NavHost를 사용하기 위해선 NavController가 필요하다.
이 NavController를 NavHost에 전달할 수 있는데 startDestination을 정의해야한다.

startDestination?
어떤 컴포저블이, 즉 어느 화면이 시작 화면인가 지정하는 것

예시

//startDestination에 시작화면 지정
NavHost(navController = navController, startDestination = Profile) {
    composable<Profile> { ProfileScreen( /* ... */ ) } //개별 화면인 다른 컴포저블을 여기에 지정한다
    composable<FriendsList> { FriendsListScreen( /* ... */ ) }
    // Add more destinations similarly.
}

NavController과 NavHost를 이용 하여 화면간 이동이 가능하도록 연동한다.
NavHost에 rememberNavController()와 기준이 될 화면을 매개변수로 둔다
NavHost함수 안에서 composable을 통해 화면을 식별할 경로 이름을 지정하고 만들어둔 화면과 연동한뒤 navController.navigate를 통해 이동할 화면의 식별이름을 쓴다.

MainActivity.kt

package com.lullulalal.navigationsample

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import com.lullulalal.navigationsample.ui.theme.NavigationSampleTheme

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            NavigationSampleTheme {
                // A surface container using the 'background' color from the theme
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                    myApp()
                }
            }
        }
    }
}

@Composable
fun myApp() {
    //NavController는 중심이 되는 API다
    //앱 화면을 만드는 백 스택과 각 화면의 상태를 유지함
    val navController = rememberNavController()

    NavHost(navController = navController, startDestination = "firstScreen") {
        //composable => 경로와 필요한 경우 인수들을 갖을 수 있다
        //route는 앱 어디서든 화면을 식별하는데 사용함
        composable(route = "firstScreen"){
            //firstScreen을 경로로 하는 컴포저블이 실행될 때 무슨 일이 일어나야 하는지 정의
            FirstScreen {
                navController.navigate("secondScreen")
            }
        }
        composable(route = "secondScreen"){
            SecondScreen{
             navController.navigate("thirdScreen")
            }
        }
        composable("thirdScreen") {
            ThirdScreen {
                navController.navigate("firstScreen")
            }
        }
    }
}

4. 버튼을 이용해 화면을 이동

버튼을 이용해 화면을 이동하기 위해선 두가지 준비가 필요하다
1.실행할 코드나 함수를 전달하는 것, 익명 함수 또는 람다 사용해 간결하게 할 수 있음
fun FirstScreen(navigationToSecondScreen:()->Unit)
2.버튼 안에서 매개변수로 받은 함수 호출

4-1) 첫번쨰 화면

package com.lullulalal.navigationsample

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.lullulalal.navigationsample.ui.theme.NavigationSampleTheme

// 버튼을 이용해 화면을 이동하기 위해선 두가지 준비가 필요하다
//1.실행할 코드나 함수를 전달하는 것, 익명 함수 또는 람다 사용해 간결하게 할 수 있음
//fun FirstScreen(navigationToSecondScreen:()->Unit)
//2.버튼 안에서 매개변수로 받은 함수 호출

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun FirstScreen(navigationToSecondScreen:()->Unit) {
    val name = remember {
        mutableStateOf("")
    }

    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(16.dp),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Text(text = "First", fontSize = 24.sp)
        Spacer(modifier = Modifier.height(16.dp))
        OutlinedTextField(value = name.value, onValueChange = {
            name.value = it
        })
        Button(onClick = {
            navigationToSecondScreen()
        }) {
            Text(text = "이동")
        }
    }
}

@Preview(showBackground = true)
@Composable
fun FirstScreenPreview() {
    NavigationSampleTheme {
        FirstScreen({})
    }
}

4-2) 두번째 화면

package com.lullulalal.navigationsample

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.lullulalal.navigationsample.ui.theme.NavigationSampleTheme

@Composable
fun SecondScreen(navigateToThirdScreen:()->Unit) {
    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(16.dp),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Text(text = "Second", fontSize = 24.sp)
        Text(text = "hihi~", fontSize = 24.sp)
        Button(onClick = {
            navigateToThirdScreen()
        }) {
            Text(text = "Go to Third Screen")
        }
    }
}

@Preview(showBackground = true)
@Composable
fun SecondScreenPreview() {
    NavigationSampleTheme {
        SecondScreen({})
    }
}

4-3) 세번째 화면

package com.lullulalal.navigationsample

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.lullulalal.navigationsample.ui.theme.NavigationSampleTheme

@Composable
fun ThirdScreen(navigationToFirstScreen:()->Unit) {
    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(16.dp),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Text(text = "This is the Third Screen. Go to First Screen", fontSize = 24.sp)
        Text(text = "나는 세번째 화면", fontSize = 24.sp)
        Button(onClick = {
            navigationToFirstScreen()
        }) {
            Text(text = "first로 이동")
        }
    }
}

@Preview(showBackground = true)
@Composable
fun ThirdScreenPreview() {
    NavigationSampleTheme {
        ThirdScreen({})
    }
}

5.화면간 데이터 이동

A화면에서 B화면으로 데이터 주고 B화면에서 받은 데이터를 다시 A화면으로 돌려주기

1. 데이터를 받을 화면에서 매개변수로 받을 자료형과 변수이름 설정

package com.lullulalal.navigationsample

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.lullulalal.navigationsample.ui.theme.NavigationSampleTheme

@Composable
//fun SecondScreen(name:String, navigateToThirdScreen:(nameToFirst)->Unit) {
fun SecondScreen(name:String, navigationToFirstScreen:()->Unit) {
    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(16.dp),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Text(text = "Second", fontSize = 24.sp)
        Text(text = "welcome $name", fontSize = 24.sp)
        Button(onClick = {
//            navigateToThirdScreen()
            navigationToFirstScreen()
        }) {
            Text(text = "Go to Third Screen")
        }
    }
}

@Preview(showBackground = true)
@Composable
fun SecondScreenPreview() {
    NavigationSampleTheme {
        SecondScreen("Rose",{})
    }
}



2. 보내는 화면에서 넘길 데이터 설정

2-1) navigationToSecondScreen() -> Unit에 빈값을 보내고 있었는데
매개변수로 1에게 넘겨줄 데이터의 자료형 쓰기

fun FirstScreen(navigationToSecondScreen:(String)->Unit) {...}

2-2) navigationToSecondScreen호출하는 곳에서 넘겨줄 데이터 매개변수로 넣기

navigationToSecondScreen(name.value)

package com.lullulalal.navigationsample

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.lullulalal.navigationsample.ui.theme.NavigationSampleTheme

// 버튼을 이용해 화면을 이동하기 위해선 두가지 준비가 필요하다
//1.실행할 코드나 함수를 전달하는 것, 익명 함수 또는 람다 사용해 간결하게 할 수 있음
//fun FirstScreen(navigationToSecondScreen:()->Unit)
//2.버튼 안에서 매개변수로 받은 함수 호출

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun FirstScreen(navigationToSecondScreen:(String)->Unit) {
    val name = remember {
        mutableStateOf("")
    }

    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(16.dp),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Text(text = "First", fontSize = 24.sp)
        Spacer(modifier = Modifier.height(16.dp))
        OutlinedTextField(value = name.value, onValueChange = {
            name.value = it
        })
        Button(onClick = {
            navigationToSecondScreen(name.value)
        }) {
            Text(text = "이동")
        }
    }
}

@Preview(showBackground = true)
@Composable
fun FirstScreenPreview() {
    NavigationSampleTheme {
        FirstScreen({})
    }
}

3. NavHost를 작성한 곳에서 세부 사항 추가하기

package com.lullulalal.navigationsample

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import com.lullulalal.navigationsample.ui.theme.NavigationSampleTheme

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            NavigationSampleTheme {
                // A surface container using the 'background' color from the theme
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                    myApp()
                }
            }
        }
    }
}

@Composable
fun myApp() {
    //NavController는 중심이 되는 API다
    //앱 화면을 만드는 백 스택과 각 화면의 상태를 유지함
    val navController = rememberNavController()

    NavHost(navController = navController, startDestination = "firstScreen") {
        //composable => 경로와 필요한 경우 인수들을 갖을 수 있다
        //route는 앱 어디서든 화면을 식별하는데 사용함
        composable(route = "firstScreen"){
            //firstScreen을 경로로 하는 컴포저블이 실행될 때 무슨 일이 일어나야 하는지 정의
            FirstScreen {name, age->
                navController.navigate("secondScreen/$name/$age") //경로에 데이터
            }
        }
        composable(route = "secondScreen/{name}/{age}"){
            val name = it.arguments?.getString("name") ?: "no data"
            val age = it.arguments?.getString("age") ?: "no age"
            //첫번째 화면에서 아무것도 입력하지않고 버튼 클릭하면 no data 나옴
            SecondScreen(name,age){
//             navController.navigate("thirdScreen")
                navController.navigate("firstScreen")
            }
        }
//        composable("thirdScreen") {
//            ThirdScreen {
//                navController.navigate("firstScreen")
//            }
//        }
    }
}



참고 사이트)
https://developer.android.com/develop/ui/compose/navigation?hl=ko

profile
보조기억장치

0개의 댓글