안드로이드 3주차 정리
Fragment
학습목표
- Activity 내에서 Fragment를 만들 수 있다.
- navigation 라이브러리와 navigation editor를 사용하여 fragment에 대한 navigation graph를 만들 수 있다.
- 앱에서 navigation path를 만들 수 있다.
- options menu를 사용하여 navigation을 추가할 수 있다.
- 사용자가 앱의 어디에서나 타이틀 화면으로 돌아갈 수 있도록 Up button을 구현할 수 있다.
- navigation drawer menu를 추가할 수 있다.
Fragment
Fragment는 Activity에서 동작 또는 UI(사용자 인터페이스)의 일부를 나타냅니다. Fragment는 앱 UI의 재사용 가능한 부분입니다.
Fragment는 자체 레이아웃을 정의 및 관리하고 자체 수명 주기를 가지며 자체 입력 이벤트를 처리할 수 있습니다. Fragment는 단독으로 존재할 수 없으며 Activity 또는 다른 Fragment에서 호스팅해야 합니다. Fragment의 뷰 계층은 호스트의 뷰 계층의 일부가 되거나 연결됩니다.
Fragment는 다른 Activity에서 사용할 수 있는 하위 Activity의 개념과 같은 모듈화 된 부분이라고 생각하세요.
- Fragment에는 자체 수명 주기가 있으며 자체 입력 이벤트를 수신합니다.
- Activity가 실행되는 동안 프래그먼트를 추가하거나 제거할 수 있습니다.
- Fragment는 코틀린 클래스로 정의됩니다.
- Fragment의 UI는 XML 레이아웃 파일로 정의됩니다.
Navigation
Navigation은 사용자가 앱 내의 다양한 콘텐츠를 탐색하고, 들어가고, 뒤로 이동할 수 있도록 하는 상호 작용을 나타냅니다.
Android Jetpack의 Navigation component는 단순한 버튼 클릭부터 앱 바와 Navigation drawer과 같은 더 복잡한 패턴에 이르기까지 Navigation을 구현하는 데 도움이 됩니다.
Navigation component의 주요 3요소.
- Navigation graph : xml 파일로 네비게이션과 관련된 정보를 담고 있다. 레이아웃 에디터와 비슷하게 캔버스 안에 화면들을 배치하고, 선으로 연결하여 경로를 설정 할 수 있다.
- NavHost : Navigation graph의 목적지를 나타내는 빈 컨테이너.
- NavController : NavHost 내에서 앱 탐색을 관리하는 개체이다. NavController는 사용자가 앱 전체에서 이동할 때 NavHost에서 대상 콘텐츠의 스와핑을 조정한다.
Navigation component의 장점.
- fragment transactions 관리가 편함.
- Up and Back actions을 정확하게 잘 처리함.
- 애니메이션 및 전환을 위한 표준화된 리소스를 제공합니다.
- 딥링킹 구현 및 처리.
- Safe Args
- ViewModel 지원 - ViewModel의 범위를 탐색 그래프로 지정하여 그래프의 대상 간에 UI 관련 데이터를 공유할 수 있습니다.
프로젝트에 Navigation component 추가.
- 의존성 추가
- build.gradle(project)에 아래의 코드를 추가한다.
ext {
...
navigationVersion = "2.3.0"
...
}
- build.gradle(app)에 아래의 코드를 추가한다.
dependencies {
...
implementation "androidx.navigation:navigation-fragment-ktx:$navigationVersion"
implementation "androidx.navigation:navigation-ui-ktx:$navigationVersion"
...
}
- 상단의 Sync Now를 클릭한다.
- Navigation Graph 추가
- res 디렉토리를 우클릭하여 New > Android Resource File을 클릭한다.
- New Resource File창에서 Resource type을 Navigation으로 선택한다.
- File name 필드에서 이름을 설정한다.
- res/navigation/filename.xml이 잘 생성됐는지 확인한다.
NavHostFragment 생성.
navigation host fragment은 navigation graph에서 fragment의 호스트 역할을 합니다. navigation host fragment의 이름은 일반적으로 NavHostFragment입니다.
- res > layout > activity_main.xml의 코드탭을 엽니다.
- 존재하는 fragment의 이름을 androidx.navigation.fragment.NavHostFragment로 바꿉니다.
- fragment의 아이디를 myNavHostFragment로 바꿉니다.
- navigation host fragment는 사용할 navigation graph 리소스를 알아야 합니다. app:navGraph 속성을 추가합니다.
- app:defaultNavHost 속성을 추가하고 "true"로 설정합니다. 이제 이 navigation host가 기본 host이며 시스템 back 버튼을 가로챕니다.
navigation graph에 fragment 추가.
- res/navigation/navigation.xml을 연다. navigation editor에서 New Destination 버튼을 누른다. fragment와 activity의 목록이 나온다.
- fragment_title을 선택합니다. TitleFragment는 앱 사용자가 앱을 처음 열 때 시작하는 위치이기 때문에 먼저 fragment_title을 추가합니다.
- New Destination 버튼을 사용하여 GameFragment를 추가합니다.
미리보기에 "Preview Unavailable" 메시지가 표시되면 코드 탭을 클릭하여 탐색 XML을 엽니다. 아래와 같이 gameFragment의 프래그먼트 요소에 tools:layout="@layout/fragment_game"이 포함되어 있는지 확인합니다.
<fragment
android:id="@+id/gameFragment"
android:name="com.example.android.navigation.GameFragment"
android:label="GameFragment"
tools:layout="@layout/fragment_game" />
- 미리 보기에서 title fragment 위에 포인터를 놓습니다. Fragment 보기의 오른쪽에 원형 연결점이 나타납니다. 연결 지점을 클릭하고 gameFragment로 드래그하거나 gameFragment 미리보기의 아무 곳이나 드래그합니다. 두 조각을 연결하는 action이 생성됩니다.
play버튼에 clickhandler 추가.
- TitleFragment.kt 파일을 엽니다. onCreateView() 메서드 내에서 return 문 앞에 다음 코드를 추가합니다.
binding.playButton.setOnClickListener { view : View ->
view.findNavController().navigate(R.id.action_titleFragment_to_gameFragment)
}
- 앱을 빌드하고 필요한 모든 import가 있는지 확인합니다. 예를 들어 TitleFragment.kt 파일에 다음 줄을 추가해야 할 수 있습니다.
import androidx.navigation.findNavController
Invoke-customs are only supported starting with Android O (--min-api 26) 발생 시 해결 방법
android { compileOptions { sourceCompatibility 1.8 targetCompatibility 1.8 } }
build.grade(Module)에 위의 코드를 붙여넣어준다.
conditional navigation 추가.
- GameWonFragment와 GameOverFragment를 navigation graph에 추가한다.
- GameFragment를 GameWonFragment와 GameOverFragment에 연결한다.
- Fragment에서 다른 Fragment로 이동하는 코드를 추가한다.
- GameFragment.kt 파일을 엽니다.
- 게임에서 승리하기 위한 else 조건 안에 gameWonFragment로 이동하는 다음 코드를 추가합니다. 작업 이름(이 예에서는 action_gameFragment_to_gameWonFragment)이 navigation.xml 파일에 설정된 것과 정확히 일치하는지 확인하십시오.
// We've won! Navigate to the gameWonFragment.
view.findNavController()
.navigate(R.id.action_gameFragment_to_gameWonFragment)
- 게임의 패배에 대한 else 조건 내에서 gameOverFragment로 이동하는 다음 코드를 추가합니다.
// Game over! A wrong answer sends us to the gameOverFragment.
view.findNavController().
navigate(R.id.action_gameFragment_to_gameOverFragment)
back 버튼의 목적지 변경
Android 시스템은 사용자가 Android 기반 장치에서 탐색하는 위치를 추적합니다. 사용자가 기기의 새 목적지로 이동할 때마다 Android는 해당 목적지를 백 스택에 추가합니다.
navigation action은 백 스택을 수정할 수 있습니다. 이 작업에서는 GameFragment에서 탐색하는 작업을 변경하여 작업이 백 스택에서 GameFragment를 제거하도록 합니다. 사용자가 게임에서 이기거나 졌을 때 뒤로 버튼을 누르면 앱이 GameFragment를 건너뛰고 TitleFragment로 돌아갑니다.
- 작업의 popUpTo 속성은 탐색하기 전에 백 스택을 지정된 대상으로 "pop up"합니다. (목적지는 백 스택에서 제거됩니다.)
- popUpToInclusive 속성이 false이거나 설정되지 않은 경우 popUpTo는 지정된 대상까지 대상을 제거하지만 지정된 대상은 백 스택에 남깁니다.
- popUpToInclusive가 true로 설정되면 popUpTo 속성은 백 스택에서 지정된 대상까지 포함하여 모든 대상을 제거합니다.
- popUpToInclusive가 true이고 popUpTo가 앱의 시작 위치로 설정된 경우 작업은 백 스택에서 모든 앱 대상을 제거합니다. 뒤로 버튼은 사용자를 앱에서 완전히 나오게 합니다.
- res > navigation 폴더에서 navigation.xml을 엽니다. 탐색 그래프가 레이아웃 편집기에 나타나지 않으면 디자인 탭을 클릭합니다.
- gameFragment에서 gameOverFragment로 이동하기 위한 action을 선택합니다.
- 속성 창에서 popUpTo를 gameFragment로 설정합니다. popUpToInclusive를 체크합니다.
- gameWonFragment에 대해서도 똑같이 작업합니다.
더 많은 navigation action 추가 및 onClickHandler 추가
이 단계에서는 사용자 흐름의 두 단계를 더 구현합니다.
- 사용자가 next match 또는 try again 버튼을 탭하면 앱이 GameFragment 화면으로 이동합니다.
- 이 시점에서 사용자가 시스템 뒤로 버튼을 누르면 앱은 GameWon 또는 GameOver 화면으로 돌아가는 대신 TitleFragment 화면으로 이동합니다.
- Navigation.xml 파일 내에서 gameOverFragment를 gameFragment에 연결하는 navigation action을 추가합니다. action ID의 fragment name이 XML에 있는 fragment name과 일치하는지 확인하십시오. 예를 들어 action ID는 action_gameOverFragment_to_gameFragment일 수 있습니다.
- 속성 창에서 작업의 popUpTo 속성을 titleFragment로 설정합니다.
- gameWonFragment에 대해서도 똑같이 작업합니다.
이제 try again 및 next match 버튼에 기능을 추가하십시오. 사용자가 두 버튼 중 하나를 탭하면 앱이 GameFragment 화면으로 이동하여 사용자가 게임을 다시 시도할 수 있게 만들겁니다.
- GameOverFragment.kt 파일을 엽니다. onCreateView() 메서드 끝에서 return 문 앞에 다음 코드를 추가합니다. 코드는 try again 버튼에 clickListener를 추가합니다. 사용자가 버튼을 탭하면 앱이 GameFragment로 이동합니다.
// Add OnClick Handler for Try Again button
binding.tryAgainButton.setOnClickListener{view: View->
view.findNavController()
.navigate(R.id.action_gameOverFragment_to_gameFragment)}
- GameWonFragment.kt 파일을 엽니다. onCreateView() 메서드의 끝에서 return 문 앞에 다음 코드를 추가합니다.
// Add OnClick Handler for Next Match button
binding.nextMatchButton.setOnClickListener{view: View->
view.findNavController()
.navigate(R.id.action_gameWonFragment_to_gameFragment)}
app bar
앱 바(= 액션 바)는 앱 브랜딩과 아이덴티티를 위한 전용 공간입니다. 예를 들어 앱 바의 색상을 설정할 수 있습니다. 앱 바를 통해 사용자는 옵션 메뉴와 같은 친숙한 navigation 기능에 액세스할 수 있습니다.
The Up button
현재 앱에서 사용자는 시스템 뒤로 버튼을 사용하여 이전 화면으로 이동합니다. 그러나 Android 앱에는 앱 바의 왼쪽 상단에 표시되는 화면 위 버튼이 있을 수도 있습니다.
앱에서 타이틀 화면을 제외한 모든 화면에 Up 버튼이 나타나게 만들겁니다. 타이틀 화면이 앱의 화면 계층 구조의 맨 위에 있기 때문에 사용자가 타이틀 화면에 도달하면 Up 버튼이 사라집니다.
Up button과 Back button의 차이
- Up 버튼은 화면 간의 계층적 관계를 기반으로 앱 내에서 탐색합니다. Up 버튼은 사용자를 앱 외부로 안내하지 않습니다.
- Back 버튼은 사용자가 최근에 작업한 화면(백 스택)을 뒤로 탐색합니다.
Up 버튼 추가.
navigation component에는 NavigationUI라는 UI 라이브러리가 포함되어 있습니다. Navigation 구성 요소에는 NavigationUI 클래스가 포함되어 있습니다. 이 클래스에는 app bar, navigation drawer 및 bottom navigation을 사용하여 navigation을 관리하는 정적 메서드가 포함되어 있습니다. navigation controller는 app bar와 통합되어 Up 버튼의 동작을 구현하므로 직접 수행할 필요가 없습니다.
- MainActivity.kt 파일을 엽니다. onCreate() 메서드 내에서 navigation controller 개체를 찾는 코드를 추가합니다.
val navController = this.findNavController(R.id.myNavHostFragment)
- 또한 onCreate() 메서드 내부에 navigation controller를 app bar에 연결하는 코드를 추가합니다.
NavigationUI.setupActionBarWithNavController(this,navController)
- onCreate() 메서드 다음에 onSupportNavigateUp() 메서드를 override하여 navigation controller에서 NavigateUp()을 호출합니다.
override fun onSupportNavigateUp(): Boolean {
val navController = this.findNavController(R.id.myNavHostFragment)
return navController.navigateUp()
}
options menus 추가.
이 작업에서는 options menu 항목을 옵션 메뉴에 추가합니다. 사용자가 about menu 항목을 탭하면 앱이 AboutFragment로 이동하고 사용자에게 앱 사용 방법에 대한 정보가 표시됩니다.
- navigation graph에 AboutFragment 추가
- options menu 리소스 추가
- Android Studio 프로젝트 창에서 res 폴더를 마우스 오른쪽 버튼으로 클릭하고 new > Android resource file을 선택합니다.
- New Resource File 대화 상자에서 File name을 options_menu로 지정합니다.
- Resource Type으로 메뉴를 선택하고 확인을 클릭합니다.
- res > menu 폴더에서 options_menu.xml 파일을 열고 Design 탭을 클릭하면 Layout Editor를 볼 수 있습니다.
- 팔레트 창에서 메뉴 항목(아래 스크린샷에서 1로 표시)을 끌어 디자인 편집기 창(2)의 아무 곳에나 놓습니다. 메뉴 항목은 미리 보기(3)와 구성 요소 트리(4)에 나타납니다.
- 미리 보기 또는 component tree에서 메뉴 항목을 클릭하여 속성 창에 속성을 표시합니다.
- 메뉴 항목의 ID를 aboutFragment로 설정합니다. 제목을 @string/about으로 설정합니다.
- onClickHandler 추가.
- TitleFragment.kt 파일을 엽니다. onCreateView() 메서드 내에서 return 전에 setHasOptionsMenu() 메서드를 호출하고 true를 전달합니다.
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { ... setHasOptionsMenu(true) return binding.root }
- onCreateView() 메서드 다음에 onCreateOptionsMenu() 메서드를 재정의합니다. 메서드에서 옵션 메뉴를 추가하고 메뉴 리소스 파일을 inflate합니다.
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { super.onCreateOptionsMenu(menu, inflater) inflater.inflate(R.menu.options_menu, menu) }
- 메뉴 항목을 탭할 때 적절한 조치를 취하도록 onOptionsItemSelected() 메서드를 override합니다. 이 경우 action은 선택한 메뉴 항목과 동일한 id를 가진 Fragment로 이동하는 것입니다.
override fun onOptionsItemSelected(item: MenuItem): Boolean { return NavigationUI. onNavDestinationSelected(item,requireView().findNavController()) || super.onOptionsItemSelected(item) }
navigation drawer 추가
navigation drawer는 화면 가장자리에서 바깥쪽으로 미끄러지는 패널입니다. drawer는 일반적으로 헤더와 메뉴를 포함합니다.
휴대폰 크기의 기기에서는 사용하지 않을 때 navigation drawer를 숨깁니다. 두 가지 유형의 사용자 작업으로 navigation drawer를 표시할 수 있습니다.
- navigation drawer는 사용자가 화면의 모서리 끝에서 반대로 스와이프하면 나타납니다. AndroidTrivia 앱에서 탐색 창은 사용자가 왼쪽에서 오른쪽으로 스와이프하면 나타납니다.
- navigation drawer는 사용자가 앱의 시작 위치에 있을 때 나타나고 앱 바에서 서랍 아이콘을 탭하면 나타납니다.
-
프로젝트에 material 라이브러리 추가
- 앱 수준 Gradle 빌드 파일에서 Material 라이브러리에 대한 종속성을 추가합니다.
dependencies { ... implementation "com.google.android.material:material:$version" ... }
- Sync 버튼을 클릭합니다.
-
destination fragment에 ID가 있는지 확인하십시오.
- fragment_rules.xml 레이아웃 파일을 열어 어떻게 생겼는지 확인하세요. 디자인 탭을 클릭하여 디자인 편집기에서 미리보기를 봅니다.
- navigation.xml 파일을 여십시오. new destination 버튼을 클릭하고 rules fragment을 추가합니다. ID를 rulesFragment로 설정합니다.
-
drawer menu 및 drawer layout 만들기
- drawer에 대한 메뉴를 만듭니다. 프로젝트 창에서 res 폴더를 마우스 오른쪽 버튼으로 클릭하고 new resource file을 선택합니다. file name을 navdrawer_menu로 지정하고 resource type을 menu로 설정한 다음 확인을 클릭합니다.
- res > menu 폴더에서 navdrawer_menu.xml을 열고 디자인 탭을 클릭합니다. 팔레트 분할창에서 component tree 분할창으로 두 개의 메뉴 항목을 끌어서 추가하십시오.
- 첫 번째 메뉴 항목의 경우 id를 rulesFragment로 설정합니다. (메뉴 항목의 ID는 Fragment의 ID와 같아야 합니다.) 제목을 @string/rules로, 아이콘을 @drawable/rules로 설정합니다.
- 두 번째 메뉴 항목의 경우 id를 aboutFragment로, 제목 문자열을 @string/about으로, 아이콘을 @drawable/about_android_trivia로 설정합니다.
- activity_main.xml 레이아웃 파일을 엽니다. 모든 서랍 기능을 얻으려면 DrawerLayout 안에 뷰를 넣으십시오. 전체 을 안에 래핑합니다. (즉, DrawerLayout을 루트 뷰로 추가합니다.)
<layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <androidx.drawerlayout.widget.DrawerLayout android:id="@+id/drawerLayout" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout . . . </LinearLayout> </androidx.drawerlayout.widget.DrawerLayout> </layout>
- 이제 방금 정의한 navdrawer_menu를 사용하는 NavigationView인 drawer을 추가합니다. DrawerLayout에서 요소 뒤에 다음 코드를 추가합니다.
<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" />
- drawer에 대한 메뉴를 만듭니다. 프로젝트 창에서 res 폴더를 마우스 오른쪽 버튼으로 클릭하고 new resource file을 선택합니다. file name을 navdrawer_menu로 지정하고 resource type을 menu로 설정한 다음 확인을 클릭합니다.
-
navigation drawer 표시
- MainActivity.kt 파일을 엽니다. onCreate()에서 사용자가 navigation drawer을 표시할 수 있도록 하는 코드를 추가합니다. setupWithNavController()를 호출하여 이 작업을 수행합니다. onCreate() 맨 아래에 다음 코드를 추가합니다.
NavigationUI.setupWithNavController(binding.navView, navController)
-
drawer button에서 navigation drawer 표시
- MainActivity.kt 파일에서 drawer layout을 나타내는 lateinit drawer layout 멤버 변수를 추가합니다.
private lateinit var drawerLayout: DrawerLayout
- onCreate() 메서드 내에서 바인딩 변수가 초기화된 후 drawer layout을 초기화합니다.
val binding = DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main) drawerLayout = binding.drawerLayout
- setupActionBarWithNavController() 메서드에 세 번째 매개변수로 drawer layout을 추가합니다.
NavigationUI.setupActionBarWithNavController(this, navController, drawerLayout)
- navController.navigateUp을 반환하는 대신 NavigationUI.navigateUp을 반환하도록 onSupportNavigateUp() 메서드를 편집합니다. navigation controller와 drawer layout을 navigationUp()에 전달합니다.
override fun onSupportNavigateUp(): Boolean { val navController = this.findNavController(R.id.myNavHostFragment) return NavigationUI.navigateUp(navController, drawerLayout) }
Author And Source
이 문제에 관하여(안드로이드 3주차 정리), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@tjdwns5063/안드로이드-3주차-정리저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)