본문 바로가기
Android/[Kotlin]

[Android][Kotlin] Schedule app - 메인 액티비티(1)

by PhoB 2023. 5. 9.

일단 앱을 만들기 시작했으니 기본적으로 Main Activity의 레이아웃을 구성하려고 한다.

메인 액티비티는 단순하게 Fragment를 띄울 FramLayout하나와 Bottom Navigation Bar 한개로만 구성하였다.

메인 액티비티

프레그먼트를 띄울 Framlayout은 정말 필수적인 설정 외에는 하지 않았다.

<FrameLayout
    android:id="@+id/main_frame"
    android:layout_width="match_parent"
    android:layout_height="0dp"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintBottom_toTopOf="@id/bottom_layout"
    android:orientation="vertical">
</FrameLayout>

그러면 이제 남은것은 Bottom Navigation Bar이다

우선 네비게이션 바를 사용하기위해 의존성을 추가해줬다.

def nav_version = "2.5.3"
/*네비게이션바 의존성*/
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"

글을 작성하는 5월 8일기준 23년 2월22일 업데이트된 2.5.3버전이 최신버전이다.

최신버전 확인은 아래 링크에서 하면 된다.

 

Navigation  |  Android 개발자  |  Android Developers

컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. Navigation Navigation은 Android 애플리케이션 내에서 '대상' 사이를 탐색하는 프레임워크로, 대상이 Fragment, Activity

developer.android.com

이후 다시 xml파일로 돌아와서 네비게이션 바를 추가해주자

<com.google.android.material.bottomnavigation.BottomNavigationView
    android:id="@+id/nav_bar"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:menu="@menu/bottom_navbar"
    app:itemIconSize="35dp"
    app:labelVisibilityMode="unlabeled" <!-- 메뉴xml에서 설정한 title의 노출 여부 , 디폴트는 able -->
    android:background="@color/white"
    />

 

메뉴 아이템의 아이콘들은 구글 폰트에서 기본 제공하는 아이콘들을 가져와서 사용하였다

 

Material Symbols and Icons - Google Fonts

Material Symbols are our newest icons consolidating over 2,500 glyphs in a single font file with a wide range of design variants.

fonts.google.com

 

이제 레이아웃이 끝났으니 메인 액티비티 클래스의 코드를 작성해 주도록 하자

우선 뷰 바인딩을 사용해 주었다. 뷰 바인딩을 사용하면 장점이 여러가지가 있겠지만 무엇보다 매번 위젯 등록을 안해줘도 되기 때문에 굉장히 편해진다는것이 가장 큰 강점인것 같다.

// 전역 변수로 바인딩 객체 선언
private var mBinding: ActivityMainBinding? = null
// 매번 null 체크를 할 필요 없이 편의성을 위해 바인딩 변수 재 선언
private val binding get() = mBinding!!

그리고 네비게이션 바에서 메뉴를 누를시 그에 해당하는 프레그먼트로 이동하도록 setFrag()라는 함수를 만들었다.

private fun setFrag(fragNum: Int) {
    val ft = supportFragmentManager.beginTransaction()
    when(fragNum){
        0 -> {
            ft.replace(R.id.main_frame, RecycleView_Frag()).commit()
        }
        1-> {
            ft.add(R.id.main_frame, Add_schedule_fragment()).commit()
        }
        2->{
        
        }
    }
}

메뉴 아이템은 총 3개가 있지만 나머지 하나는 맨 마지막에 구현할 생각이기 때문에 따로 만들어두지 않았다.

자 이제 뷰 바인딩도 설정해 주었고, 함수도 만들어두었으니 이제 onCreate()에서 이용해주기만 하면된다.

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

    setFrag(0)
    binding.navBar.run{setOnNavigationItemSelectedListener {
        when(it.itemId){
            R.id.account ->{
                setFrag(0)
                true
            }
            R.id.add ->{
                setFrag(1)
                true
            }
            else -> false
        }
    }}
}

뷰 바인딩객체와 메인 액티비티를 연결시켜준뒤 RecycleView_Frag 프레그먼트가 제일 먼저 노출되는 화면이기 때문에 setFrag(0)으로 맨 처음에 노출되게 설정해 주었다.

글을 작성하면서 다시 코드를 들여다보니 setOnNavigationItemSelectedListener{}는 이제 사용이 권장되지 않는 메서드라고 한다. 현재 권장되는 메소드는 setOnItemSelectedListener 이라고 하는데 사실 목적에 따라서 사용하는것이 달라진다.

메소드명 setOnNavigationItemSelectedListener setOnItemSelectedListener 
Callback시점 메뉴 아이템이 선택될 때마다 즉각적으로 Callback이 실행 선택된 아이템이 바뀌는 순간에만 Callback이 실행

즉 setOnNavigationItemSelectedListener는 선택된 메뉴 아이템에 대한 즉각적인 처리가 필요할 때 사용하고, setOnItemSelectedListener는 선택된 아이템이 변경될 때만 처리가 필요할 때 사용된다고 생각하면 되겠다.

추가적으로 setOnItemSelectedListener는  API 28이상 부터 동작한다고 하니 유의하자

아래는 메인 액티비티 클래스와 레이아웃 전체 코드이다.

class MainActivity : AppCompatActivity() {


    // 전역 변수로 바인딩 객체 선언
    private var mBinding: ActivityMainBinding? = null
    // 매번 null 체크를 할 필요 없이 편의성을 위해 바인딩 변수 재 선언
    private val binding get() = mBinding!!

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

        setFrag(0)
        binding.navBar.run{setOnNavigationItemSelectedListener {
            when(it.itemId){
                R.id.account ->{
                    setFrag(0)
                    true
                }
                R.id.add ->{
                    setFrag(1)
                    true
                }
                else -> false
            }
        }}
    }

    private fun setFrag(fragNum: Int) {
        val ft = supportFragmentManager.beginTransaction()
        when(fragNum){
            0 -> {
                ft.replace(R.id.main_frame, RecycleView_Frag()).commit()
            }
            1-> {
                ft.add(R.id.main_frame, Add_schedule_fragment()).commit()
            }
            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/main_frame"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toTopOf="@id/bottom_layout"
        android:orientation="vertical">
    </FrameLayout>

    <LinearLayout
        android:id="@+id/bottom_layout"
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:gravity="center"
        app:layout_constraintBottom_toBottomOf="parent"
        android:orientation="horizontal"
        >
        <com.google.android.material.bottomnavigation.BottomNavigationView
            android:id="@+id/nav_bar"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:menu="@menu/bottom_navbar"
            app:itemIconSize="35dp"
            app:labelVisibilityMode="unlabeled"
            android:background="@color/white"
            />
    </LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>