티스토리 뷰

아래는 코모스튜디오가 직접 만든 무료 앱이에요

(한 번만 봐주세요 ^^)

01

02

03

정각알림 만들기(말하는시계)

말하는 시계 (취침, 자전거) 

말하는 타이머 음성 스톱워치 

Activity

 

최초 액티비티에서

  • activity_garden 을 layout으로 설정하게 되면
GardenActivity.kt

class GardenActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView<ActivityGardenBinding>(this, R.layout.activity_garden)
    }
}

NagGraph

 

R.layout.activity_garden 에서는

  • 이후 연결되는 view들을 아래와 같이 관리할 navigaion을 지정한다.
  • app:navGraph="@navigation/nav_garden"
R.layout.activity_garden.xml

<layout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <fragment
            android:id="@+id/nav_host"
            android:name="androidx.navigation.fragment.NavHostFragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            //뒤로 가기 설정
            app:defaultNavHost="true"
            //navigaion 지정
            app:navGraph="@navigation/nav_garden"/>

    </FrameLayout>

</layout>

Navigation

 My Garden > Plant List > Detail

Sunflower는 크게 3가지 View로 이루어져 있는데

이 뷰들이 위 navGraph로 연결되어 관리되는데, 이후에는 safe argument를 통해 뷰 아이템들의 id 등을 쉽게 가져와서 사용할 수 있다.

 

ViewPager

  • GardenFragment
    • 심은 식물을 담는 RecyclerView
  • PlantListFragment(RecyclerView)
    • 모든 식물을 보여주는 RecyclerView 
    • DetailFragment
      • 선택된 식물의 정보와 담기 버튼

이 구조는 JetPack의 Navigation으로 정의가 된다.

app:startDestination=시작될 뷰를 ViewPager로 넣었으며

app:destination = 이동할 뷰를 DetailFragment로 넣었다.

nav_garden.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"
        tools:layout="@layout/fragment_view_pager">

        <action
                android:id="@+id/action_view_pager_fragment_to_plant_detail_fragment"
                //navigate() 할 경우 이동할 View
                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: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>

이와 같이 정의를 하면 아래 그림처럼 그래프로 표시된다

navigation desgin

아이템 클릭 navigate

 

PlantList에서 아이템 하나를 클릭할 경우

위 navigation에서 destination으로 등록된 곳으로 보내는데, navigate()를 사용해서 화면을 이동시킨다.

이때 Safe Argument를 사용한다.

  • app:destination으로 등록하면,
  • HomeViewPagerFragmentDirections처럼 뒤에 Directions 클래스가 생성되며
  • Safe Argument를 담을 수 있는
  • actionViewPagerFragmentToPlantDetailFragment 가 생성된다.
  • argument를 HomeViewPagerFragmentDirections로 안전하게 담은 뒤 destination으로 이동한다.
PlantListFramgment.kt

class PlantViewHolder(
        private val binding: ListItemPlantBinding
    ) : RecyclerView.ViewHolder(binding.root) {
        init {
            binding.setClickListener {
                binding.plant?.let { plant ->
                    navigateToPlant(plant, it)
                }
            }
        }

        private fun navigateToPlant(
            plant: Plant,
            view: View
        ) {
            val direction =
                HomeViewPagerFragmentDirections.actionViewPagerFragmentToPlantDetailFragment(
                    plant.plantId
                )
            //app:destination 으로 등록 하면, 
            //HomeViewPagerFragmentDirections 처럼 뒤에 Directions 클래스가 생성되며 
            //safe argument 를 담을 수 있는 
            //actionViewPagerFragmentToPlantDetailFragment 가 생성된다.
            //argument 를 HomeViewPagerFragmentDirections 로 안전하게 담은 뒤,
            //destination 이동한다.
            //이동이 된 뒤, DetailFragment 에서는 이를 arg by navArg() 로 받아 와서 사용한다.
            view.findNavController().navigate(direction)
        }

        fun bind(item: Plant) {
            binding.apply {
                plant = item
                executePendingBindings()
            }
        }
    }

Detail Fragment 설정

 

navigate(direction)을 통해 Detail View로 이동 한 뒤,

안전하게 담아온 Safe argument는 아래와 같이 ktx navArgs()로 위임하여 받아 올 수 있다.

그리고, 받아온 plantId로 Db에서 해당 식물의 자료를 가져와서 상세(Detail) 뷰에서 사용할 View Model을 생성한다.

참고) ViewModel 주입하기는 이 링크 참조 [Sunflower 디비 보기] ViewModel 주입(초기화) 과정

PlantDetailFragment.kt

class PlantDetailFragment : Fragment() {

//navArgs()로 safe argument 가져오기
    private val args: PlantDetailFragmentArgs by navArgs()

//ViewModel 주입
    private val plantDetailViewModel: PlantDetailViewModel by viewModels {
        InjectorUtils.providePlantDetailViewModelFactory(requireActivity(), args.plantId)
    }

코틀린 코드는 아래와 같이 Java에서 getArgument()로 받아오는 코드와 동일 하지만, ktx를 이용하여 코드의 깔끔함과 안전함을 더 하게 되었다.

Java Code
   
   arg = PlantDetailFragmentArgs.fromBundle(getArguments()).getPlantId();

 

Summary

 

여기까지 하면 앱 시작점과 View의 연결 그리고 이동에 대한 기본이 완성된다.

 

그리고, JetPack의 Navigation을 사용하면 위와 같이 깔끔하게 앱 내 뷰의 배치 및 이동 연결 관계를 정의할 수 있으며, Safe Argument를 통해 데이터도 쉽고 안전하게 주고받을 수 있다.

 

Android AAC JetPack Sunflower
이 글은 코모가 구글 안드로이드 Sunflower디비보기 한 것입니다.

모든 게시물은 코모스튜디오의 소유이며, 무단 복제 수정은 절대 불가입니다.
퍼가실 경우 댓글과 블로그 주소를 남기고 해당 게시물에 출처를 명확히 밝히세요.
댓글
댓글쓰기 폼