일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 막내의막무가내
- 막내의막무가내 프로그래밍
- 안드로이드 sunflower
- 막내의막무가내 rxjava
- 막내의막무가내 코틀린 안드로이드
- 막내의막무가내 안드로이드 에러 해결
- 2022년 6월 일상
- 부스트코스에이스
- 막내의막무가내 안드로이드
- 주엽역 생활맥주
- 막내의막무가내 플러터 flutter
- 막내의 막무가내
- 막내의막무가내 SQL
- 막내의막무가내 안드로이드 코틀린
- 안드로이드
- 막내의막무가내 플러터
- 막내의막무가내 코틀린
- 막내의막무가내 일상
- 막내의막무가내 코볼 COBOL
- 프래그먼트
- Fragment
- 막무가내
- 부스트코스
- flutter network call
- 안드로이드 Sunflower 스터디
- 막내의막무가내 알고리즘
- 막내의막무가내 목표 및 회고
- 막내의 막무가내 알고리즘
- 프로그래머스 알고리즘
- 주택가 잠실새내
- Today
- Total
막내의 막무가내 프로그래밍 & 일상
[안드로이드] 구글 공식 프로젝트 Sunflower 스터디 (3) Jetpack Navigation 구조 본문
[안드로이드] 구글 공식 프로젝트 Sunflower 스터디 (3) Jetpack Navigation 구조
막무가내막내 2021. 4. 19. 13:50
[Jetpack Navigation 구조]
[참고]
developer.android.com/guide/navigation?hl=ko
앞선 (1) 패키지 구조 포스팅에서 말했듯이 이 프로젝트는 SPA(Single-Page-Application) 싱글 액티비티 디자인 구조로 되어있으므로 하나의 액티비티와 다수의 프래그먼트가 존재한다.
이 프로젝트에서는 Jetpack Navigation에서 제공해주는 바텀네비게이션, 툴바를 사용하지는 않았고 메인 액티비티에 Toolbar + ViewPager2 + TabLayout 구조를 가진 Fragment 가 세팅되고 프래그먼트가 전환되는 식이다. 추가로 프래그먼트에서 아이템을 누르면 상세화면으로 가는 네비게이션을 갖고있다.
Jetpack Navigation은 싱글 액티비티 디자인, 프래그먼트를 적극적으로 활용할때 강한 이점이 있다.
프로젝트에서는 위 사진의 기능들을 대부분 사용한다. 한번 살펴보도록 하겠다.
먼저 디자인이다.
[GardenActivity XML]
단 하나인 메인 액티비티를 담당하는 부분이다. XML을 보면 navGraph와 defaultNavHost가 설정되어 있다. 이이 대해서 포스팅에 기록한 경험이 있다.
간단히 설명하면
- app:navGraph 속성은 NavHostFragment를 탐색 그래프와 연결합니다. 탐색 그래프는 사용자가 이동할 수 있는 이 NavHostFragment의 모든 대상을 지정합니다.
- app:defaultNavHost="true" 속성을 사용하면 NavHostFragment가 시스템 뒤로 버튼을 가로챕니다. 하나의 NavHost만 기본값으로 지정할 수 있습니다. 동일한 레이아웃에 여러 호스트가 있다면(예: 창이 2개인 레이아웃) 한 호스트만 기본 NavHost로 지정해야 합니다
youngest-programming.tistory.com/274
nav_garph.xml 에서 app:startDestination 보면 FragmentContainerView 에 ViewPager2 가 세팅된다.
<layout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/nav_host"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_garden" />
</layout>
[nav_graph XML]
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
app:startDestination="@id/view_pager_fragment">
<fragment
android:id="@+id/view_pager_fragment"
android:name="com.google.samples.apps.sunflower.HomeViewPagerFragment"
tools:layout="@layout/fragment_view_pager">
<action
android:id="@+id/action_view_pager_fragment_to_plant_detail_fragment"
app:destination="@id/plant_detail_fragment"
app:enterAnim="@anim/slide_in_right"
app:exitAnim="@anim/slide_out_left"
app:popEnterAnim="@anim/slide_in_left"
app:popExitAnim="@anim/slide_out_right" />
</fragment>
<fragment
android:id="@+id/plant_detail_fragment"
android:name="com.google.samples.apps.sunflower.PlantDetailFragment"
android:label="@string/plant_details_title"
tools:layout="@layout/fragment_plant_detail">
<action
android:id="@+id/action_plant_detail_fragment_to_gallery_fragment"
app:destination="@id/gallery_fragment"
app:enterAnim="@anim/slide_in_right"
app:exitAnim="@anim/slide_out_left"
app:popEnterAnim="@anim/slide_in_left"
app:popExitAnim="@anim/slide_out_right" />
<argument
android:name="plantId"
app:argType="string" />
</fragment>
<fragment
android:id="@+id/gallery_fragment"
android:name="com.google.samples.apps.sunflower.GalleryFragment"
android:label="@string/plant_details_title"
tools:layout="@layout/fragment_gallery">
<argument
android:name="plantName"
app:argType="string" />
</fragment>
</navigation>
Arguments에 대해 보겠다.
Jetpack Navigation의 디자인은 위와 같이 3개의 화면으로 이루어져있다. 그리고 각 화면이동간에 커스텀 anim이 구현되어 있다. 또한 넘길 arguments들도 설정되어 있다.
이에 대해서도 이전에 정리한 경험이 있다.
youngest-programming.tistory.com/332
HomeViewPagerFragment(홈 식물 리스트 프래그먼트 화면) -> PantDetailFragment(식물 상세화면) 예시하나만 살펴보겠다.
nav_graph.xml 을 보면 PlantDetailFragment 는 plantId라는 String 타입 매개변수를 전달받는다.
<fragment
android:id="@+id/plant_detail_fragment"
android:name="com.google.samples.apps.sunflower.PlantDetailFragment"
android:label="@string/plant_details_title"
tools:layout="@layout/fragment_plant_detail">
<action
android:id="@+id/action_plant_detail_fragment_to_gallery_fragment"
app:destination="@id/gallery_fragment"
app:enterAnim="@anim/slide_in_right"
app:exitAnim="@anim/slide_out_left"
app:popEnterAnim="@anim/slide_in_left"
app:popExitAnim="@anim/slide_out_right" />
<argument
android:name="plantId"
app:argType="string" />
</fragment>
그리고 HomeViewPager에서는 <action> 으로 PantDetailFragment 로 Direction이 설정되어 있다. 이렇게 설정해놓으면 빌드시 자동으로 NavController에서 네비게이션하는 함수가 만들어진다.
<fragment
android:id="@+id/view_pager_fragment"
android:name="com.google.samples.apps.sunflower.HomeViewPagerFragment"
tools:layout="@layout/fragment_view_pager">
<action
android:id="@+id/action_view_pager_fragment_to_plant_detail_fragment"
app:destination="@id/plant_detail_fragment"
app:enterAnim="@anim/slide_in_right"
app:exitAnim="@anim/slide_out_left"
app:popEnterAnim="@anim/slide_in_left"
app:popExitAnim="@anim/slide_out_right" />
</fragment>
[HomeViewPagerFragment - PlantListFragment - PlantAdapter]
ViewPager 안의 PlantListFragment 리사이클러뷰의 PlantAdater 에 아이템 클릭시 식물 상세화면으로 가는 이벤트가 구현되어 있다.
Jetpack Navigation Graph에 의해 자동으로 만들어진 Directions 객체와 action 함수를 통해 프래그먼트간 전환 및 값 전달을 하게 되는 것을 볼 수 있다.
class PlantAdapter : ListAdapter<Plant, RecyclerView.ViewHolder>(PlantDiffCallback()) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return PlantViewHolder(
ListItemPlantBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val plant = getItem(position)
(holder as PlantViewHolder).bind(plant)
}
class PlantViewHolder(
private val binding: ListItemPlantBinding
) : RecyclerView.ViewHolder(binding.root) {
init {
binding.setClickListener {
binding.plant?.let { plant ->
navigateToPlant(plant, it)
}
}
}
// 이 부분을 보면 된다. Jetpack Navigation Direction
private fun navigateToPlant(
plant: Plant,
view: View
) {
val direction =
HomeViewPagerFragmentDirections.actionViewPagerFragmentToPlantDetailFragment(
plant.plantId
)
view.findNavController().navigate(direction)
}
fun bind(item: Plant) {
binding.apply {
plant = item
executePendingBindings()
}
}
}
}
private class PlantDiffCallback : DiffUtil.ItemCallback<Plant>() {
override fun areItemsTheSame(oldItem: Plant, newItem: Plant): Boolean {
return oldItem.plantId == newItem.plantId
}
override fun areContentsTheSame(oldItem: Plant, newItem: Plant): Boolean {
return oldItem == newItem
}
}
[PlantDetailFragment]
by navArgs 로 값을 전달받는 것을 볼 수 있다.
@AndroidEntryPoint
class PlantDetailFragment : Fragment() {
private val args: PlantDetailFragmentArgs by navArgs()
@Inject
lateinit var plantDetailViewModelFactory: PlantDetailViewModelFactory
private val plantDetailViewModel: PlantDetailViewModel by viewModels {
PlantDetailViewModel.provideFactory(plantDetailViewModelFactory, args.plantId)
}
Anim에 대해 보겠다.
커스텀 애니메이션이 구현되어있는 것을 볼 수 있다.
이거에 대해서는 이전에 포스팅 한 경험이 있으니 참고하면 좋을 것 같다.
youngest-programming.tistory.com/483
Jetpack Navigation 디자인만으로는 완전한 디자인을 보기 힘드므로 원본 앱 사진을 보면 크게 ViewPager 구조에 내 정원과 식물 리스트 두개의 탭이 있고 식물의 상세화면이 존재한다.
댓글과 공감은 큰 힘이 됩니다. 감사합니다. !!
'안드로이드 > 코틀린 & 아키텍처 & Recent' 카테고리의 다른 글
[안드로이드] 구글 공식 프로젝트 Sunflower 스터디 (5) MVVM - View (0) | 2021.04.19 |
---|---|
[안드로이드] 구글 공식 프로젝트 Sunflower 스터디 (4) Hilt Dependency Injection (10) | 2021.04.19 |
[안드로이드] 구글 공식 프로젝트 Sunflower 스터디 (2) 패키지 구조 (0) | 2021.04.19 |
[안드로이드] 구글 공식 프로젝트 Sunflower 스터디 (1) 개요 (0) | 2021.04.19 |
[안드로이드] 카카오링크 API 구현 방법 (feat. 카카오톡 공유하기 기능, 피드형 메시지) (2) | 2021.04.08 |