오늘은 BottomNavigationView에 대해서 공부해보았습니다.
예를 들면 위와 같이 아래쪽 부분에 메뉴가 이번 주제입니다.
먼저 gradle(Module)에 dependecies부분에
implementation 'com.google.android.material:material:1.6.1'
를 추가시켜줍니다.
BottomNavigationView에서 사용될 item들은 안드로이드 리소스 중에서도 menu로 정의됩니다.
res -> new -> android resource file 에서 type을 values에서 menu로 바꾸고 이름을 저는 bottom_menu라고 하겠습니다.
만들면 다음과 같이
생성이 완료됩니다.
그 후 menu에 들어가서 item을 설정해줄 겁니다. BottomNavigationView 공식 홈페이지를 살펴보면 주의사항이 존재하는데 간단하게 설명하자면 하단에 item은 5개 초과로 설정하면 안됩니다. 그리고 item에 넣을 text가 너무 길어도 안됩니다. 등이 주의 사항으로 존재합니다.
저는 총 4개를 만들려고 합니다. menu에 item을 추가해줍니다.
<?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/home"
android:icon="@drawable/ic_menu_home"
android:title="Home"
android:enabled="true"
/>
<item
android:id="@+id/search"
android:icon="@android:drawable/ic_menu_search"
android:title="Search"
android:enabled="true"
/>
<item
android:id="@+id/camera"
android:icon="@android:drawable/ic_menu_camera"
android:title="Camera"
android:enabled="true"
/>
<item
android:id="@+id/account"
android:icon="@drawable/ic_menu_account"
android:title="Account"
android:enabled="true"
/>
</menu>
4개의 item과 id, icon등을 생성해줍니다. enabled는 true로 버튼을 활성화 하겠다는 뜻입니다.
그 후 item을 4개 만들었으니 4개의 fragment가 필요하겠죠?
위 사진처럼 directory인 navigation을 만들어 그 안에 Empty fragment를 생성해줍니다.
fragment의 코드는 건들지 않을 것이니 그대로 놔둡니다.
fragment의 xml은 첫 태그를 FrameLayout으로 변경하고 text와 gravity만 원하는대로 변경해줍니다.
작성자의 xml
<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=".navigation.AccountFragment">
<!-- TODO: Update blank fragment layout -->
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="@string/account"
android:textSize="50sp"
android:gravity="center"/>
</FrameLayout>
다음으로 저는 전에 했던 GoogleLogin 코드에서 시작했기 때문에 MainActivity는 Login과 CreateAccount를 담당하도록 하고 로그인 완료시 TestActivity로 이동하기 위해 Empty Activity로 생성해줍니다.
Activity를 만들면 자동으로 xml이 추가될 텐데 첫 태그는 LinearLayout으로 하고
다음에 메인화면을 담을 LinearLayout하나와 대망의 BottomNavigationView를 선언해줍니다.
<LinearLayout 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"
android:orientation="vertical"
tools:context=".TestActivity">
<LinearLayout
android:id="@+id/main_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
/>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/bottom_navigationview"
android:layout_height="56dp"
android:layout_width="match_parent"
app:itemBackground="@color/black"
app:menu="@menu/bottom_menu" />
</LinearLayout>
이제 토대를 완성하였으니, 본격적으로 코드를 건드리겠습니다.
package com.example.clonecoding_instagram
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.LinearLayout
import androidx.fragment.app.Fragment
import com.example.clonecoding_instagram.databinding.ActivityTestBinding
import com.example.clonecoding_instagram.navigation.AccountFragment
import com.example.clonecoding_instagram.navigation.CameraFragment
import com.example.clonecoding_instagram.navigation.HomeFragment
import com.example.clonecoding_instagram.navigation.SearchFragment
import com.google.android.gms.auth.api.signin.GoogleSignInClient
import com.google.android.material.bottomnavigation.BottomNavigationView
import com.google.firebase.auth.FirebaseAuth
import kotlinx.android.synthetic.main.activity_test.*
import kotlin.math.sign
class TestActivity : AppCompatActivity() {
private lateinit var main_content : LinearLayout
private lateinit var bottom_navigationview : BottomNavigationView
private var auth: FirebaseAuth = FirebaseAuth.getInstance()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_test)
/*val btn : Button = findViewById(R.id.sign_out)
btn.setOnClickListener {
signOOut()
}*/
init()
initNavigationBar()
}
private fun init() {
main_content = findViewById(R.id.main_content)
bottom_navigationview = findViewById(R.id.bottom_navigationview)
}
private fun initNavigationBar() {
bottom_navigationview.run {
setOnNavigationItemSelectedListener {
//id에 알맞은 fragment로 변경
when(it.itemId) {
R.id.home -> {
changeFragment(HomeFragment())
}
R.id.search -> {
changeFragment(SearchFragment())
}
R.id.camera -> {
changeFragment(CameraFragment())
}
R.id.account -> {
changeFragment(AccountFragment())
}
}
true
}
selectedItemId = R.id.home
}
}
//아래 item클릭 시 변경될 fragment
private fun changeFragment(fragment : Fragment) {
supportFragmentManager
.beginTransaction()
.replace(R.id.main_content, fragment)
.commit()
}
}
init으로 먼저 객체를 정의하고
initNavigationBar에서 setOnNavigationItemSelectedListener을 통해 id에 알맞은 fragment를 changeFragment를 통해서 전환되도록 하였습니다.
추가!
여기에 저는 fragment_home.xml에서 로그아웃버튼을 추가하였습니다.
그 후 fragment는 OnClickListener를 상속받아 onClick메소드를 통해 로그아웃을 구현하였습니다.
package com.example.clonecoding_instagram.navigation
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import com.example.clonecoding_instagram.R
import com.example.clonecoding_instagram.databinding.ActivityMainBinding
import com.example.clonecoding_instagram.databinding.FragmentHomeBinding
import com.google.firebase.auth.FirebaseAuth
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private const val ARG_PARAM1 = "param1"
private const val ARG_PARAM2 = "param2"
/**
* A simple [Fragment] subclass.
* Use the [HomeFragment.newInstance] factory method to
* create an instance of this fragment.
*/
class HomeFragment : Fragment(), View.OnClickListener {
private lateinit var mBinding: FragmentHomeBinding
private var param1: String? = null
private var param2: String? = null
private var auth : FirebaseAuth = FirebaseAuth.getInstance()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
param1 = it.getString(ARG_PARAM1)
param2 = it.getString(ARG_PARAM2)
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
mBinding = FragmentHomeBinding.inflate(inflater,container,false)
val btn : Button = mBinding.root.findViewById(R.id.sign_out)
btn.setOnClickListener(this)
return mBinding.root
}
companion object {
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @param param1 Parameter 1.
* @param param2 Parameter 2.
* @return A new instance of fragment HomeFragment.
*/
// TODO: Rename and change types and number of parameters
@JvmStatic
fun newInstance(param1: String, param2: String) =
HomeFragment().apply {
arguments = Bundle().apply {
putString(ARG_PARAM1, param1)
putString(ARG_PARAM2, param2)
}
}
}
override fun onClick(v: View?) {
auth.signOut()
//fragment는 finish가 없으므로 activity를 받아서 finish
activity?.finish()
}
}
아래는 Emulator로 실행 시켜본 gif입니다.
참조
BottomNavigationView
Fragment Finish
BottomNavigationView 공식홈페이지