프로그래밍/안드로이드

안드로이드 - 3. 네비게이션 드로어(Navigation Drawer) 사용하기

가카리 2017. 9. 23. 15:38
반응형
내용 및 사진 출처 : http://androidhuman.com/524
                            http://freehoon.tistory.com/29
안드로이드 소스 출처 : https://www.inflearn.com/course/

예제 깃헙 주소

Navigation Drawer는 다음과 같이 왼쪽에서 드래그를 했을 때 나오는 뷰입니다.


위 그림과 같이 DrawerLayout 내에 뷰를 선언하게 되면 뷰들이 쌓이게 됩니다. 

따라서 DrawerLayout을 맨아래 깔아두지 않으면 앞에 있는 뷰가 먼저 이벤트를 낚아채서 

DrawerLayout으로 이벤트가 전달되지 않습니다.

그러면 먼저 activity_main.xml를 확인해 봅시다.

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:openDrawer="start">

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

    <android.support.design.widget.NavigationView
        android:id="@+id/nav_view"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:fitsSystemWindows="true"
        app:headerLayout="@layout/nav_header_main"
        app:menu="@menu/activity_main_drawer" />

</android.support.v4.widget.DrawerLayout>


분석 

전체 앱을 DrawerLayout이 감싸고 있고 include를 이용해서  app_bar_main을 가져오고

NavigationView가 있는 것을 볼 수 있습니다.

android:fitsSystemWindows  속성 : 뷰가 차지할 수 있는 영역을 상태바 및 소프트키 영역을 제외한 

영역까지 확장해주는 역할을 합니다.

tools:openDrawer 속성 : Drawer가 어디서 나올지 결정합니다. start는 왼쪽 end는 오른쪽입니다.

app:headerLayout은 헤더부분의 레이아웃을 지정하는데 여기서는 nav_header_main을 지정했습니다.
app:menu는 메뉴의 레이아웃을 지정하는데 여기서는 activity_main_drawer를 지정했습니다.

다음은 nav_header_main의 레이아웃 디자인입니다.



다음은 activity_menu_drawer.xml 디자인 입니다.




다음은 app_bar_main.xml 소스입니다.

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout 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="com.example.kch.tutorial_nav2.MainActivity">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:popupTheme="@style/AppTheme.PopupOverlay" />

    </android.support.design.widget.AppBarLayout>

    <include layout="@layout/content_main" />

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:layout_margin="@dimen/fab_margin"
        app:srcCompat="@android:drawable/ic_dialog_email" />

</android.support.design.widget.CoordinatorLayout>



분석 
CoordinatorLayout 은 스크롤시 헤더부분의 애니메이션 처리를 위한 것인데 이번 예제에서는 다루지 않습니다.

Toolbar 를 AppBarLayout으로 감싸서 도구 모음을 제어 할 수 있습니다.

그다음 content_main.xml을 include하고 마지막 아래에 FloatingActionButton을 넣습니다.

FloatingActionButton은 다음 그림의 편지 모양 버튼입니다.



first_layout.xml

간단히 텍스트 뷰 하나를 배치했습니다.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent" android:layout_height="match_parent">

    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:text="fisrt layout"
        android:textAppearance="@style/TextAppearance.AppCompat.Display3" />
</RelativeLayout>


second_view.xml

또한 간단한 텍스트뷰 한개만 배치되어 있습니다.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent" android:layout_height="match_parent">

    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:text="second layout"
        android:textAppearance="@style/TextAppearance.AppCompat.Display3" />
</RelativeLayout>

FirstLayout.java

위의  first_layout.xml파일을 가져와서 실제 View객체로 만듭니다.


package com.example.kch.tutorial_nav2;

import android.app.Fragment;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

/**
* Created by kch on 2017. 9. 22..
*/

public class FirstLayout extends Fragment {
    View v;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {

        //inflate메소드는 XML데이터를 가져와서 실제 View객체로 만드는 작업을 합니다.
        v = inflater.inflate(R.layout.first_layout, container, false);

        return v;
    }
}

SecondLayout.java

FirstLayout클래스와 동일한 역할을 합니다.

package com.example.kch.tutorial_nav2;

import android.app.Fragment;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

/**
* Created by kch on 2017. 9. 22..
*/

public class SecondLayout extends Fragment {
    View v;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
        v = inflater.inflate(R.layout.second_layout, container, false);

        return v;
    }
}

MainActivity.java

설명은 주석에 달아놨습니다.

package com.example.kch.tutorial_nav2;

import android.app.FragmentManager;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.view.View;
import android.support.design.widget.NavigationView;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;

public class MainActivity extends AppCompatActivity
        implements NavigationView.OnNavigationItemSelectedListener {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //툴바를 가져온후
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        //setSupportActionBar() 메서드는 인자로 받은 툴바를 액티비티의 액션바로 대체하는 역할을 합니다. 기본으로 제공되는 액션바 외에 별도로 툴바를 사용하고 싶다면 이 메서드를 호출하지 않고 툴바만 단독으로 사용하는 것도 가능합니다.



        //FloatingActionButton을 가져온 후
        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        //리스너를 달아줍니다.
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });

        //DrawerLayout 먼저 지정해줍니다.
        DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);

        //ActionBarDrawerToggle(Activity activity, DrawerLayout drawerLayout, int openDrawerContentDescRes, int closeDrawerContentDescRes)
        ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
                this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
        drawer.setDrawerListener(toggle);

        toggle.syncState();

        NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
        navigationView.setNavigationItemSelectedListener(this);
        //네비게이션뷰 클릭 시 onNavigationItemSelected로 이동합니다.
    }

    @Override
    public void onBackPressed() {
        DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
        if (drawer.isDrawerOpen(GravityCompat.START)) {
            drawer.closeDrawer(GravityCompat.START);
        } else {
            super.onBackPressed();
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    @SuppressWarnings("StatementWithEmptyBody")
    @Override
    public boolean onNavigationItemSelected(MenuItem item) {
        // Handle navigation view item clicks here.
        int id = item.getItemId();

        FragmentManager manager = getFragmentManager();

        //first layout 메뉴 버튼이 눌리면 실행됨
        if (id == R.id.nav_first_layout) {
            //content_main을 FirstLayout으로 대체합니다
            manager.beginTransaction().replace(R.id.content_main, new FirstLayout()).commit();

        //first layout 메뉴 버튼이 눌리면 실행됨
        } else if (id == R.id.nav_second_layout) {
            //content_main을 SecondLayout으로 대체합니다
            manager.beginTransaction().replace(R.id.content_main, new SecondLayout()).commit();

        } else if (id == R.id.nav_share) {

        } else if (id == R.id.nav_send) {

        }

        DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
        drawer.closeDrawer(GravityCompat.START);//Drawer를 닫음
        return true;
    }
}



실행 화면


첫 실행 화면입니다. 네비게이션 드로어를 사용하기 위해서 왼쪽을 드래그해주면



다음과 같이 네비게이션 드로어가 나옵니다. 여기서 fisrt layout을 누르면 



다음과 같이 first layout으로 내용이 바뀝니다.