BottomNavigation을 이용한 Fragment 전환
BottomNavigation을 이용해서 아래와 같은 View를 구현할 수 있다.
그럼, 위와 같은 사항을 구현하기 위해 코드로
하나씩 구현해보자 ㅎ
BottomNavigation에서 나타낼 Item 요소들 저장 - menu XML 폴더
BottomNavigation의 Item을 지정하는 menu 폴더를 생성
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/menu_home"
android:title="홈"
android:icon="@drawable/home_icon">
</item>
<item
android:id="@+id/menu_setting"
android:title="메뉴"
android:icon="@drawable/menu"/>
</menu>
구현한 menu를 bottomNavigation의 Item 요소로 나타낸다.
이는, 아래의 activity_main.xml 파일의 bottomNavigation에서 나타낸다.
(xml 객체와 xml 객체의 연결된 셈이다.)
activity_main.xml 파일에 BottomNavigation 구현 - 요소 Layout
activity_main 파일에 추가로 FramLayout을 지정해 Fragment Container를 할당해줌.
Fragment Container란,
activity_main에서 Fragment를 띄울 영역을 의미한다.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<FrameLayout
android:id="@+id/container_fragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@id/nav_bottom"/>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/nav_bottom"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:menu="@menu/menu_bottomnav"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
# Fragment xml은 다음과 같이 구성했으며,
xml 코드 작성사항은 생략한다.
MainActvitiy에서 BottomNavigation 속성의 클릭이벤트에 따라 Fragment 전환
package com.example.umc_week6
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.example.umc_week6.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
// viewBinding 객체 선언 즉시, 값 생성
private val viewBinding: ActivityMainBinding by lazy{
ActivityMainBinding.inflate(layoutInflater)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(viewBinding.root)
// MainActivity에 처음 접근했을 때 띄어지는 화면을 설정해줌
supportFragmentManager
.beginTransaction()
.replace(viewBinding.containerFragment.id, HomeFragment())
.commitAllowingStateLoss()
// Bottom Navigation View 설정
/*
run 메소드는 "범위함수"라고 함
범위함수는 속성에 속한 요소들을 바로 사용할 수 있다.
*/
viewBinding.navBottom.run{
// navBottom 속성이 클릭되었을 때 아래와 같은 동작실행
setOnItemSelectedListener {
// when() 문은 Switch 문과 동등하게 사용됨
// menu의 itemId로 식별한다.
when (it.itemId) {
R.id.menu_home -> {
supportFragmentManager
.beginTransaction()
.replace(viewBinding.containerFragment.id, HomeFragment())
.commitAllowingStateLoss()
}
R.id.menu_setting -> {
supportFragmentManager
.beginTransaction()
.replace(viewBinding.containerFragment.id, SettingFragment())
.commitAllowingStateLoss()
}
}
true
}
// MainActivity에 접근 시 초기설정 Fragment를 빼당해줌.
selectedItemId = R.id.menu_home
}
}
}
# HomeFragment와 SettingFragment 구현된 사항들은
일반적인 Fragment 파일 구성과 동일하니, 생략하도록 하겠다.
구현완료
정리하며,
BottomNavigation은 위와 같은 형태의 뷰를 구성할 때 사용하는 VIew 전략이다.
이전에 구현했던 Fragment와 Button의 조합으로 구현해도 비슷한 양상을 가지지만,
BottomNavigation을 이용해서 더 깔끔하게 구현할 수 있을 뿐만 아니라, BottomNavigation를 통해 하단 뷰를
체계적으로 관리할 수 있다.
즉, 하단 버튼 뷰를 관리하는 개발 전략이 BottomNavigation을 이용한다고 생각해서 코드를 더 체계적으로 구성할 수 있다.
이 부분 개발은 이러한 구조로 개발을 한다라는 느낌을 받을 수 있다.
ViewPager2를 이용한 Fragment 전환
ViewPager2를 이용하면,
스크롤해서 Layout 요소들을 전환시킬 수 있다. 이는 Adapter를 통해서 구현이 되며,
RecyclerViewAdapter를 비롯한 다양한 Adapter로써 구현이 된다.
그럼, 이번에는 ViewPager2를 사용해 스크롤 시 Fragment가 전환되도록 구현해보자.
activity_main.xml 파일에서 ViewPager2 영역 지정해주기
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.google.android.material.tabs.TabLayout
android:id="@+id/tab_main"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/vp_main"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/tab_main"/>
</androidx.constraintlayout.widget.ConstraintLayout>
MainVPAdapter를 구성해 ViewPager2 객체와 Fragment 클래스를 연결해줌.
package com.example.umc_week6_2
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.viewpager2.adapter.FragmentStateAdapter
// ViewPager 기능을 사용할 요소들을 Adapter 클래스 생성자로 지정 - Fragment를 ViewPager로 전환
class MainVPAdapter(fragmentActivity: FragmentActivity): FragmentStateAdapter(fragmentActivity) {
// ViewPager로 표시할 아이템 갯수
override fun getItemCount(): Int {
return 2;
}
// 포지션에 따라서 어떤 Fragment를 보여줄 건지 설정
/*
createFragment() 메소드에서 position 값을 받아올 때는
MainActivity의 화면을 토대로 position 값이 받아진다.
*/
override fun createFragment(position: Int): Fragment {
// when() 문으로 postion 값에 따라서 보여지는 Fragment를 설정함.
return when (position) {
0 -> OneFragment()
1 -> TwoFragment()
else -> OneFragment()
}
}
}
MainActivity 파일에 Adapter를 연결해 ViewPager2에 따른 Fragment 전환
package com.example.umc_week6_2
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.example.umc_week6_2.databinding.ActivityMainBinding
import com.google.android.material.tabs.TabLayoutMediator
class MainActivity : AppCompatActivity() {
private val viewBinding: ActivityMainBinding by lazy {
ActivityMainBinding.inflate(layoutInflater)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(viewBinding.root)
// AppCompatActivitiy()는 Fragment를 상속받기에, MainActivity 클래스는 Fragment 클래스를 내장하고 있다.
val mainVPAdapter = MainVPAdapter(this)
viewBinding.vpMain.adapter = mainVPAdapter
}
}
구현 완료
그러면, 스크롤 시 Fragment를 전환할 수 있는 상태가 된다.
해당 부분에 대해선 영상이 없기에 글로 대체한다
위와 같이 구성하면 구현이 완료될 것이다.
Fragment 클래스는 일반적인 Fragment 클래스 파일과 동일하니, 생략하도록 하겠다.
ViewPager2 & TabLayout을 이용한 Fragment 전환
스크롤을 토대로 Fragment를 전환하는 것에 추가하여
Tab을 클릭 시 Fragment를 전환되도록 구현하려고 한다.
그러기 위해선, 위에서 작성한 코드를 토대로 추가하여 구현을 완료할 수 있다.
activity_main.xml 파일에서 ViewPager2 영역과 TabLayout 영역을 지정해주기.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.google.android.material.tabs.TabLayout
android:id="@+id/tab_main"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/vp_main"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/tab_main"/>
</androidx.constraintlayout.widget.ConstraintLayout>
MainVPAdapter에서 ViewPager2와 Fragment 클래스 연결해줌. - 위와 구현된 사항은 동일
package com.example.umc_week6_2
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.viewpager2.adapter.FragmentStateAdapter
// ViewPager 기능을 사용할 요소들을 Adapter 클래스 생성자로 지정 - Fragment를 ViewPager로 전환
class MainVPAdapter(fragmentActivity: FragmentActivity): FragmentStateAdapter(fragmentActivity) {
// ViewPager로 표시할 아이템 갯수
override fun getItemCount(): Int {
return 2;
}
// 포지션에 따라서 어떤 Fragment를 보여줄 건지 설정
/*
createFragment() 메소드에서 position 값을 받아올 때는
MainActivity의 화면을 토대로 position 값이 받아진다.
*/
override fun createFragment(position: Int): Fragment {
// when() 문으로 postion 값에 따라서 보여지는 Fragment를 설정함.
return when (position) {
0 -> OneFragment()
1 -> TwoFragment()
else -> OneFragment()
}
}
}
MainActivity에서 TabLayout을 연결해서 Activity에서 현재 보여지고 있는 Page의 위치를 받아와서
Tab을 변경한다.
package com.example.umc_week6_2
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.example.umc_week6_2.databinding.ActivityMainBinding
import com.google.android.material.tabs.TabLayoutMediator
class MainActivity : AppCompatActivity() {
private val viewBinding: ActivityMainBinding by lazy {
ActivityMainBinding.inflate(layoutInflater)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(viewBinding.root)
// AppCompatActivitiy()는 Fragment를 상속받기에, MainActivity 클래스는 Fragment 클래스를 내장하고 있다.
val mainVPAdapter = MainVPAdapter(this)
viewBinding.vpMain.adapter = mainVPAdapter
// Tab의 Title을 배열로 지정해둠.
val tabTitleArray = arrayOf(
"One",
"Two",
)
// TabLayout 객체를 연결하기 쉽게 TabLayoutMediator 클래스가 구현됨.
// 이를 이용해서 TabLayout 객체를 연동함.
/*
ViewPager에 따라서 TabLayout도 함께 움직이도록 구현가능해짐.
*/
// tab, position 값은 현재 MainActivity에서 보여지고 있는 위치를 의미한다. - VPAdapter 에서 Postion에 따라서 보여지는 Fragment를 설정해줬다.
TabLayoutMediator(viewBinding.tabMain, viewBinding.vpMain) {tab, position ->
tab.text = tabTitleArray[position]
}.attach()
}
}
구현완료
그렇게되면, 위에서 구현한 바에서 추가해 Tab을 클릭 시 Fragment가 전환되도록 구현을 완료할 수 있다.
정리해서, Fragment를 전환 시
스크롤해서 전환이 가능하고,
Tab을 클릭해서 전환이 가능해졌다.
마무리,,
이번 6주차는 Fragment를 활용해서 기능을 추가했기에, 생각보다 쉬웠고,
5주차에서 다뤘던 RecyclerView의 여파가 컷던 탓에 Adapter에 대해선 어느정도 감이 잡힌 것 같다 ㅎㅎㅋㅋ
Adapter는 View 객체와 Class 객체를 연결해주는 연결자 Class 파일
5주차하면서 Adapter 개념이 복잡하고 추상적이어서 많이 힘들었지만,
차근차근 하나씩 이해하다보니, 극복해낼 수 있었다.
그러니깐, 어려울 때는 잠시 돌아보면서 처음부터 하나씩 학습해나가는 자세를 지니자를 깨닫게 해주는 뜻깊은 경험이었다.
요즘들어, 안드로이드 개발이 심화를 향해 달려나가고 있다.
그만큼 더 열심히 공부를 할 예정이고, 학기 중 진행하는 안드 개발 프로젝트를 처음부터 완벽하게 하지 않고,
진행하면서 맞추어 가는 식으로 하겠다고 다짐했듯이 뭐든지 해보면서 감을 익혀가는 식으로 해볼 것이다.
안드 개발은 물론이고, 백엔드 NestJS 개발도 마찬가지다.
우선 개발에 대한 두려움을 없애야, 내가 생각한 것보다 훨씬 많은 것들을 개발해낼 수 있다.
그럼, 지금보다 더 책임감있는 사람이 되는 "그날까지" 난 달린다.
'📚 스터디 > 프론트엔드' 카테고리의 다른 글
[안드로이드] 7주차: Thread 실습 [타이머 제작] (0) | 2022.11.15 |
---|---|
[안드로이드] 7주차: Thread & 동기, 비동기 작업 (0) | 2022.11.12 |
[안드로이드] 5주차 실습: RecyclerView 사용 (5) | 2022.11.05 |
[안드로이드] 6주차: 고급 Layout과 View (0) | 2022.11.05 |
[안드로이드] 4주차: LifeCycle 실습 (0) | 2022.11.01 |