Android Navigation
업데이트:
카테고리: Android
/태그: findNavController, Fragment, Menu, Navigation
무엇을 배우는가?
- Fragment를 앱에 정적으로 추가하는 법
- navigation 사용, 앱에 경로 정의하기
- 메뉴 만들기
1. Fragment 추가
Fragment
는 FragmentAcivity
내부에 있는 어떤 동작 또는 사용자 인터페이스의 일부이다.
여러 개의 프래그먼트를 하나의 액티비티에 결합해 창이 여러개인 UI를 만들 수 있고, 하나의 프래그먼트를 여러 액티비티에서 재사용할 수 있다.
react나 vue의 컴포넌트와 비슷한 개념
프래그먼트는 항상 액티비티 내에서 호스팅해야 되고 호스팅 액티비티의 수명 주기에 직접적으로 영향을 받는다.
Fragment는 MainActivity가 있는 폴더 내부에 Fragment로 생성한다.
그럼 자동으로 Kotlin과 xml파일이 생성된다.
처음에 생성하면 컴파일이 진행되지 않는다. 그렇기에 바인딩 객체를 생성해 프래그먼트의 뷰를 확장시켜야 한다.(메인액티비티에 setContentView()를 하는것과 동일)
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
val binding = DataBindingUtil.inflate<FragmentTitleBinding>(inflater, R.layout.fragment_title, container, false)
return binding.root
}
데이터 바인딩을 해주기 위해서 DataBindingUtil.inflate
을 사용한다.
해당 함수에는 4개의 인자가 있다.
LayoutInflator
: 바인딩 레이아웃을 확장하는데 사용하는 인자inlflator
: 확장할 레이아웃의 IDViewGroup
attachToParent
true : 생성된 계층의 부모가 되는 선택적 뷰attachToParent
false : 반환된 계층의 루트에 대한 LayoutParams 값 집합을 제공하는 객체
2. Fragment를 메인 액티비티에 추가
activity_main.xml
파일에 fragment
태그를 사용해 넣어준다.
꼭 name을 적어주어야 하며, 인자로는 연결될 코틀린 파일의 경로가 들어간다.
INSTALL_PARSE_FAILED_MANIFEST_MALFORMED in Android12
Android 12 버전을 실행하기 위해서는 2가지 조건이 필요하다.
- complieSDK와 targetSdkVersion가 31 이상일것
- androidManifest에 activity, service, recevier 등에
android:exported=""
옵션이 있는가
이 두가지 중 2번째가 설정이 따로 되어있지 않아 추가를 하니 빨간줄도 사라지고 에러 없이 잘 구동되었다.
3. Navigation 사용하기 위한 사전작업
의존성 추가
build.gradle (Project: ...)
에 들어가 아래 코드를 추가한다.
ext {
...
navigationVersion = "2.3.0"
...
}
그리고 module의 build.gradle
에도 아래 코드를 추가해준다.
dependencies {
implementation "androidx.navigation:navigation-fragment-ktx:$navigationVersion"
implementation "androidx.navigation:navigation-ui-ktx:$navigationVersion"
}
Navigation 파일 추가
res 폴더에 Resource File
을 추가한다.
이 때 resource Type을 Navigation으로 설정하고 하단 박스에는 아무것도 넣지 않고 OK를 눌러준다.
그리고 acitivty_main.xml
파일에 아래 코드를 넣어준다.
<fragment
android:id="@+id/myNavHostFragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="@navigation/navigation"/>
navigation.xml
파일은 현재가지고 있는 fragment들을 연결할 수 있는 공간이다.
현재 어떤 버튼을 클릭하면 다음으로 어디를 이동할 지 지정할 수 있다.
해당 버튼을 클릭하였을 때 이동하는 리스너를 추가해준다.
view.findNavController().navigate(R.id.action_gameFragment_to_gameWonFragment)
뒤로 버튼 클릭시 이전 경로로 이동
navigation 파일에 연결된 경로를 클릭하면 Pop Behavior
이라는 탭이 있다.
popUpTo
: 뒤로가기 버튼을 클릭하였을 때 어디로 이동하는 지 입력popUpToLinclusive
: popUpTo로 지정한 fragment까지 pop할 것인지 결정하는 속성
이후에는 navigate를 연결하는 것과 동일한 순서로 작성하면 된다.
4. 앱 바 버튼
뒤로가기
navigation components는 NavigationUI
라이브러리가 포함되어 있다.
onCreate()
안에는 밑의 코드를 작성해준다.
val navController = this.findNavController(R.id.myNavHostFragment)
NavigationUI.setupActionBarWithNavController(this, navController)
그리고 하단에는 해당코드를 작성해주면 앱 상단의 뒤로가기 버튼을 만들 수 있다.
override fun onSupportNavigateUp(): Boolean {
val navController = this.findNavController(R.id.myNavHostFragment)
return navController.navigateUp()
}
메뉴버튼 ⁝
res
폴더에 Resource Type을 Menu
로 하나 생성한다.
여기에서는 일반 layout처럼 디자인 요소를 추가해 메뉴를 만들 수 있다.
디자인을 완료한 후 해당 메뉴버튼을 사용할 fragment나 activity의 onCreateView()
안에 setHasOptionsMenu(true)
을 추가한다.
그리고 onCreateView()
하단에 아래 코드를 작성한다.
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
super.onCreateOptionsMenu(menu, inflater)
inflater.inflate(R.menu.options_menu, menu)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return NavigationUI.onNavDestinationSelected(item, requireView().findNavController()) || super.onOptionsItemSelected(item)
}
메뉴버튼 ☰
위와는 다르게 한쪽면을 드래그하면 나타나는 메뉴버튼이다.
- 의존성 추가하기
implementation "com.google.android.material:material:$version"
- fragment의 목적지 확인하기
- 연결할 fragment나 activity의 layout 과 LinearLayout 사이에 아래코드 추가하기
<androidx.drawerlayout.widget.DrawerLayout android:id="@+id/drawerLayout" android:layout_width="match_parent" android:layout_height="match_parent">
</LinearLayout>
뒤에 아래코드 추가하기<com.google.android.material.navigation.NavigationView android:id="@+id/navView" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="start" app:headerLayout="@layout/nav_header" app:menu="@menu/navdrawer_menu" />
MainActivity
에 메뉴 연결하기// drawerLayout 설정하기 위해 미리 선언 private lateinit var drawerLayout: DrawerLayout override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @Suppress("UNUSED_VARIABLE") val binding = DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main) drawerLayout = binding.drawerLayout val navController = this.findNavController(R.id.myNavHostFragment) NavigationUI.setupActionBarWithNavController(this, navController, drawerLayout) NavigationUI.setupWithNavController(binding.navView, navController) } override fun onSupportNavigateUp(): Boolean { val navController = this.findNavController(R.id.myNavHostFragment) return NavigationUI.navigateUp(navController, drawerLayout) }