업데이트:

카테고리:

/

태그: , , ,

무엇을 배우는가?

  1. Fragment를 앱에 정적으로 추가하는 법
  2. navigation 사용, 앱에 경로 정의하기
  3. 메뉴 만들기

1. Fragment 추가

FragmentFragmentAcivity내부에 있는 어떤 동작 또는 사용자 인터페이스의 일부이다.
여러 개의 프래그먼트를 하나의 액티비티에 결합해 창이 여러개인 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: 확장할 레이아웃의 ID
  • ViewGroup
    • attachToParent true : 생성된 계층의 부모가 되는 선택적 뷰
    • attachToParent false : 반환된 계층의 루트에 대한 LayoutParams 값 집합을 제공하는 객체

2. Fragment를 메인 액티비티에 추가

activity_main.xml파일에 fragment태그를 사용해 넣어준다.
name을 적어주어야 하며, 인자로는 연결될 코틀린 파일의 경로가 들어간다.

INSTALL_PARSE_FAILED_MANIFEST_MALFORMED in Android12

Android 12 버전을 실행하기 위해서는 2가지 조건이 필요하다.

  1. complieSDK와 targetSdkVersion가 31 이상일것
  2. 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"
}

res 폴더에 Resource File을 추가한다.
이 때 resource TypeNavigation으로 설정하고 하단 박스에는 아무것도 넣지 않고 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 TypeMenu로 하나 생성한다.
여기에서는 일반 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)
}

메뉴버튼 ☰

위와는 다르게 한쪽면을 드래그하면 나타나는 메뉴버튼이다.

  1. 의존성 추가하기
      implementation "com.google.android.material:material:$version"
    
  2. fragment의 목적지 확인하기
  3. 연결할 fragment나 activity의 layout 과 LinearLayout 사이에 아래코드 추가하기
     <androidx.drawerlayout.widget.DrawerLayout 
       android:id="@+id/drawerLayout"
       android:layout_width="match_parent"
       android:layout_height="match_parent">
    
  4. </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" />
    
  5. 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)
       }