class DiaryActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val diaryDao = DiaryDatabase.getDatabase(application).diaryDao()
val repository = OfflineDiariesRepository(diaryDao)
val viewModelFactory = DiaryViewModelFactory(repository)
val diaryViewModel = ViewModelProvider(this, viewModelFactory)[DiaryViewModel::class.java]
setContent{
val navController = rememberNavController()
//ViewModel 선언
DiaryTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
SetupNavHost(navController = navController, viewModel = diaryViewModel)
}
}
}
}
}
@Composable
fun SetupNavHost(navController: NavHostController, viewModel: DiaryViewModel) {
NavHost(
navController = navController,
startDestination = "list"
) {
composable("list") {
DiariesListScreen(
viewModel,
onNavigateToCreate = {
navController.navigate("create")
},
onDiaryClick = { diaryId ->
navController.navigate("detail/$diaryId")
}
)
}
composable("create") {
DiaryEntryForm(
navController,viewModel
)
}
composable("detail/{id}",
arguments = listOf(navArgument("id") { type = NavType.IntType }) // 인자 정의
) { backStackEntry ->
// 인자 값을 가져와서 사용
val id = backStackEntry.arguments?.getInt("id") ?: return@composable
DiaryDetailScreen(navController,viewModel = viewModel, id = id,onNavigateToUpdate = { diaryId ->
navController.navigate("update/$diaryId")
})
}
composable(
"update/{id}",
arguments = listOf(navArgument("id") { type = NavType.IntType })
) { backStackEntry ->
val id = backStackEntry.arguments?.getInt("id") ?: return@composable
DiaryUpdateForm(viewModel = viewModel, id = id)
}
}
}
@Composable
fun CalendarPicker(onDateSelected: (Date) -> Unit) {
val context = LocalContext.current
// 현재 날짜를 가져옵니다.
val today = Calendar.getInstance()
// 캘린더 아이콘을 클릭하면 DatePickerDialog를 표시합니다.
Icon(
imageVector = Icons.Filled.DateRange,
contentDescription = "Calendar",
modifier = Modifier
.size(40.dp)
.clickable {
// DatePickerDialog 표시, 현재 날짜(today)를 초기값으로 설정합니다.
DatePickerDialog(
context,
{ _, year, month, dayOfMonth ->
// 사용자가 날짜를 선택하면 콜백 함수를 호출합니다.
val selectedCalendar = Calendar
.getInstance()
.apply {
set(year, month, dayOfMonth)
}
onDateSelected(selectedCalendar.time) // 새로운 날짜를 반환합니다.
},
today.get(Calendar.YEAR),
today.get(Calendar.MONTH),
today.get(Calendar.DAY_OF_MONTH)
).show()
}
)
}
fun dateFormatter(selectedDate: String): LocalDateTime {
// 선택된 날짜를 LocalDateTime으로 변환
val date = LocalDate.parse(selectedDate, DateTimeFormatter.ISO_LOCAL_DATE)
// LocalDate를 LocalDateTime으로 변환하면서 시간을 0시 00분으로 설정
return LocalDateTime.of(date, LocalTime.MIDNIGHT)
}
navHostController
를 인자로 전달받을 수 있는데 각각의 장 단점이 확실하고, 아직 Fragment 구성을 확실하게 하지 않아 두가지 방법 다 사용해 보았다.함수를 인자로 받는 경우
NavHostController
를 직접 받는 경우
- 장점: 네비게이션 로직이 컴포저블 내부에서 직접 처리되므로, 관련 로직을 한눈에 볼 수 있고 관리가 용이합니다.
- 단점: 컴포저블의 재사용성이 다소 감소할 수 있으며, NavHostController
에 대한 의존성이 커집니다.
어느 것이 더 효과적인지는 앱의 구조와 사용 사례에 따라 달라질 수 있습니다. 만약 네비게이션 로직이 복잡하고 여러 컴포저블에서 비슷한 네비게이션 동작이 필요한 경우, NavHostController
를 직접 인자로 받는 것이 좋을 수 있습니다. 반면, 컴포저블을 다양한 상황에서 재사용하고자 하거나, 네비게이션 로직을 외부에서 제어하고 싶은 경우에는 함수를 인자로 받는 방식이 더 적합할 수 있습니다.
@Composable
fun SetupNavHost(navController: NavHostController, viewModel: DiaryViewModel) {
NavHost(
navController = navController,
startDestination = "list"
) {
composable("list") {
DiariesListScreen(
viewModel,
onNavigateToCreate = {
navController.navigate("create")
},
onDiaryClick = { diaryId ->
navController.navigate("detail/$diaryId")
}
)
}
composable("create") {
DiaryEntryForm(
navController,viewModel
)
}
composable("detail/{id}",
arguments = listOf(navArgument("id") { type = NavType.IntType }) // 인자 정의
) { backStackEntry ->
// 인자 값을 가져와서 사용
val id = backStackEntry.arguments?.getInt("id") ?: return@composable
DiaryDetailScreen(navController,viewModel = viewModel, id = id,onNavigateToUpdate = { diaryId ->
navController.navigate("update/$diaryId")
})
}
composable(
"update/{id}",
arguments = listOf(navArgument("id") { type = NavType.IntType })
) { backStackEntry ->
val id = backStackEntry.arguments?.getInt("id") ?: return@composable
DiaryUpdateForm(viewModel = viewModel, id = id)
}
}
}
arguments
파라미터: 이 네비게이션 대상으로 전달되는 인자를 정의한다.listOf(navArgument("id") { type = NavType.IntType })
는 id
라는 이름의 인자를 정의하며, 이 인자의 타입이 Int
임을 나타냄backStackEntry -> {...}
: composable
함수에 대한 콜백으로, 네비게이션 대상이 활성화될 때 실행됨.backStackEntry
는 이 네비게이션 대상으로 이동할 때의 상태를 포함하는 객체로 이 객체를 통해 인자 값을 가져올 수 있다.backStackEntry.arguments?.getInt("id") ?: return@composable
:backStackEntry
의 arguments
에서 "id"
인자의 값을 Int
로 가져온다.?.
는 안전 호출 연산자로, arguments
가 null
이 아닐 때만 getInt("id")
를 호출?:
는 엘비스 연산자로, 왼쪽 표현식의 결과가 null
일 경우 오른쪽 값을 사용, 여기서는 null
일 경우 composable
람다 함수에서 반환하여 더 이상 진행하지 않음rememberNavController
함수가 Composable 함수이며, Compose UI의 컨텍스트에서 호출되어야 하기 때문에 setContent
안에서 호출 된다.setContent
는 Compose UI 라이브러리를 사용하는 Android 애플리케이션에서 UI의 최상위 진입점을 정의한다.setContent
내에서 UI를 구성하는 Composable 함수들을 호출한다.