티스토리 뷰
우선 위의 링크 2개를 반드시 읽어보고 아래 내용을 읽기를 추천한다. 굉장히 정리가 잘 되어 있다.
위의 블로그의 내용을 좀 더 쉽게 정리를 해보겠다.
먼저, 네비게이션 드로어가 무엇인지는 위의 2개의 블로그에서 상세히 설명했으므로 여기서는 생략한다.
DrawerLayout이라는것은 폰 상단에 돼지바를 클릭했을때 옆에서 메뉴가 튀어나오는 안드로이드 머티리얼 디자인중 하나이다.
거의 요즘 이 기능을 사용하지 않는 앱이 없을 정도로 자주 사용 되기때문에 꼭 알아둬야 한다.
DrawerLayout을 적용하는 방법에는 2가지가 있다.
1. 핸드폰 왼쪽 -> 오른쪽 또는 오른쪽 -> 왼쪽으로 밀었을때 나오게 하는 방법.
2. 휴대폰 상단 액션바에있는 돼지바(3개의 줄로 되어 있는 아이콘)를 클릭했을때 메뉴가 서랍장을 여는 것처럼 나오게 하는 방법.
2가지가 있는데, 보통 첫번째 방식보다는 두번째 방식이 직관적이기 때문에 두번째 방식이 거의 대부분이라고 할 수 있다.
우선 첫번째 방법을 구현하는 방법을 알아보자.
간단하다.
1.메인 화면을 표시할 뷰
2. 드로어(서랍장)을 표시할 뷰
2가지 준비물이 필요하다.
나의 경우에는 메인 화면에 대한 스켈레톤 코드는 다음과 같다.
<CoordinatorLayout>
<AppBarLayout>
<Toolbar>
</Toolbar>
</AppBarLayout>
<include/> -> 메인 화면의 컨텐츠를 따로 분리하여 xml파일로 작성 하였다.
<FloatingActionButton/>
</CoordinatorLayout>
보면 별거 없다. 그냥 전체를 CoordinatorLayout으로 감싼 이유는 플로팅 액션 버튼과 툴바가 서로 상호작용 하게 만들기 위해서 이고, AppBarLayout로 Toolbar를 감싸놓은 이유는 이렇게 해야 include된 메인 화면 컨텐츠 부분에서 스크롤이 일어났을때 툴바에 어떤 애니메이션 효과를 줄 수 있기 때문이다. AppBarLayout으로 감싸고 난 뒤 메인 컨텐츠를 스크롤 했을때 툴바에 나타나는 효과와 CollapsingToolbarLayout로 툴바를 감싸고 스크롤 할때 적용되는 효과가 다르다. 무엇으로 감싸느냐에 따라 적용되는 애니메이션이 달라질수있는것이다.
뭐 예를 들어, 메인 컨텐츠 부분이 스크롤 될때 플로팅 액션 버튼을 사라지게 만들었다가 스크롤을 멈추면 다시 나타나게 한다던가, 아니면 메인 컨텐츠를 스크롤 할때 툴바 부분이 사라진다거나, 하게끔 만들기 위해서 위와 같이 만들었다고 할 수 있다.
즉 CoordinatorLayout의 하위 자식들간 어떤 상호 작용을 위해서 위와 같이 구성한것이다.
그리고 주의 할점은 include 태그를 통해서 xml파일을 include시켰을때 그 include된 xml 파일의 최상단 루트 뷰또는 뷰 그룹에 설정을 <app:layout_behavior="@string/appbar_scrolling_view_behavior"> 이런식으로 추가 해 줘야 제대로 동작한다.
메인 화면은 위와 같이 구성했고 이제 드로어에 해당하는 뷰를 만들고 최종적으로 위의 메인화면과 뷰를 DrawerLayout으로 감싸주기만 하면 첫번째 구현 방법은 완료가 되는 것이다. 드로어에 해당하는 뷰는 그냥 단순히 텍스트뷰로 구성하였다.
즉 최종적인 네비게이션 드로어가 추가된 메인 화면의 스켈레톤 코드는 다음과 같다.
<DrawerLayout>
<CoordinatorLayout>
<AppBarLayout>
<Toolbar>
</Toolbar>
</AppBarLayout>
<include/> -> 메인 화면의 컨텐츠를 따로 분리하여 xml파일로 작성 하였다.
<FloatingActionButton/>
</CoordinatorLayout>
<LinearLayout>
<TextView/>
</LinearLayout>
파란색으로 칠한 부분이 메인 화면에 대한것이고 보라색으로 칠한 부분이 드로어에 해당하는 뷰이다. 이것을 DrawerLayout으로 감싸주면 네비게이션 드로어의 간단한 버전을 구현 할 수 있다. 근데, 여기서 중요한점이 드로어로 사용할 뷰는 항상 맨 마지막에 넣어야 한다는것이다. 그래서 보라색 부분을 맨 마지막에 배치시켰다. 이렇게 해야 xml이 화면에 로딩될때 드로어 부분이 최상단에 깔리기 때문에 모든 이벤트를 드로어가 받을 수 있다. 위의 링크의 블로그에 잘 설명되있으니 참고하자.
우선 이렇게 했을 경우 아래와 같이 폰 화면을 오른쪽에서 왼쪽으로 밀었을때 드로어가 나오는것을 볼 수 있다. 지금 현재는 드로어를 그냥 단순히 텍스트뷰로 구성했기 때문에 위와 같이 나오는것이지만, 보통은 리싸이클러뷰 또는 리스트뷰 등으로 구성한다.
잘 안보이지만 this is drawer라는 텍스트뷰가 보이는것을 확인 할 수 있다. 이로써 1번째 방법으로 구현이 완료 되었다. 간단하다. 이제는 자주 사용되는 방법인 2번째 방법으로 고쳐보자.
우선 두번째 방법을 사용하기 위해서는 Support.v7의 ActionBarDrawerToggle 객체를 생성하여 DrawerLayout에 달아줘야 한다. 이 객체는 DrawerLayout.DrawerListener 인터페이스를 구현한 객체 이기 때문에 DrawerLayout에서 일어난 이벤트를 모두 처리 할 수 있는 객체이다.
즉, mActionBarDrawerToggle = new ActionBarDrawerToggle(, , , , ){};
뭐 이런식으로 객체를 생성하여
mDrawerLayout.setDrawerLayoutListener(mActionBarDrawerToggle); 이렇게 등록 해주면 액션바 드로어 토글이 드로어 레이아웃의 리스너 역할을 할 수 있다는 것이다.
물론 액션바드로어토글의 오버라이드 메소드를 재정의 해주어야 하는 것은 기본이다.또한 리스너를 달아줌으로써 그 햄버거바를 눌렀을때 드로어가 나타나게끔 할 수 있다.
toggleButton = new AppCompatImageButton(toolbar.getContext(), null, R.attr.toolbarNavigationButtonStyle);
toolbar.addView(toggleButton, new LayoutParams(GravityCompat.Start));
이런 코드가 생성자 내부에 구현 되어 있다.
햄버거바와 드로어가 열렸을때 그 햄버거바가 화살표로 바뀌게 만드는것은 액션바 드로어 토글내의 생성자에서 처리를 해주는것이다.
다음은 햄버거바를 오른쪽에서 왼쪽으로 열리게하는 액션바드로어토글 클래스의 생성자 예시이다.
public EndDrawerToggle(Activity activity, DrawerLayout drawerLayout, Toolbar toolbar,
int openDrawerContentDescRes, int closeDrawerContentDescRes) {
this.drawerLayout = drawerLayout;
this.openDrawerContentDesc = activity.getString(openDrawerContentDescRes);
this.closeDrawerContentDesc = activity.getString(closeDrawerContentDescRes);
arrowDrawable = new DrawerArrowDrawable(toolbar.getContext()); // 햄버거바 or 화살표 왔다갔다하게 하는 클래스
arrowDrawable.setDirection(DrawerArrowDrawable.ARROW_DIRECTION_END); // 화살표의 방향을 지정한다.(왼쪽방향)
toggleButton = new AppCompatImageButton(toolbar.getContext(), null,
R.attr.toolbarNavigationButtonStyle);//이전버전과 호환을 위해서 새롭게 생긴 이미지 버튼이다.
toolbar.addView(toggleButton, new LayoutParams(GravityCompat.END));//기본 액션바드로어토글에는 GravityCompat.Start로 되어있어서 왼쪽에 나타나는 것이다.
toggleButton.setImageDrawable(arrowDrawable);//이미지 버튼에 햄버거바 이미지를 붙임. 이미지버튼은 툴바에 붙어있음.
toggleButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
toggle(); //드로어가 열려있으면 닫고 닫혀있으면 여는 리스너
}
}
);
}
------------------------------------------------------------------------------------------
이쯤에서 나의 삽질 해결 과정을 한번 살펴보고 오자. -> 링크
------------------------------------------------------------------------------------------
cf) 위의 이미지에서 돼지바가 있는것은 그냥 이미지버튼의 백그라운드로 넣은것이다. 네비게이션 드로어를 구현한 상태가 아니다.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
Toolbar toolbar = (Toolbar)findViewById(R.id.toolbar);
mDrawerLayout= (DrawerLayout)findViewById(R.id.home_drawer);
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM); //액션바를 커스터마이징 하기 위해
actionBar.setCustomView(R.layout.toolbar_home);
actionBar.setElevation(0); //z축 깊이 0으로 설정 하여 그림자 없애기.
mDrawerToggle = new ActionBarDrawerToggle(this,mDrawerLayout,toolbar,R.string.open_drawer,R.string.close_drawer){
@Override //드로어가 열렸을때
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
}
@Override //드로어가 닫혔을때
public void onDrawerClosed(View drawerView) {
super.onDrawerClosed(drawerView);
}
};//액션바 드로우 토글 구현 -> 액션바에 있는 돼지바 클릭시 네비게이션 드로어 나타남.
mDrawerLayout.addDrawerListener(mDrawerToggle);mDrawerLayout.addDrawerListener(mDrawerToggle);
actionBar.setDisplayHomeAsUpEnabled(true); //홈버튼을 업버튼으로 설정 -> 뒤로가기 버튼
actionBar.setHomeAsUpIndicator(R.drawable.menu); //뒤로가기 버튼의 이미지를 R.drawable.menu로 설정
이중에서 이부분을 집중해서 살펴보자.
mDrawerToggle = new ActionBarDrawerToggle(this,mDrawerLayout,toolbar,R.string.open_drawer,R.string.close_drawer){
@Override //드로어가 열렸을때
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
}
@Override //드로어가 닫혔을때
public void onDrawerClosed(View drawerView) {
super.onDrawerClosed(drawerView);
}
};//액션바 드로우 토글 구현 -> 액션바에 있는 돼지바 클릭시 네비게이션 드로어 나타남.
생성자의 첫번째 매개변수로 this를 전달하고 있다. 이것은, 현재 메인 액티비티에서 드로어 토글이 동작하게끔 하겠다는것이고, mDrawerLayout과 toolbar를 전달함으로써 툴바에 돼지바를 붙이고 돼지바를 눌렀을때 DrawerLayout에 있는 드로어 뷰(위에서 리니어레이아웃에 해당)를 튀어 나오게끔 설정하게 하기 위해서가 아닐까 라고 생각이 된다.(검색에 기반한 뇌피셜이니 걸러듣자)
위와 같이 설정해주면 아래와 같이 화면이 완성된다.
위와 같이 구현이 되었다.
저 위에 있는 돼지바 세줄은 단순한 이미지 버튼이 아니라 액션바드로어토글 구현에 의해 생성된 토글버튼이자 홈버튼이다.
저것을 클릭했을때 우측과 같이 드로어 뷰가 나오게 된다.
이제 나는 햄버거 바를 액션바의 오른쪽에 배치를 시키고 싶다. 하지만 액션바드로어토글 클래스는 항상 드로어를 왼쪽에서 오른쪽으로만 토글 가능하게끔 구현 되어 있기 때문에 DrawerLayout.DrawerListener 인터페이스를 구현한 커스텀 클래스를 구현해야 했다. 그 클래스의 이름은 EndDrawerToggle클래스이다.
이 클래스는 그냥 오른쪽에서 왼쪽으로 드로어를 버튼 클릭을 통해 표시할수있다는것빼고는 기존의 액션바 드로어 토글과 다를것이 없는 클래스이다. 그리하여 적용을 해보려고 했는데 자꾸 액션바에 햄버거바가 오른쪽에 표시 되지 않는 문제가 발생하였다. 여러번의 삽질 끝에
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
Toolbar toolbar = (Toolbar)findViewById(R.id.toolbar);
mDrawerLayout= (DrawerLayout)findViewById(R.id.home_drawer);
mDrawerToggle = new EndDrawerToggle(this,mDrawerLayout,toolbar,R.string.open_drawer,R.string.close_drawer){
@Override //드로어가 열렸을때
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
}
@Override //드로어가 닫혔을때
public void onDrawerClosed(View drawerView) {
super.onDrawerClosed(drawerView);
}
};//액션바 드로우 토글 구현 -> 액션바에 있는 돼지바 클릭시 네비게이션 드로어 나타남.
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM); //액션바를 커스터마이징 하기 위해
actionBar.setCustomView(R.layout.toolbar_home);
actionBar.setElevation(0); //z축 깊이 0으로 설정 하여 그림자 없애기.
mDrawerLayout.addDrawerListener(mDrawerToggle);
actionBar.setHomeAsUpIndicator(R.drawable.menu); //뒤로가기 버튼의 이미지를 R.drawable.menu로 설정
위와 같이 코드 배치에 문제가 있었다는것을 깨달았다. 처음에는 setSupportActionBar를 호출하기 전에 EndDrawerToggle을 생성자를 통해 인스턴스화 시켰었다. 여기서 문제가 발생한것인데, 저 클래스의 생성자 내부에서는 매개변수로 전달한 툴바에 햄버거바를 붙이는 작업을 행한다.
그렇기 때문에 툴바에 햄버거바 버튼이 붙여지기도 전에 툴바를 액션바로 셋팅했기 때문에 액션바에 햄버거바가 표시 되지 않았던 것이다. 그리하여 위의 배치 처럼 수정하게 되면 아래와 같은 화면과 같이 돼지바가 오른쪽에 붙게 된다.
'컴퓨터 공학과 졸업 > 안드 개발 기록' 카테고리의 다른 글
하단바 만들기 (0) | 2018.07.12 |
---|---|
프래그먼트 (0) | 2018.07.12 |
[퍼옴] RecyclerView (0) | 2018.07.03 |
DP단위 (0) | 2018.06.29 |
AsyncTask (0) | 2018.06.29 |
- Total
- Today
- Yesterday
- Next.js
- react hooks
- props
- reflow
- await
- state
- type alias
- Babel
- hydrate
- webpack
- reducer
- useRef
- async
- design system
- mobx
- es6
- server side rendering
- react
- typescript
- useEffect
- Action
- reactdom
- javascript
- storybook
- computed
- atomic design
- rendering scope
- promise
- Polyfill
- return type
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |