개발 끄적끄적/Android

[Android Kotlin] Navigation Drawer를 이용한 사이드 메뉴 만들기

공간을담다 2020. 6. 1. 20:48
반응형

Google Play Store, Gmail 등 많은 앱에서 사용되고 있는 메뉴를 알아보겠습니다.  三 모양의 버튼(일명 햄버거 버튼)으로 왼쪽에서 열리는 사이드 메뉴를 많이 보셨을텐데요. 직접 커스텀할 수 있는 사이드 메뉴를 만들어보겠습니다.


DrawerLayout

서랍이라는 의미의 Drawer를 따서 DrawerLayout은 '평소에는 숨어 있다가 사용자의 액션을 받아 나타나는 기능을 도와주는 레이아웃' 입니다. DrawerLayout 자체가 사라지는 것이 아닌 DrawerLayout에 추가된 child layout이 서랍의 기능을 하도록 해주는 것입니다.

 

하지만 DrawerLayout의 모든 child layout이 서랍의 기능을 수행하는 것은 아닙니다.

보통 DrawerLayout의 자식은 두개의 layout으로 구성됩니다.

 

하나는 메뉴(서랍)가 열리기 전 화면을 보여주는 activity이며,

다른 하나는 메뉴의 화면을 담당하는 fragment입니다.

 

DrawerLayout 구조

xml의 가장 최상단은 DrawerLayout으로 구성됩니다. 자식으로 fragment와 activity를 가지며,
fragment에 layout_gravity 값을 주어 메뉴로써 동작하게 합니다.

 

layout_gravity에 "left" 값을 주면 왼쪽에서 열리고 닫히는 메뉴가 되며, 반대로 "right" 값을 주면 오른쪽에서 열리고 닫히는 메뉴가 됩니다.

 

메뉴는 기본적으로 끝을 스와이프(Edge Swipe)해 열 수 있습니다.
그 외에 동적으로 열고 닫기 위해서는 openDrawer() 메소드와 closeDrawer() 메소드가 사용됩니다.

본 포스팅에서는 버튼 하나에 openDrawer() 메소드를 달아 사용해보겠습니다.

 

아래는 파라미터에 따른 openDrawer() 메소드입니다.

리턴 타입 함수 설명
void openDrawer(drawerView : View,
animate : Boolean)
drawerView 열기. animate에 따라 애니메이션 결정.
(API 24.0.0 이상)
void openDrawer(drawerView : View) 애니메이션과 함께 drawerView 열기
void openDrawer(gravity : Int) 지정된 Drawer를 gravity 방향에서 애니메이션과 함께 열기
void openDrawer(gravity : Int, animate Boolean) 지정된 Drawer를 gravity 방향에서 열기. animate에 따라 애니메이션 여부 결정 (API 24.0.0 이상)

 

 

Drawer가 swipe 에 의해 열리고 닫히는 것을 막기 위한 메소드도 있습니다.

setDrawerLockMode(lockMode : Int) 입니다.

lockMode 설명
LOCK_MODE_UNLOCKED 0x00000000 Lock 기능 비활성화. Swipe에 의해 열리고 닫힘
LOCK_MODE_LOCKED_CLOSED 0x00000001 Drawer가 닫힌 채로 잠김. 만약 Drawer가 열려있었다면 닫힘
LOCK_MODE_LOCKED_OPEN 0x00000002 Drawer가 열린 채로 잠김. 만약 Drawer가 닫혀있었다면 열림

 

이 메소드는 swipe에 의한 열림/닫힘을 막아주는 기능만 있어서 openDrawer()와 closeDrawer() 메소드에 의한 열림/닫힘은 여전히 동작합니다.

 


open_menu_btn 이라는 버튼에 메뉴 열기 기능을 주고 DrawerLayout 안의 버튼, layout에 기능을 부여하는 예제를 만들어보았습니다. MainActivity.kt 의 setContentView가 activity_main 이 아닌 main_include_drawer인 점을 유의해주시길 바랍니다.

 

 

우선 액션바를 따로 사용하지 않을 것이기에 theme를 AppTheme.NoActionBar로 설정해줍니다.

 

1. res - values - styles 에 아래와 같은 스타일을 만들어줍니다.

styles.xml에 추가

 

2. manifest의 application에 theme를 변경해줍니다.

manifest의 application


이제 MainActivity와 연결할 DrawerLayout을 생성해줍니다.

main_include_drawer.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout
    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:id="@+id/main_drawer_layout"
    tools:openDrawer="start"
    android:fitsSystemWindows="true"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    
    <!--fitsSystemWindows를 true로 지정할 경우 
    뷰가 차지할 수 있는 영역을 소프트키, 상태바를 제외한 영역까지 넓혀줍니다.-->
    
    

    <include
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        layout="@layout/activity_main"/>

    <com.google.android.material.navigation.NavigationView
        android:id="@+id/navigation_view"
        android:orientation="vertical"
        android:background="#313131"
        android:layout_gravity = "left"
        app:itemTextColor="#fff"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <include
                android:id="@+id/main_header_include_logged_in"
                android:visibility="invisible"
                app:layout_constraintTop_toTopOf="parent"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                layout="@layout/main_drawer_header_logged_in"/>

            <include
                android:id="@+id/main_header_include_logged_out"
                android:visibility="visible"
                app:layout_constraintTop_toTopOf="parent"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                layout="@layout/main_drawer_header_logged_out"/>


            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                app:layout_constraintTop_toBottomOf="@id/main_header_include_logged_in"
                app:layout_constraintLeft_toLeftOf="parent"
                android:orientation="vertical">

                <Button
                    android:id="@+id/main_navigation_btn1"
                    android:clickable="true"
                    android:enabled="false"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:background="#313131"
                    style="?android:attr/borderlessButtonStyle"
                    android:layout_marginLeft="21dp"
                    android:layout_marginTop="20dp"
                    android:text="메뉴 1"
                    android:textSize="18sp"
                    android:textColor="#777777"/>

                <Button
                    android:id="@+id/main_navigation_btn2"
                    android:clickable="true"
                    android:enabled="false"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:background="#313131"
                    style="?android:attr/borderlessButtonStyle"
                    android:layout_marginLeft="21dp"
                    android:text="메뉴 2"
                    android:textSize="18sp"
                    android:textColor="#777777"/>

                <Button
                    android:id="@+id/main_navigation_btn3"
                    android:clickable="true"
                    android:enabled="false"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:background="#313131"
                    style="?android:attr/borderlessButtonStyle"
                    android:layout_marginLeft="21dp"
                    android:text="메뉴 3"
                    android:textSize="18sp"
                    android:textColor="#777777"/>
            </LinearLayout>
        </androidx.constraintlayout.widget.ConstraintLayout>
    </com.google.android.material.navigation.NavigationView>
</androidx.drawerlayout.widget.DrawerLayout>

 

MainActivity.kt

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.main_include_drawer)
		
        //버튼을 눌러 메뉴를 오픈할 수도 있고, 왼쪽에서 오른쪽으로 스왑해 오픈할 수 있습니다.
        //DrawerLayout의 id에 직접 openDrawer()메소드를 사용할 수 있습니다.
        open_menu_btn.setOnClickListener {
            main_drawer_layout.openDrawer((GravityCompat.START))
        }

        navigation_header_logout_btn.setOnClickListener {
            logOut()
        }

        navigation_header_login_btn.setOnClickListener {
            logIn()
        }

        main_navigation_btn1.setOnClickListener {
            //버튼1 클릭 시
        }

        main_navigation_btn2.setOnClickListener {
            //버튼2 클릭 시
        }

        main_navigation_btn3.setOnClickListener {
            //버튼3 클릭 시
        }
    }

    private fun logOut(){
        main_header_include_logged_in.visibility = View.INVISIBLE
        main_header_include_logged_out.visibility = View.VISIBLE
        main_navigation_btn1.isEnabled = false
        main_navigation_btn1.setTextColor(Color.parseColor("#777777"))
        main_navigation_btn2.isEnabled = false
        main_navigation_btn2.setTextColor(Color.parseColor("#777777"))
        main_navigation_btn3.isEnabled = false
        main_navigation_btn3.setTextColor(Color.parseColor("#777777"))
    }

    private fun logIn(){
        main_header_include_logged_in.visibility = View.VISIBLE
        main_header_include_logged_out.visibility = View.INVISIBLE
        main_navigation_btn1.isEnabled = true
        main_navigation_btn1.setTextColor(Color.parseColor("#ffffff"))
        main_navigation_btn2.isEnabled = true
        main_navigation_btn2.setTextColor(Color.parseColor("#ffffff"))
        main_navigation_btn3.isEnabled = true
        main_navigation_btn3.setTextColor(Color.parseColor("#ffffff"))
    }
}

 


 

실행화면

 

반응형