박상권의 삽질블로그

[안드로이드/Android]CoordinatorLayout Behavior를 이용해 FooterView 숨기기/보여주기 본문

IT/Android-TIP (한글)

[안드로이드/Android]CoordinatorLayout Behavior를 이용해 FooterView 숨기기/보여주기

박상권 2015. 11. 25. 20:33

안드로이드 개발자들이 모여있는 오픈채팅방에 참여해보세요 .
Q&A 및 팁을 공유하는 방입니다..
오픈채팅방 참여



블로그를 Medium으로 옮겨서 운영하고 있습니다.
앞으로 새로운 글은 모두 미디엄 블로그를 통해서 올릴 예정입니다.
미디엄에서 다양하고 유익한 포스팅을 살펴보세요
미디엄 블로그 보기







아래 화면처럼 ScrollView나 RecyclerView가 스크롤시 아래에 있는 배너나 기타 Footer버튼을  없애주고 보여주는 기능을 보여주고 싶은때가 있습니다.







보통 Quick return Header/Footer로 검색하시면 많은 참고자료및 라이브러리를 찾아볼 수 있습니다.

Android Support Design Library 이전에는 대부분 라이브러리들이 RecyclerView/ScrollView에 스크롤리스너를 달아서 그 안에 함수를 구현해주고 스크롤되고있는 item위치에 따라서 ShowView()/HideView()의 방식으로 구현되어 있습니다.


이제는 각각 View에 ScrollLister를 달지말고 Behavior를 사용하면 됩니다


Support Design Library의 등장으로 behavior개념이 생기면서 간단하게 Behavior클래스를 만들어주고 이를 재사용하면 여러군데에서 사용할 수 있게됩니다.

정확히는 CoordinatorLayout의 Behavior 를 활용합니다.








Custom Behavior만들기


1. Class만들기


CoordinatorLayout.Behavior<View> 를 상속받은 CustomBehavior클래스를 만들어 줍니다.



public class QuickReturnFooterBehavior extends CoordinatorLayout.Behavior<View> {









2. 스크롤에 반응하기


가로방향의 스크롤일경우에만 Footer View를 숨기거나 보여줄것이기 때문에 nestedScrollAxes값이 Vertical(세로)방향일 경우에만 true를 리턴해줍니다.


@Override
public boolean onStartNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull View child, @NonNull View directTargetChild, @NonNull View target, int axes, int type) {
return axes == ViewCompat.SCROLL_AXIS_VERTICAL;
}







3. Footer View hide/show


스크롤 y값의 변화와 현재 Footer View의 상태에 따라서 Footer View를 숨기거나 보여주는 판단을 해줍니다.

onNestedPreScroll안의 hide/show 판단은 기존에 ScrollView/RecyclerView에 ScrollLister를 달아준뒤 그 안에서 하던 작업과 비슷한 일을 하게됩니다.

1. 위/아래방향으로 일정한 방향으로 향하던 도중에 방향이 바뀌는경우(원래 진행하던 방향과 현재 진행방향이 반대) 모든 작업을 초기화하고 다시 시작합니다.

2. 스크롤방향이 위/아래 방향으로 가는경우 숨기거나 보여주는 작업을 수행합니다.


@Override
public void onNestedPreScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull View child, @NonNull View target, int dx, int dy, @NonNull int[] consumed, int type) {
// 스크롤이 반대방향으로 전환
if (dy > 0 && dyDirectionSum < 0
|| dy < 0 && dyDirectionSum > 0) {
child.animate().cancel();
dyDirectionSum = 0;
}

dyDirectionSum += dy;

if (dyDirectionSum > child.getHeight()) {
hideView(child);
} else if (dyDirectionSum < -child.getHeight()) {
showView(child);
}
}







4. hideView/ShowView 구현


위에서 사용한 hideView와 showView 함수를 구현해줍니다.

이 함수 또한 기존에 사용하던 ScrollLister를 달고 hide/show 하던 함수와 같은 방식으로 만들어주시면 됩니다.

여기서는 hideView 애니메이션이 끝난뒤에 INVISIBLE을 해줍니다.(GONE처리하는경우 Behavior 이벤트를 받지 못하게 됩니다.)

showView 애니메이션이 시작하기전에 VISIBLE을 해주었지만 취향에 맞게 변경하셔도 됩니다.

또한 애니메이션 시간도 원하는대로 변경하고 여기서는 FastOutSlowInInterpolator InterPolator를 사용하였지만 얼마든지 다른것으로 변경하셔도 좋습니다.

private void hideView(final View view) {
if (isHiding || view.getVisibility() != View.VISIBLE) {
return;
}

ViewPropertyAnimator animator = view.animate()
.translationY(view.getHeight())
.setInterpolator(INTERPOLATOR)
.setDuration(ANIMATION_DURATION);

animator.setListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
isHiding = true;
}

@Override
public void onAnimationEnd(Animator animator) {
isHiding = false;
view.setVisibility(View.INVISIBLE);
}

@Override
public void onAnimationCancel(Animator animator) {
// 취소되면 다시 보여줌
isHiding = false;
showView(view);
}

@Override
public void onAnimationRepeat(Animator animator) {
// no-op
}
});

animator.start();
}

private void showView(final View view) {
if (isShowing || view.getVisibility() == View.VISIBLE) {
return;
}
ViewPropertyAnimator animator = view.animate()
.translationY(0)
.setInterpolator(INTERPOLATOR)
.setDuration(ANIMATION_DURATION);

animator.setListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
isShowing = true;
view.setVisibility(View.VISIBLE);
}

@Override
public void onAnimationEnd(Animator animator) {
isShowing = false;
}

@Override
public void onAnimationCancel(Animator animator) {
// 취소되면 다시 숨김
isShowing = false;
hideView(view);
}

@Override
public void onAnimationRepeat(Animator animator) {
// no-op
}
});

animator.start();
}








전체 소스코드




Behavior를 잘 이용해서 Footer뿐만 아니라 Header도 숨기기/보여주기로도 응용가능합니다.

또한 Google의 여러 앱에서 보여지는 hide/show 방식도 얼마든지 원하는대로 만들 수 있습니다.

좀더 많은 팁이나 정보는 아래 링크들을 참고해보셔도 좋습니다.

감사합니다.







유용한 링크


CoordinatorLayout 을 위한 Custom Behavior 구현

Mastering the Coordinator Layout

Design Support Library: Coordinator layout and Behavior

Quick return with CoordinatorLayout

Comments