# 결과물 미리보기
지금 까지는 액티비티만을 사용하여 화면을 구성했지만, 프래그먼트를 이용하여 자연스럽게 화면을 구성하고 있다. 하단메뉴바를 사용하면서 프래그먼트를 이용하여 메뉴를 클릭시 화면이 바뀌는 것을 구현해보자.
나도 프래그먼트의 존재는 알았지만 처음 써보기 이 단락자체를 하나의 포스팅으로 기록해 두도록 하겠다.
# 구현 방법
- 메인액티비티에서 하단바메뉴바를 위한 곳과, 화면을 띄울 곳을 분리시킨다 ( navibar, framelayout )
- 메뉴바를 클릭하면 해당 framelayout에 연결된 프래그먼트를 띄운다.
크게는 이렇게 두개의 동작으로 나누면 된다.
네비바를 처음부터 만들 필요 없이, material에서 제공해주는 BottomNavigationView를 사용하면 된다. 여기에 itemIconTint를통해 클릭시 색깔을 바뀌는것을 정해주며, menu옵션을 통해서 아이콘들을 만들어 줄 수 있다.
프래그먼트를 바꿔줄시에는 supportFragmentManager.beginTransaction을 통해서 바꿔줘야 한다. 순서대로 하나씩 정리해보도록 하겠다. 중요한 기초개념이기 때문에 조금 꼼꼼히 기록해야할 것 같다.
# XML 레이아웃 구성하기
1번 영역과 2번영역 두개로 mainxml을 분리해준다. 위에서 말했듯이 1번영역은 FrameLayout으로 우리가 보게될 곳이며, 2번영역은 네비게이션바를 사용한다.
<?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/fragmentCotainer"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@id/bottomNavigationView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/bottomNavigationView"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:itemIconTint="@color/selector_menu_color"
app:itemRippleColor="@null"
app:itemTextColor="@color/black"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:menu="@menu/bottom_navigation_menu" />
</androidx.constraintlayout.widget.ConstraintLayout>
## 네비게이션 바 구성하기
최초의 네비게이션 바에는 아무것도 없다.
- 들어갈(자리) 아이콘 및 텍스트
- 눌렀을때(동작마다) 색깔
을 따로 정의해줘야한다.
### 아이콘 및 텍스트 추가하기
app:menu="@menu/bottom_navigation_menu"
해당 옵션을 통해서 만들어줘야 한다. 첫번째로, res폴더에 menu라는 새로운 리소스 폴더를 만들어주고, 새로운 xml을 하나 만들어준다.
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/home"
android:icon="@drawable/ic_baseline_home_24"
android:title="@string/menu_title_home"/>
<item android:id="@+id/chatList"
android:icon="@drawable/ic_baseline_chat_24"
android:title="@string/menu_title_chating"/>
<item android:id="@+id/myPage"
android:icon="@drawable/ic_baseline_person_pin_24"
android:title="@string/menu_title_myInfo"/>
</menu>
그리고 다음과 같이 들어갈 title을 추가해주고, icon은 벡터로 내가 원하는 이미지를 만들어 달아주도록 하자 그러면
위와 같이 xml이 구성된다. BottomNavigationView으로 들어가게 되면 우리가 원하던 것처럼 정렬되어 들어간다.
### 동작마다 다른 색깔 정의해주기
색을 따로 설정하지 않으면 안드로이드에서 제공해주는 기본 색인 보라색이다. 조금 칙칙하기 색을 바꿔 줄 수 있다. 난 당근마켓 느낌을 내기위해 주황색(#e78111)을 사용했다.
app:itemIconTint="@color/selector_menu_color"
여러 동작이 있기때문에 개별적으로 옵션을 주는 것은 불가능하기 때문에 selector이라는 res파일을 만들어야한다. 여기서 또 새로운 폴더구조를 만들어 줘야 인식하기 때문에, res/color라는 res폴더를 만들어주고 그 안에 selector xml을 만들어 주도록 하자.
state에 대한 옵션은 꽤 많았다. 구글문서에 가면 볼 수 있으니까, 더 많은 동작에대해서 상태를 정의하고 싶으면 참고하면 될것 같다.
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/carrot_color" android:state_checked="true"/>
<item android:color="@color/gray_cc" android:state_checked="false"/>
</selector>
위 두가지 item은 선택된 것일때, 선택되지 않았을때 이며, 즉 현재 보고있는 것이 주황색 안보고있는 나머지들은 회색의 색을 주는 것이다.
### 더 꾸며주기 ( 테마색 바꾸기 )
터치시 생기는 물결반응을 없애주기 위해서는 아래의 옵션을 주면 되고
app:itemRippleColor="@null"
글씨색을 진한 검정색으로 바꾸고 싶다면 아래 옵션을 주도록 하자.
app:itemTextColor="@color/black"
또 테마옵션을 변경해주지 않으면 메뉴바의 색이 디폴트 보라색으로 나올 수 있기 때문에 테마의 색을 따로 변경해주도록 하자
res/themes/themes.xml 에서
<style name="Theme.CarrotMarket" parent="Theme.MaterialComponents.Light.NoActionBar">
// ...
// ...
</style>
Light의 NoActionBar로 바꿔주면 된다. 이제 메뉴바는 성공적으로 만들어 졌기 때문에, 각각의 메뉴바를 눌렀을때 화면을 연결시켜주기 위해서 프래그먼트를 구성해보자.
# 프래그먼트 구성하기
먼저 프래그먼트는 독자적인 생명주기를 가지며, 액티비티 안에서 사용되어야 한다는데, 아직은 프래그먼트를 처음 사용해보기 때문에 정확히 어떠한 쓰임인지는 잘 모르겠다. 쓰다보면 알게 될 것 이라 믿는다.. ㅎㅎ
생성할 프래그먼트별로 패키지를 만들어 관리를 해야지 깔끔하다고 하기 때문에 패키지별로 3개의 프래그먼트를 구성한다.
각각의 프래그먼트는 아직 내용이 없기 때문에
class HomeFragment : Fragment(R.layout.home_fragment) {
}
위와 같이 AppCompatActivity가 아닌 Fragment를 상속받고, 그 안에 layout을 연결시켜준다. 아직은 아무 내용이 없기때문에 각각의 레이아웃배경색을 다른 것으로 주어 구별하면 좋다.
이제 MainActivity로 돌아와, 각각의 프래그먼트객체를 만들어주도록 한다.
val homeFragment = HomeFragment()
val chatlistFragment = ChatlistFragment()
val myPageFragment = MyPageFragment()
이제 메뉴바가 눌렸을때, 해당 프래그먼트를 연결시켜줘야한다. 여기서 메뉴바가 눌릴때 그냥 setOnClickListener를 달아주게 된다면, 메뉴바의 각각의 요소의 접근하는 것이 아닌 메뉴바자체가 눌렸을때 반응하기 때문에 다른 리스너를 사용하도록 한다.
// 없어짐 사용X
setOnNavigationItemSelectedListener
//이거 사용하면 됨👇
setOnItemSelectedListener
아래와 같이 MenuItem이 람다의 인자로 내려오게 된다.
bottomNavigationView.setOnItemSelectedListener { MenuItem ->
when (MenuItem.itemId) {
R.id.home -> replaceFragment(homeFragment)
R.id.chatList -> replaceFragment(chatlistFragment)
R.id.myPage -> replaceFragment(myPageFragment)
}
true
}
프래그먼트를 교체해주기 위해서는 프래그먼트매니저의 도움을 받아야 한다.
private fun replaceFragment(fragment : Fragment) {
Log.d("MainActivity","${fragment}")
supportFragmentManager.beginTransaction()
.apply {
replace(R.id.fragmentCotainer,fragment)
commit()
}
}
와 같이 구성하면 된다. replace의 첫번째 인자에 두번째 인자를 보여준다는 뜻이다.
# 마치며
처음 공부하는 개념이라 조금 꼼꼼히 기록했다. 프래그먼트를 많이 활용해야지 유저에게 조금 더 친숙한 디자인이 될 것 같다.
# 참고
프래그먼트 매니저에 대한 설명