안드로이드 드로어레이아웃. (Android DrawerLayout)

2017. 10. 13. 17:10


1. 화면의 특정 영역에서 동적으로 열리고, 닫히는 사용자 인터페이스.

통상적으로, "안드로이드 레이아웃"이라고 하면, 화면의 전체 또는 일부에 자신의 영역을 확보한 다음, 정해진 규칙에 따라 자식(Children) 뷰 위젯들을 배치하는 역할을 하는 요소를 말합니다. 


한 방향으로 뷰(View) 위젯을 나열하는데 사용되는 [리니어레이아웃(LinearLayout)], 뷰(View) 위젯 간 상대적 위치에 따라 자식(Children)들을 정렬하는 [렐러티브레이아웃(RelativeLayout)], 액자 형태로 뷰(View) 위젯을 바꿔가면서 표시하기 위한 [프레임레이아웃(FrameLayout)], 그리고 표 형태의 레이아웃을 구성할 때 사용하는 [테이블레이아웃(TableLayout)] 등, 여러 종류의 레이아웃들이 바로 그런 역할을 수행합니다.


그런데 앞에서 살펴본 요소들처럼 고정 영역에 레이아웃이 표시되는 형태가 아니라, 사용자의 액션에 따라 화면의 일부분이 나타나거나 사라지게 만드려면 어떻게 해야 할까요? 마치 책상에서 "서랍"이 열리고 닫히는 것처럼, 평소에는 화면의 한 쪽에 숨겨져 있다가, 사용자가 화면을 스와이프하거나 메뉴 버튼을 선택하면 화면에 표시되는 형태 말이죠.

DrawerLayout 동작


물론, 여러 레이아웃 중 하나를 사용하여 화면을 구성한 다음, 사용자 입력 이벤트 핸들러를 작성하여, 레이아웃의 visibility를 조절하는 방법을 선택할 수 있을 것입니다. 거기에 더해 레이아웃이 나타나고 사라지는 과정의 애니메이션 효과까지 구현해주면 더 좋겠죠.


하지만 개발자가 하나하나 모두 구현해야 하는 수고를 들이지 않아도 "서랍"처럼 화면이 열리고 닫히는 기능을 수행할 수 있게 만들어 주는 레이아웃이 있습니다. 바로 DrawerLayout입니다.

2. 안드로이드 DrawerLayout

DrawerLayout의 "Drawer"는 사전적으로 "서랍"을 의미하는 단어입니다.

Drawer의 사전적 의미


Drawer라는 단어가 뜻하는 "서랍"이 열리고 닫히는 것처럼, DrawerLayout"평소에는 화면의 한쪽에 숨겨져 있다가 사용자가 액션을 취하면 화면에 나타나는 기능을 만들 수 있게 해주는 레이아웃"입니다.


DrawerLayout 클래스


하지만 DrawerLayout에 대한 설명을 보고, DrawerLayout 자체가 화면에 나타나거나 사라지는 동작을 수행하는 것으로 오해하면 안됩니다. DrawerLayout에 추가된 자식(Children)이 DrawerLayout의 영역 안에서 "Drawer(서랍)"와 같은 동작을 수행하도록 만들어주는 것이죠.


그리고 DrawerLayout에 추가된 모든 자식(Children)들이 Drawer로 동작하는 것이 아니라는 사실에도 주의해야 합니다. 자식(Children)들 중 layout_gravity 속성 값을 가지지 않은 자식(Child)은 기본적으로 표시되는 주화면으로 취급되고, layout_gravity 속성 값을 가진 자식(Child)만이 Drawer로써 동작하는 것이죠. 또한 Drawer가 어느 방향에서 열릴지는 layout_gravity에 지정된 값(left or right)에 의해 결정됩니다.


음, 글로 설명한 내용만으로는 쉽게 이해가 되지 않죠? 하지만 넘 머리 아파하지 마세요. 아래에서 좀 더 자세한 설명과 예제를 통해 DrawerLayout을 어떻게 사용하는지 완벽히 이해하실 수 있을 것입니다.


그럼, 지금부터 DrawerLayout의 사용 방법 및 동작, 그리고 제약 사항들에 대해 알아보겠습니다.

2.1 DrawerLayout의 기본 레이아웃 구성.

DrawerLayout을 사용하여 화면이 열리고 닫히는 기능을 구현하기 위해서는 DrawerLayout에 최소 두 개의 자식(Children)이 추가되어야 합니다. 하나는 Drawer 역할을 수행할 화면이고, 다른 하나는 Drawer가 닫혀있는 상태에서 표시될 주화면입니다.

DrawerLayout의 화면 구성


어떤 화면이 Drawer로 사용될 것인지는, 레이아웃 리소스 XML에 기록된 순서와 layout_gravity 속성의 유무로 결정됩니다. 즉, DrawerLayout의 첫 번째 자식(Child)이 주 화면으로 표시되고, 그 아래 layout_gravity 속성을 가지는 자식(Child)이 Drawer로 사용됩니다.

DrawerLayout의 기본 레이아웃


DrawerLayout에서 Drawer가 어느 방향에서 열리고 닫힐지는 layout_gravity에 지정된 값에 의해 결정되며, 가로 방향에 대해서만 지정할 수 있습니다. 즉, left(start) 또는 right(end) 값만 사용할 수 있습니다.

DrawerLayout layout_gravity 지정


DrawerLayout에 하나의 Drawer만 사용하는게 일반적이긴 하지만, 그렇다고 반드시 하나의 Drawer만 사용할 수 있는 것은 아닙니다. 정확히 말하면, 각 방향에 하나씩의 Drawer를 지정할 수 있죠. 그러므로 (실제로 잘 쓰이진 않지만) 아래와 같은 경우도 가능한 것입니다.

DrawerLayout layout_gravity left and right


2.2 DrawerLayout에서 Drawer의 크기

DrawerLayout의 Drawer는 layout_gravity 값에 따라 왼쪽 또는 오른쪽 방향으로 열리고 닫히기 때문에, Drawer의 너비는 DrawerLayout보다 작은 고정(fixed) 값으로, Drawer의 높이는 DrawerLayout의 높이와 같은 값으로 지정하는 게 일반적입니다.

DrawerLayout layout_width and layout_height


그리고 Drawer가 아닌 주화면은 DrawerLayout 전체 영역에 표시됩니다. 그래서 DrawerLayout 주화면으로 사용되는 자식(Children)은 지정된 layout_width, layout_height 값과 관계없이, match_parent로 동작합니다.

2.3 DrawerLayout 기본 동작.

최초 DrawerLayout이 화면에 표시될 때는, Drawer 화면이 표시되지 않습니다. 주화면, 즉, Drawer가 아닌 자식(Child)의 화면만 표시되죠. 이 때 left에 위치한 Drawer가 열리게 만들기 위해서는 화면 왼쪽 가장자리에서 시작하여 오른쪽 방향으로 쓸어넘기는 스와이프(Swipe) 동작을 수행하면 됩니다. right에 위치한 Drawer는 오른쪽 가장자리에서 시작하여 왼쪽 방향으로 스와이프(Swipe)하면 됩니다. 그리고 Drawer를 닫으려면 열기 방향의 반대로 스와이프(Swipe) 동작을 수행하거나, DrawerLayout 상의 Drawer 외 영역을 클릭하면 됩니다.

DrawerLayout에서 Drawer 열기 및 닫기


하지만 누군가에게는 스와이프(Swipe) 동작이 어렵게 느껴질 수도 있고, 현재 화면에서 Drawer를 사용할 수 있다는 것을 모를 수도 있습니다. 이 때, 스와이프(Swipe)가 아닌 버튼 클릭 등을 통해 Drawer가 표시되게 만들 수 있는데, DrawerLayout에서 제공하는 함수를 통해 Drawer를 열거나 닫을 수 있습니다.

2.4 코드를 통해 Drawer 열기 및 닫기.

DrawerLayout의 Drawer 화면이 기본적으로 스와이프(Swipe) 동작에 의해 열리지만, DrawerLayout에서 제공되는 함수를 호출하면 외부 버튼 또는 메뉴를 통해 열리거나 닫히게 만들 수 있습니다. Drawer 열기 및 닫기, 즉, openDrawer() 함수와 closeDrawer() 함수를 사용하면 자바 코드에서 Drawer를 열고 닫는 게 가능합니다.


아래 표는 파라미터의 종류 및 갯수에 따라 구분된 openDrawer() 함수를 나타낸 것입니다.


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


closeDrawer() 함수의 종류는 아래와 같습니다.


리턴 타입 함수 설명
void closeDrawer(View drawerView) 애니메이션과 함께 drawerView 닫기.
void closeDrawer(int gravity) gravity 방향에 있는 Drawer를 애니메이션과 함께 닫기.
void closeDrawer(View drawerView, boolean animate) drawerView를 애니메이션과 함께 닫기. (API Level 24.0.0 이상)
void closeDrawer(int gravity, boolean animate) 지정된 Drawer를 gravity 방향으로 열기. animate에 따라 애니메이션 여부 결정. (API Level 24.0.0 이상)
void closeDrawers() 현재 열려 있는 모든 Drawer를 애니메이션과 함께 닫기.


openDrawer() 및 closeDrawer() 함수를 사용하여 Drawer를 열고 닫는 예제 코드는 아래와 같습니다.

    // left에 지정된 Drawer 열기.
    drawer.openDrawer(Gravity.LEFT) ;

    // left에 지정된 Drawer 닫기.
    drawer.closeDrawer(Gravity.LEFT) ;

2.5 Drawer 잠그기(Lock).

앞서 DrawerLayout의 동작에 대해 설명했듯이, DrawerLayout에서 Drawer를 열기 위해서는 Drawer가 닫혀있는 방향의 테두리에서 스와이프(Swipe) 액션을 수행하면 됩니다. 그런데 어떤 경우에는, 스와이프(Swipe)에 의해 Drawer가 열리고 닫히는 것을 막아야 하는 경우도 있습니다. 예를 들어 메뉴로 동작하는 Drawer가 열린 상태로 고정되거나, 현재 컨텐츠 화면에서 Drawer가 표시될 필요가 없는 경우가 바로 그런 경우죠.


이렇게 Drawer를 열린 상태로 고정 또는 닫힌 상태로 고정시키는 것을 Drawer 잠그기(Lock)라고 하는데, DrawerLayout의 setDrawerLockMode() 함수를 통해 Drawer 잠그기(Lock) 기능을 활성화 또는 비활성화 할 수 있습니다.

    void setDrawerLockMode(int lockMode) ;

setDrawerLockMode() 함수의 파라미터인 lockMode에는 아래의 값 중 하나를 지정할 수 있습니다.


lockMode Hex 값 설명
LOCK_MODE_UNLOCKED 0x00000000 잠그기(Lock) 기능 비활성화. 스와이프(Swipe)에 의해 열리고 닫힘.
LOCK_MODE_LOCKED_CLOSED 0x00000001 Drawer가 닫힌 채로 잠김(Locked). 만약 Drawer가 열려 있는 상태였다면 자동으로 닫힘.
LOCK_MODE_LOCKED_OPEN. 0x00000002 Drawer가 열린 채로 잠김(Locked). 만약 Drawer가 닫혀 있는 상태였다면 자동으로 열림.


참고로, setDrawerLockMode() 함수에 의해 Drawer가 잠김(Locked) 상태가 되면 스와이프(Swipe)에 의한 열기 또는 닫기는 불가능해지지만, openDrawer() 함수 또는 closeDrawer() 함수에 의한 열기 또는 닫기는 여전히 가능합니다.

3. DrawerLayout 사용하기

그럼 이제부터, 예제를 통해 DrawerLayout의 사용법에 대해 살펴보겠습니다.

DrawerLayout 사용 예제는 아래 그림과 같은 레이아웃으로 구성됩니다.

DrawerLayout 예제 레이아웃


3.1 MainActivity 레이아웃 작성하기.

앞서 설계한 화면 레이아웃에 따라 MainActivity의 레이아웃 리소스 XML 파일을 작성합니다.

[STEP-1] "activity_main.xml" - MainActivity 레이아웃 리소스 XML 파일
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context="com.recipes4dev.examples.drawerlayoutexample.MainActivity"
    tools:showIn="@layout/activity_main">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:text="Open"
        android:id="@+id/open" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintLeft_toRightOf="@id/open"
        android:text="Close"
        android:id="@+id/close" />

    <CheckBox
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintLeft_toRightOf="@id/close"
        app:layout_constraintBaseline_toBaselineOf="@id/close"
        android:text="Lock"
        android:id="@+id/lock" />

    <android.support.v4.widget.DrawerLayout
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@id/open"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        android:id="@+id/drawer">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:textSize="48sp"
            android:text="CONTENTS"
            android:background="#00BCD4"/>

        <TextView
            android:layout_width="400dp"
            android:layout_height="match_parent"
            android:gravity="center"
            android:textSize="48sp"
            android:text="DRAWER"
            android:background="#009688"
            android:layout_gravity="left" />
    </android.support.v4.widget.DrawerLayout>
</android.support.constraint.ConstraintLayout>

3.2 "Open" 버튼 클릭 이벤트 처리.

"Open" 버튼이 클릭되면, Drawer를 여는 코드를 작성합니다.

[STEP-2] "MainActivity.java" - onCreate() 함수에서 "Open" 버튼 클릭 이벤트 작성
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // 코드 계속 ...

        Button buttonOpen = (Button) findViewById(R.id.open) ;
        buttonOpen.setOnClickListener(new Button.OnClickListener() {
            @Override
            public void onClick(View v) {
                DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer) ;
                if (!drawer.isDrawerOpen(Gravity.LEFT)) {
                    drawer.openDrawer(Gravity.LEFT) ;
                }
            }
        });

        // ... 코드 계속
    }
}

3.3 "Close" 버튼 클릭 이벤트 처리.

"Close" 버튼이 클릭되면, 열려 있는 Drawer를 닫는 코드를 작성합니다.

[STEP-3] "MainActivity.java" - onCreate() 함수에서 "Close" 버튼 클릭 이벤트 작성
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        // 코드 계속 ...

        Button buttonClose = (Button) findViewById(R.id.close) ;
        buttonClose.setOnClickListener(new Button.OnClickListener() {
            @Override
            public void onClick(View v) {
                DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer) ;
                if (drawer.isDrawerOpen(Gravity.LEFT)) {
                    drawer.closeDrawer(Gravity.LEFT) ;
                }
            }
        });

        // ... 코드 계속
    }
}

3.4 "Lock" 체크박스 클릭 이벤트 처리.

"Lock" 체크박스가 클릭되면, Drawer를 잠그는 코드를 작성합니다.

[STEP-4] "MainActivity.java" - onCreate() 함수에서 "Lock" 체크박스 클릭 이벤트 작성
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
      
        // 코드 계속 ...

        CheckBox checkboxLock = (CheckBox) findViewById(R.id.lock) ;
        checkboxLock.setOnClickListener(new CheckBox.OnClickListener() {
            @Override
            public void onClick(View v) {
                DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer) ;
                if (((CheckBox)v).isChecked()) {
                    if (drawer.isDrawerOpen(Gravity.LEFT)) {
                        drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_OPEN);
                    } else {
                        drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
                    }
                } else {
                    drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
                }
            }
        });
    }
}

4. 실행 화면

예제 코드를 작성하고 실행하면, 아래 그림과 같은 화면이 표시됩니다.

DrawerLayout 예제 실행 화면


화면의 왼쪽 가장자리에서 오른쪽으로 스와이프(Swipe)하면 Drawer 화면이 열리고, 반대 방향으로 스와이프(Swipe)하거나 Drawer 외 공간을 클릭하면 Drawer가 닫히는 것을 확인할 수 있습니다.

DrawerLayout에서 스와이프로 Drawer 열기 및 닫기


그리고 화면 위의 "Open", "Close" 버튼을 클릭하면 Drawer가 열리고 닫히는 것을 확인할 수 있습니다.

DrawerLayout에서 버튼으로 Drawer 열기 및 닫기


마지막으로 "Lock" 체크박스를 체크한 상태에서는, 화면을 스와이프(Swipe)해도 Drawer가 열리거나, 닫히지 않은 것을 확인할 수 있습니다. 대신, "Open", "Close" 버튼을 클릭하는 경우, Drawer는 정상적으로 동작합니다.


아래 동영상을 통해, DrawerLayout 예제의 전체적인 동작 과정을 확인할 수 있습니다.


5. DrawerLayout 사용 시 주의 사항

5.1 Drawer로 동작하는 자식(Child)의 layout_gravity는 left(start) 또는 right(end)만 지정 가능.

DrawerLayout에서 Drawer가 위치하는 방향은 왼쪽 또는 오른쪽만 지정 가능합니다. 즉, Drawer의 layout_gravity 속성에 지정할 수 있는 값은 "left"(또는 "start")나 "right"(또는 "end")만 사용할 수 있는 것이죠. 만약 layout_gravity 값을 "top" 또는 "bottom"을 사용하면 아래와 같은 에러가 발생합니다.


java.lang.IllegalStateException: Child android.support.v7.widget.AppCompatTextView{d880155 V.ED..... ......ID 0,0-0,0} at index 2 does not have a valid layout_gravity - must be Gravity.LEFT, Gravity.RIGHT or Gravity.NO_GRAVITY

5.2 layout_gravity 속성 값이 동일한 자식(Child)을 추가할 수 없음.

보통 DrawerLayout에 하나의 Drawer를 만들지만, 오직 하나의 Drawer만 사용할 수 있는 것은 아닙니다. 정확히 말하면, layout_gravity에 지정되는 방향 별로 하나의 Drawer만 지정할 수 있죠. 그래서 만약 layout_gravity 속성 값이 동일한 Drawer가 둘 이상 있으면 에러가 발생합니다.

    <android.support.v4.widget.DrawerLayout ...>
        <TextView ...
            android:text="CONTENTS" />
        <TextView ...
            android:text="DRAWER 1"
            android:layout_gravity="left" />
        <TextView ...
            android:text="DRAWER 2"
            android:layout_gravity="left" />
    </android.support.v4.widget.DrawerLayout>


java.lang.IllegalStateException: Child drawer has absolute gravity LEFT but this DrawerLayout already has a drawer view along that edge

5.3 Drawer가 존재하지 않는 방향의 layout_gravity를 여는 경우는 에러 발생.

앞서 "2.4 코드를 통해 Drawer 열기 및 닫기." 에서, DrawerLayout의 Drawer를 열고 닫을 때, openDrawer()와 closeDrawer() 함수를 사용하는 방법에 대해 설명하였습니다. 그리고 openDrawer()와 closeDrawer() 함수의 파라미터로 gravity가 사용되는 것을 확인했었죠.


그런데 만약, Drawer가 존재하지 않는 방향에 대해, openDrawer() 함수를 사용하여 Drawer 열기를 시도하면 어떻게 될까요?

    <android.support.v4.widget.DrawerLayout ...>
        <TextView ...
            android:text="CONTENTS" />
        <TextView ...
            android:text="DRAWER 1"
            android:layout_gravity="left" />
    </android.support.v4.widget.DrawerLayout>
    DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer) ;
    drawer.openDrawer(Gravity.RIGHT) ;

그럼, 아래와 같은 에러가 발생합니다.

java.lang.IllegalArgumentException: No drawer view found with gravity RIGHT

6. 참고.

.END.


ANDROID 프로그래밍/LAYOUT , , , , , , , , , , ,

  1. Blog Icon
    개발자

    진짜 깔끔하고 명료하게 잘 설명하시네요!
    다른 보드도 봤는데 감탄을 금할길이 없네요.
    전문 기업체 강연나가도 손색없을것 같네요.

  2. 제겐 너무나 과분한 칭찬글을 남겨주셨네요.
    최대한 글을 쉽게 쓰려고 노력했지만, 부족함을 많이 느낍니다.
    방문해 주시고, 격려의 댓글까지 남겨주셔서 감사합니다.

  3. Blog Icon

    비밀댓글입니다

  4. 죄송합니다.
    저의 티스토리 블로그 활동이 부족해서인지, 아직 초대장을 한번도 받아본 적이 없네요.
    저도 초대장 나눔같은 거 한번 해보고 싶은데, 저한텐 주질 않습니다. ㅠㅠ
    다른 분께 요청 드려보세요.
    초대장 잘 받으셔서 블로그 꼭 만드시길 바랍니다.

    감사합니다.

  5. 안녕하세요 혹시 오류 좀 봐주실 수 있을까요 ..?ㅠㅠ 일주일동안 헤맸는데 결국 못찾겠더라구요..ㅠㅠ
    로그캣을 보면 밑에있는 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" >

    <LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:background="#ffffff"
    tools:context=".MainActivity" >

    <LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal" >
    <Button
    android:id="@+id/opendrawer"
    android:layout_width="50dp"
    android:layout_height="50dp"
    />

    <Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/test"
    android:background="#00ffffff"
    />

    <Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/spll"
    android:background="#0036db89"
    />

    </LinearLayout>

    <android.support.v4.view.ViewPager
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/viewpager">
    </android.support.v4.view.ViewPager>

    </LinearLayout>
    <include
    layout="@layout/activity_drawer" />
    </android.support.v4.widget.DrawerLayout>

  6. 아래 내용만으로는 어떤 부분이 에러인지 알기 쉽지 않네요.

    에러 메시지를 같이 올려주시면 문제 해결 방법을 찾기가 더 용이할 것 같습니다.

    번거롭더라도 표시되는 에러 메시지를 같이 올려주세요.

    감사합니다.

  7. 죄송합니다 이미 해결했어요~~ 답글 달아주셔서 감사합니다! 정보 잘 보고있어요!

  8. 제가 답글을 너무 늦게 달아드렸네요.
    그래도 해결하셨다니 다행입니다.
    또 다시 도움드릴 일 있으면 언제든 질문글 남겨주세요.

    감사합니다.

  9. Blog Icon
    strongslave

    개발하면서 올해 본 레퍼런스 중 제일 깔끔명료하네여
    원래 댓글 안달고 내용만 슥 보고 빠지지만
    넘나 깔끔하게 한번에 읽혀서 부랄을 탁 치며 댓글 답니다. 감사합니다

  10. 그곳을 넘 세게 '탁'치지 마세요. ㅜㅜ
    아픕니다.
    과분한 칭찬에 몸둘바를 모르겠네요.
    격려글 남겨주셔서 감사합니다.

  11. Blog Icon
    암이 나았습니다

    정말 감사합니다 제 구세주입니다. 블로그 정독하겠습니다 . 정말 어떻게 이런 지식을 무료로 설명해주시다니... 정말 감사합니다 정말 감사합니다 !!

  12. 축하드립니다!!!
    저를 포함하여, 모든 개발자들이 암에 걸리지않도록 더욱 더 열심히! 좋은 글을 쓰겠습니다.
    감사합니다.

  13. 공식이랑 같이 보면서 해보니 이해가 잘되네요. 감사합니다 ^^

  14. 나름 열심히, 꼼꼼하게 정리했는데..
    도움이 되신 것 같아서 다행이네요.
    방문해 주셔서 감사합니다.

  15. Blog Icon
    너무 좋아

    정말 많은 도움이 되고 있습니다.
    감사합니다.

  16. 도움이 될 수 있어서 다행입니다.
    그리고 방문해 주셔서 감사합니다.

  17. Blog Icon
    오류해결

    버전이 업데이트 됨에 따라 최신버전 androidx를 사용하는 경우는
    androidx.drawerlayout.widget.DrawerLayout로 바꿔야합니다

  18. Support Library 관련 내용과 변경들에 대해서도 정리를 해야하는데, 늘 핑계만 대면서 미루고 있네요. ㅜㅜ

    언젠가는 깔끔하게 정리할 수 있는 날이 오겠지요? ;;;

    도움글 남겨주셔서 감사합니다.

  19. Blog Icon
    dunkey2615@naver.com

    안녕하십니까! 현업 1년차 개발자입니다. 다음 글 잘 보고 참고해서 잘 만들었습니다만 한가지 문제가 있어서 해결을 못해서 질문좀 드리겠습니다.

    drawerlayout 안에 현재 include 탭으로 nestedscrollview / scorllview 를 써서 구현하려고 하는데 scroll이 안먹고 click이벤트는 먹어서요. 혹시 이와 관련되서 자문좀 구할 수 있을까요~?
    구글링 해봐도 명확한 답이 안나와서요ㅠㅠ 답변좀 부탁드립니다.

  20. 일단 현재 작업하신 내용에 대한 정보가 너무 없네요.

    질문의 내용만으로는 도움을 드리기 어려울 것 같습니다. 조금 더 구체적인 구현 과정이나 코드를 올려주시면 좋을 것 같고요.

    현재 작업 중인 코드에서 원인 분석과 해결이 잘 이루어지지 않는다면, 테스트 앱을 따로 만들어 시험해보시는 것도 좋을 것 같습니다.

    잘 안될 때는 차근차근.. 하나씩..

    감사합니다.

  21. Blog Icon
    helpme1212

    안녕하세요. 이번 졸업작품으로 맨땅에 헤딩중인 졸업반 학생입니다.
    항상 구글링 할때 늘 뽀따님 블로그를 찾아오는거 같아서 감사합니다 .. 올려주신 설명 덕에 늦게나마 열공중입니다. 다름이 아니고 제가 SwipeRefresh기능과 함께 드로어 레이아웃을 같이 사용해야하는데, 스와이프를 썼더니 툴바 클릭이 안되는데 혹시 이 문제에 대한 해결방법을 알고 계신지 여쭙고 싶어 댓글을 남깁니다.

    <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:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:id="@+id/drawer_layout"
    android:fitsSystemWindows="true"
    tools:openDrawer="start">


    <RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="#B7DBF4">
    <androidx.appcompat.widget.Toolbar
    android:id="@+id/toolbar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="?attr/colorPrimary"
    android:minHeight="?attr/actionBarSize"
    android:layout_gravity="left"
    android:theme="?attr/actionBarTheme"
    app:navigationIcon="@drawable/icon_menu" />
    </RelativeLayout>
    <com.google.android.material.navigation.NavigationView
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:id="@+id/nav_view"
    app:headerLayout="@layout/header"
    app:menu="@menu/main_menu"
    android:layout_gravity="start" >
    </com.google.android.material.navigation.NavigationView>

    <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
    android:id="@+id/swipeFresh"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">

  22. 질문하신 내용에 대해서는 저도 아는 내용이 없습니다.

    올려주신 코드를 봐도 정확한 원인을 파악하기는 힘드네요.

    이런 경우는 직접 코드를 돌려보면서 확인하는 수 밖에 없겠는데요.

    1. 레이아웃 배치가 의도한대로 정확히 이루어졌는가.
    2. 뷰들의 z-order가 제대로 작성되었는가.
    3. 클릭 등의 이벤트가 각 뷰에 잘 전달되는가.

    등을 먼저 확인해보시면 좋을 것 같습니다.

    그리고 레이아웃(특히 Parent)에 사용할 수 있는 이벤트 전달 관련 옵션들도 살펴보시면 좋을 것 같습니다.

    직접적인 도움을 드리지 못해 죄송합니다.

    감사합니다.

  23. Blog Icon
    ㅇㅇ

    설명 굿. 아 책을 몇권 샀는데 진짜 설명이 너무 없어서 아,.. 책보다 좋 습니다.

  24. 칭찬글 남겨주셔서 감사합니다.