[Android] JetPack의 View 정리

Minjun Kim·2023년 8월 30일
0

Android

목록 보기
29/47
post-thumbnail

📝 SeSAC의 'JetPack과 Kotlin을 활용한 Android App 개발' 강좌를 정리한 글 입니다.


💬 JetPack 개요

❓ JetPack 이란?

구글에서 안드로이드 개발을 위해 지원하는 다양한 라이브러리의 집합

대부분 androidx 로 시작하는 패키지명을 사용하는 라이브러리

과거에 구글에서 support 라이브러리 를 제공 했었다. 네이밍이 support로 시작하고 종류가 꽤 많았다.

이것을 2017년도에 JetPack 으로 통합했다. 원래는 별개의 라이브러리들이 모두 androidx 가 붙은 라이브러리가 되었다.

  • 앱 개발의 권장 아키텍처 제공 (AAC)

  • API Level 에 의한 호환성 문제 해결

  • 표준에서 제공하지 못하는 다양한 기능 제공

🧩 androidx 라이브러리

이 외에도 다양한 라이브러리를 제공한다.

  • androidx.appcompat : 앱의 API Level 호환성 라이브러리

  • androidx.recyclerview : 목록화면 구성 라이브러리

  • androidx.viewpage2 : 스와이프에 의한 화면 구성 라이브러리

  • androidx.fragment : 액티비티 처럼 동작하는 뷰 제공 라이브러리

  • androidx.drawerlayout : 옆에서 밀리면서 보여지는 화면 구성 라이브러리


📇 Fragment

  • 프래그먼트는 뷰이다

  • 자체적으로는 화면에 아무것도 출력되지 않는다 (물론 레이아웃은 아니다)

  • 액티비티처럼 동작하는 뷰

  • 액티비티에 작성할 수 있는 모든 코드를 프래그먼트에 작성이 가능

이런 의문이 생길 수 있다.

"액티비티에 작성할 수 있는 코드를 프래그먼트에 작성할 수 있다면,
그냥 액티비티에 코드를 작성해서 액티비티를 사용하면 되는 거 아니냐"

  • 일차적으로는 액티비티의 코드 자체를 줄일 수 있다. 각각 프래그먼트를 작성한 다음, 액티비티는 각각의 프래그먼트를 출력만 해주는 방식을 취할 수 있다. 코드도 분리되고 액티비티의 코드도 줄어든다.

  • 심화적으로는 화면전환의 효과를 낼 수 있다. Fragment A 와 Fragment B 를 그저 번갈아 띄워주는 것으로 화면 전환 효과를 낼 수 있다. 유저 입장에서는 완벽히 분리된 화면 2장이라고 생각된다.

📚 사용 방법

📌 Fragment 클래스 정의

class OneFragment : Fragment() {
	//..........
}
  • Fragment 를 상속받아 작성하는 클래스

📌 정적 등록

<fragment
	android:name="com.example.OneFragment"
    android:id="@+id/fragmentView"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
  • 액티비티의 레이아웃 XML 에 등록하여 프래그먼트 출력

  • name 속성으로 프래그먼트 클래스 등록

📌 동적 등록

val fragmentManager: FragmentManager = supportFragmentManager
val transaction: FragmentTransaction = fragmentManager.beginTransaction()

transaction.add(R.id.fragment_content, oneFragment)
transaction.commit()
  • 액티비티 코드에서 프래그먼트 출력

  • add(int containerViewId, Fragment fragment) : 새로운 Fragment를 화면에 추가, id 영역에 추가한다.

  • replace(int containerViewId, Fragment fragment) : id 영역에 추가된 Fragment를 대체

  • remove(Fragment fragment) : 추가된 Fragment 제거

  • commit() : 화면 적용

🧩 실습 예제

  • fragment_one.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".OneFragment">

    <!-- TODO: Update blank fragment layout -->
    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="I am OneFragment" />

</FrameLayout>

  • fragment_two.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".TwoFragment">

    <!-- TODO: Update blank fragment layout -->
    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="I am TwoFragment" />

</FrameLayout>

  • OneFragment.kt
package com.kotdev99.android.c91

class OneFragment : Fragment() {

	override fun onCreateView(
		inflater: LayoutInflater, container: ViewGroup?,
		savedInstanceState: Bundle?
	): View? {
		// Inflate the layout for this fragment
		return inflater.inflate(R.layout.fragment_one, container, false)
	}
}

  • TwoFragment.kt
package com.kotdev99.android.c91

class TwoFragment : Fragment() {

	override fun onCreateView(
		inflater: LayoutInflater, container: ViewGroup?,
		savedInstanceState: Bundle?
	): View? {
		// Inflate the layout for this fragment
		return inflater.inflate(R.layout.fragment_two, container, false)
	}
}

  • activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <LinearLayout
        android:id="@+id/fragment_content"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:orientation="vertical">

    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <Button
            android:id="@+id/oneButton"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="one" />

        <Button
            android:id="@+id/twoButton"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="two" />
    </LinearLayout>

</LinearLayout>

  • MainActivity.kt
package com.kotdev99.android.c91

class MainActivity : AppCompatActivity() {

	private lateinit var binding: ActivityMainBinding

	override fun onCreate(savedInstanceState: Bundle?) {
		super.onCreate(savedInstanceState)

		binding = ActivityMainBinding.inflate(layoutInflater)
		setContentView(binding.root)

		val oneFragment = OneFragment()
		val twoFragment = TwoFragment()

		val manager = supportFragmentManager
		val transaction = manager.beginTransaction()

		transaction.add(R.id.fragment_content, oneFragment)
		transaction.commit()

		binding.oneButton.setOnClickListener {
			// commit() 을 하면 트랜잭션 객체는 닫힌다. 때문에 다시 얻어 주어야 한다.
			val tran = manager.beginTransaction()
			tran.replace(R.id.fragment_content, oneFragment)
			tran.commit()
		}
		binding.twoButton.setOnClickListener {
			// commit() 을 하면 트랜잭션 객체는 닫힌다. 때문에 다시 얻어 주어야 한다.
			val tran = manager.beginTransaction()
			tran.replace(R.id.fragment_content, twoFragment)
			tran.commit()
		}
	}
}

📲 결과


💬 RecyclerView

androidx 에서 제공

구성 요소

필수
Adapter, ViewHolder, LayoutManager

옵션
ItemDecoration, ItemAnimation

역할

Adapter : 항목을 구성하는 역할

ViewHolder : 항목에 필요한 뷰 객체를 가지는 역할

LayoutManager : 항목을 배치하는 역할

ItemDecoration : 항목을 꾸미기 위한 역할

ViewHolder 는 RecyclerView.ViewHolder 를 상속 받아 작성

class MyViewHolder(val binding: ItemMainBinding) : RecyclerView.ViewHolder(binding.root)

커스텀뷰의 홀더 클래스에서 처럼 원래는 findViewById로 객체를 획득했으나,
ViewBinding으로 대체되었다.

매개변수 val binding: ItemMainBinding 가 바로 뷰 바인딩 객체를 뜻한다.

Adapter 는 RecyclerView.Adapter 를 상속받아 작성

getItemCount() : 항목 개수를 판단하기 위해 자동 호출

onCreateViewHolder() : 항목의 뷰를 가지는 ViewHolder 를 준비하기 위해 자동 호출

onBindViewHolder() : ViewHolder 의 뷰에 데이터를 출력하기 위해서 자동 호출

class MyAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
	override fun getItemCount(): Int {
 		TODO("Not yet implemented") 
	}

	override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) : RecyclerView.ViewHolder {
		TODO("Not yet implemented")
	}

	override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
		TODO("Not yet implemented")
	}
}
  • onCreateViewHolder 에서 만든 뷰 객체가 onBindViewHolder 의 holder 매개변수에 전달된다.

RecyclerView 에 Adapter 와 LayoutManager 를 등록시켜 화면에 출력

binding.recycler.layoutManager = LinearLayoutManager(this)
binding.recycler.adapter = MyAdapter(datas)
  • LinearLayoutManager 를 사용하여 기본으로 항목을 세로 방향으로 배치
    옵션을 주면 가로 방향으로도 배치 가능

RecyclerView 에 배치해주는 역할이 LayoutManager

LinearLayoutManager : 가로 혹은 세로 방향으로 항목 배치

GridLayoutManager : Grid 로 항목 배치

StaggeredGridLayoutManager : GridLayoutManager 의 서브, 높이가 불규칙한 Grid 로 항목 배치


➕ 2023.09.16 추가

💬 ViewPager

📝 ViewPager2

implementation("androidx.viewpager2:viewpager2:1.0.0")
<androidx.viewpager2.widget.ViewPager2.xmlns:android="http://schemas.android.com/apk/res/android"
	android:id="@+id/viewpager"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
  • ViewPager 는 스와이프 이벤트(손으로 화면을 미는 이벤트) 에 의한 화면 전환을 목적

  • androidx.viewpager 라이브러리와 별개로 2019년 androidx.viewpager2 가 새롭게 발표

  • androidx.viewpager2 구현할 것을 권장

준비한 여러개의 화면을 뷰페이저에 등록하여 사용하는 방식이다. 뷰페이저는 자신에게 등록된 하나의 화면을 하나의 항목으로 본다. 즉, 뷰페이저는 어댑터뷰이고 어댑터를 요구한다는 의미이다.

📓 Adapter

  • ViewPager2 에 사용할 수 있는 Adapger 는 두가지가 제공

    • RecyclerView.Adapter

    • FragmentStateAdapter

📂 RecyclerView.Adapter

class MyPagerViewHolder(val binding: ItemPagerBinding) :
	RecyclerView.ViewHolder(binding.root)

class MyPagerAdapter(val datas: MutableList<String>) :
	RecyclerView.ViewHolder<RecyclerView.ViewHolder>() {
    
	override fun getItemCount(): Int {
		return datas.size
	}

	override fun onCreateViewHolder(
		parent: ViewGroup,
		viewType: Int
	): RecyclerView.ViewHolder = MyPagerViewHolder(
		ItemPagerBinding.inflate(
			LayoutInflater.from(parent.context),
			parent,
			false
		)
	)

	override fun BindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
	}
}
  • RecyclerView.Adapter 는 RecyclerView 와 동일하게 사용한다.

  • 간단한 화면 구성이라면 리사이클러뷰 어댑터를 사용하여도 된다. 하지만 화면이 복잡해 질수록 프래그먼트를 채용할 것이고, 이 경우 그냥 프래그먼트를 위한 어댑터를 사용하는 것이 일반적이다.

📂 FragmentStateAdapter

class MyFragmentPagerAdapter(activity: FragmentActivity): FragmentStateAdapter(activity) {
	val fragments: List<Fragment>
    init {
    	fragments = listOf(OneFragment(), TwoFragment(), ThreeFragment())
        Log.d("kotdev", "fragments size : ${fragments.size}")
	}
    override fun getItemCount(): Int = fragments.size
    
    override fun createFragment(position: Int): Fragment = fragments[position]
}
  • 항목이 프래그먼트라면 FragmentStateAdapter 를 사용

  • FragmentStateAdapter 를 상속 받아 Adapter 를 작성

  • getItemCount() 함수와 createFragment() 함수를 오버라이드

  • createFragment() 함수에서 리턴시킨 Fragment 객체가 각 항목에 출력

⚙ 스와이프 방향

binding.viewpager.orientation = ViewPager2.ORIENTATION_VERTICAL
  • 화면 방향도 조정

  • 기본으로 가로 방향이 적용

  • 세로방향으로 나오게 하려면 orientation 속성값을 조정

🧩 실습 예제

🧷 dependency

  • build.gradle.kts
implementation("androidx.viewpager2:viewpager2:1.0.0")

🎨 프래그먼트 레이아웃

프래그먼트 3개를 구분할 수 있게끔 간단히 작성

🎨 액티비티 레이아웃

  • activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.viewpager2.widget.ViewPager2
	xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/viewpager"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" />

⚙ 뷰페이저 어댑터

  • MyAdapter.kt
package com.kotdev99.android.c93

class MyAdapter(activity: FragmentActivity) : FragmentStateAdapter(activity) {
	val fragments: List<Fragment>

	init {
		fragments = listOf(OneFragment(), TwoFragment(), ThreeFragment())
	}

	override fun getItemCount(): Int {
		return fragments.size
	}

	override fun createFragment(position: Int): Fragment {
		return fragments[position]
	}
}

📂 메인 코드

  • MainActivity.kt
package com.kotdev99.android.c93

class MainActivity : AppCompatActivity() {
	override fun onCreate(savedInstanceState: Bundle?) {
		super.onCreate(savedInstanceState)

		val binding = ActivityMainBinding.inflate(layoutInflater)
		setContentView(binding.root)

		binding.viewpager.adapter = MyAdapter(this)
	}
}

📲 결과


➕ 2023.09.17 추가

💬 Toolbar

❓ Toolbar 란?

  • 툴바는 액션바를 개발자 뷰로 이용하기 위한 뷰

  • 툴바와 액션바는 목적이 동일

  • 액션바는 액티비티 윈도우가 자동 출력시켜 주는 액티비티의 구성요소

  • 툴바는 개발자가 직접 핸들링하는 뷰

액션바를 XML 파일로 준비하여 핸들링할 수 있다 = 툴바

원래는 윈도우가 액션바/컨텐츠 영역으로 나뉘지만, 툴바를 사용하면 액션바를 뷰 객체로 컨텐츠 영역 안에 포함시킬 수 있다. 화면을 아래로 스크롤 시 상단 바가 같이 따라오는 효과 등을 낼 수 있다.

📓 XML 에 등록

<androidx.appcompat.widget.Toolbar
	android:id="@+id/toolbar"
    android:layout_width="match_parent"
    android:layout_height-"wrap_content"
    style="@style/Widget.MaterialComponents.Toolbar.Primary"/>
  • 액티비티 테마 설정을 통해 액션바가 화면에 출력되지 않게 설정

  • 레이아웃 XML 파일에 Toolbar 를 등록

📓 ActionBar 내용 적용

setSupportActionBar(binding.toolbar)
  • setSupportActionBar(binding.toolbar) 구문에 의해 액티비티의 액션바에 적용되는 내용이 툴바에 적용

🧩 실습 예제

⚙ Menu XML

res/menu 디렉토리 하위에 메뉴 XML 생성

  • menu_main.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id="@+id/menu1"
        android:title="menu1" />
    <item
        android:id="@+id/menu2"
        android:icon="@android:drawable/ic_menu_add"
        android:title="menu2"
        app:showAsAction="always" />
</menu>


🎨 액티비티 레이아웃

  • activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <androidx.appcompat.widget.Toolbar
        android:id="@+id/toolbar"
        style="@style/Widget.MaterialComponents.Toolbar.Primary"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="hello world" />
</LinearLayout>


📂 메인 코드

  • MainActivity.kt
package com.kotdev99.android.c94

class MainActivity : AppCompatActivity() {
	override fun onCreate(savedInstanceState: Bundle?) {
		super.onCreate(savedInstanceState)
		val binding = ActivityMainBinding.inflate(layoutInflater)
		setContentView(binding.root)

		// 액션바에 적용 되는 내용을 툴바에 적용
		setSupportActionBar(binding.toolbar)    
	}

	// menu_main 를 inflate 하여 적용
	override fun onCreateOptionsMenu(menu: Menu?): Boolean {
		menuInflater.inflate(R.menu.menu_main, menu)
		return super.onCreateOptionsMenu(menu)
	}
}

📲 결과


➕ 2023.09.18 추가

💬 DrawerLayout

❓ DrawerLayout 이란?

  • DrawerLayout 은 액티비티 화면에 안보이던 내용이 왼쪽 혹은 오른쪽에서 유저 스와이프 이벤트에 의해 끌리면서 나타나는 기능을 제공

❗ 화면 구성 권장사항

DrawerLayout 의 구성을 보면 거의 대부분 목록 형식을 띄고 있다. 물론 반드시 목록만을 구현하라는 법은 없다. 이미지도 올릴 수 있다. 개발자가 구현하기 나름이라는 말이다. 하지만 거의 대부분의 개발자가 목록으로 DrawerLayout 을 구현하고 있다. 왜냐하면 화면 구성에 대한 권장사항이 있기 때문이다.

유저가 컨텐츠를 보는 공간(화면) 에 유저 이벤트를 받는 뷰(버튼 등) 의 배치를 지양하라는 권장사항이다. 즉, 컨텐츠 공간에는 오직 유저가 보는 내용만이 배치되는 구조를 구성해야 한다. 컨텐츠를 출력하는 것만 해도, 화면이 작다는 뜻이다. 그래서 주요한 이벤트를 받는 뷰는 언제나 노출되게끔 구성한다. FAB으로 항상 화면에 노출되는 이벤트, 그 다음으로 Action 아이템, 그리고 남은 기타등등의 이벤트를 DrawerLayout 을 목록 형식으로 구현해서 처리하는 방식으로 많이 개발한다. 물론 반드시 지켜야 되는 것은 아니다, 권장사항이니까. 하지만 대부분이 권장사항을 지켜면서 앱을 구현하고 있다.


⚙ XML 선언

<androidx.drawerlayout.widget.DrawerLayout
	xmlns.android="http://schemas.android.com/apk/res/android"
    android:id="@+id/drawer"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    
    <!-- 항상 출력 영역 -->
    <LinearLayout ...........>
    	<!-- ........-->
	</LinearLayout>
    
    <!-- 숨겨진 영역 -->
    <TextView
    	android:layout_gravity="start"/>
</androidx.drawerlayout.widget.DrawerLayout>
  • 액티비티 레이아웃 XML 파일에서 Drawer 가 출력되어야 하는 부분의 태그를 DrawerLayout 으로 선언

  • DrawerLayout 하위에는 두 개의 뷰가 선언

  • 첫 번째 하위 태그 부분을 액티비티 화면에 출력

  • 두 번째 하위 태그 부분이 안 보이다가 끌려 나오며 출력

  • android:layout_gravity 속성값을 이용하여 화면에서 나오는 방향을 지정

  • left, right, start 를 지정

  • start 값을 주면 언어의 쓰는 방향에 따라 left, write 가 자동 결정

📓 토글 아이콘

  • 툴바 영역에 토글 버튼을 같이 제공 가능

보통 편의성을 위해 토글 아이콘 제공해 주는 편이다. 이건 코드에서 ActionBarDrawerToggle 라는 클래스를 이용해야 한다.

📝 ActionBarDrawerToggle

toggle = ActionBarDrawerToggle(
			this,
			binding.drawer,
			R.string.drawer_opened,
			R.string.drawer_closed
		)

supportActionBar?.setDisplayHomeAsUpEnabled(true)
toggle.syncState()		// 토글이 눌렸을 때와 손가락을 끌었을 때를 싱크
override fun onOptionItemSelected(item: MenuItem): Boolean {
	if (toggle.onOptionsItemSelected(item)) {	// 무조건 토글 동작
    	return true
    }
	return super.onOptionsItemSelected(item)
}
  • Drawer 토글 버튼은 ActionBarDrawerToggle 클래스에서 제공

액션바의 좌측에 들어가는 아이콘을 흔히 액션 아이템 이라고 부른다. 근데 동작은 메뉴 기법으로 처리한다. 즉, 액션 아이템을 터치하면 Menu event 가 발생하고, 이것이 onOptionsItemSelected() 함수로 들어간다. 그런데 토글이 눌러서 출력된 메뉴의 이벤트는 onOptionsItemSelected() 함수에서 처리되면 안되니까, 그냥 return 시켜 주어야 한다.

❓ 그럼 리턴을 안하면 어떻게 되나?

만약 메뉴에 아무런 이벤트를 준비하지 않았다면 토글을 눌러도 아무것도 실행되지 않는다.

📓 NavigationView

  • NavigationView 는 DrawerLayout 에 의해 끌리면서 출력되는 부분을 위한 뷰

  • 항목을 나열하는 화면을 구성

솔직히 DrawerLayout 의 구조는 다 비슷비슷하다. 위 이미지처럼 구현을 한다면 NavigationView 를 사용하는 것이 매우 편하다.

📝 사용 방법

headerLayout.xml 파일 하나 만들어서 NavigationView 에 등록하면 headerLayout 영역은 끝,
menu.xml 파일 하나 만들어서 NavigationView 에 등록하면 menu 영역도 끝이다.

진짜 엄청 편하다!

<com.google.android.material.navigation.NavigationView
	android:id="@+id/main_drawer_view"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    app:headerLayout="@layout/navigation_header"
    app:menu="@menu/menu_navigation" />    

🧩 실습 예제

🛠 NavigationView

📌 NavigationView 의 header 및 menu 영역

  • navigation_header.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="200dp"
    android:background="#FF0000"
    android:gravity="left|bottom"
    android:paddingLeft="32dp"
    android:paddingBottom="32dp"
    android:text="I am Header"
    android:textColor="#FFFFFF"
    android:textSize="15dp"
    android:textStyle="bold" />

  • menu_navigation.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:icon="@android:drawable/ic_menu_add"
        android:title="menu1" />
    <item
        android:icon="@android:drawable/ic_menu_search"
        android:title="menu2" />
</menu>


🎨 액티비티 레이아웃

❗ NavigationView 의 규칙 = root 태그가 NavigationView 일 것!

  • activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout
	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"
    android:id="@+id/drawer"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="Hello World!"
        android:textSize="20dp"
        android:textStyle="bold" />

    <com.google.android.material.navigation.NavigationView
        android:id="@+id/nav_view"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        app:headerLayout="@layout/navigation_header"
        app:menu="@menu/menu_navigation" />

</androidx.drawerlayout.widget.DrawerLayout>


⚙ 메인 코드

  • strings.xml
<resources>
    <string name="app_name">C96</string>
    <string name="open">open drawer</string>
    <string name="close">close drawer</string>
</resources>

📂 메인 코드

  • MainActivity.kt
package com.kotdev99.android.c96

class MainActivity : AppCompatActivity() {

	lateinit var toggle: ActionBarDrawerToggle

	override fun onCreate(savedInstanceState: Bundle?) {
		super.onCreate(savedInstanceState)
		val binding = ActivityMainBinding.inflate(layoutInflater)
		setContentView(binding.root)

		// 토글이 열린 상태, 닫힌 상태를 설명 하는 문자열을 리소스(Int 변수) 로 주게 되어있다.
		toggle = ActionBarDrawerToggle(this, binding.drawer, R.string.open, R.string.close)
		supportActionBar?.setDisplayHomeAsUpEnabled(true)
		toggle.syncState()
	}

	// Menu event 발생 시 자동 호출, but 여기서 이벤트 로직은 작성하지 않는다
	override fun onOptionsItemSelected(item: MenuItem): Boolean {
		if (toggle.onOptionsItemSelected(item)) {
			return true
		}
		return super.onOptionsItemSelected(item)
	}
}

📲 결과

만약 toggle 버튼이 출력되지 않는다면 테마 를 ActionBar 테마로 변경 해주자.

색상이 맘에 들지 않으면 <colorPrimary> 태그로 변경할 수 있다.

profile
응애 나 아기 뉴비

0개의 댓글