ScollView 스크롤시 바텀레이아웃 숨기기 (detect scroll end)

2020. 12. 23. 11:01모바일/Android_Java

step1

  • CustomScrollView 구현
public class EventCustomScrollView extends ScrollView {
    private Runnable scrollerTask;
    private int initialPosition;
    private int newCheck = 100;
    private OnScrollListener onScrollListener;

    public void setOnScrollListener(OnScrollListener onScrollListener) {
        this.onScrollListener = onScrollListener;
    }

    public EventCustomScrollView(Context context) {
        super(context);
        init();
    }

    public EventCustomScrollView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    public EventCustomScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public void init() {
        scrollerTask = new Runnable() {
            public void run() {
                int newPosition = getScrollY();
                if (initialPosition - newPosition == 0) {//has stopped
                    if (onScrollListener != null) {
                        onScrollListener.onScrollEnd();
                    }

                } else {
                    initialPosition = getScrollY();
                    EventCustomScrollView.this.postDelayed(scrollerTask, newCheck);
                }
            }
        };
    }

    public void startScrollerTask() {
        initialPosition = getScrollY();
        EventCustomScrollView.this.postDelayed(scrollerTask, newCheck);
    }

    @Override
    protected void onScrollChanged(int l, int t, int oldX, int oldY) {
        super.onScrollChanged(l, t, oldX, oldY);
        if(onScrollListener!=null){
            onScrollListener.onScrollChanged(l,t,oldX,oldY);
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_UP:
                startScrollerTask();
                break;
        }
        return super.onTouchEvent(ev);
    }

    public interface OnScrollListener {
        void onScrollChanged(int l, int t, int oldX, int oldY);

        void onScrollEnd();
    }
}

step2

  • listener 등록
        scrollView.setOnScrollListener(new EventCustomScrollView.OnScrollListener() {
            @Override
            public void onScrollChanged(int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
                Rect scrollBounds = new Rect();
                scrollView.getHitRect(scrollBounds);
                direction(scrollY - oldScrollY);
                if (scrollY < oldScrollY) {
                    //스크롤 다운
                    //화면이 위로 올라감
                } else {
                    //스크롤 업
                    //화면이 아래로 내려감
                }
            }
            @Override
            public void onScrollEnd() {
                visibleBottomLayout(View.VISIBLE);
            }
        });

step3

  • animator 구현
    private final static int GAP = 5;
    private int mDySinceDirectionChange;
    private boolean mIsShowing;
    private boolean mIsHiding;
    private final Interpolator INTERPOLATOR = new FastOutSlowInInterpolator();

    public void direction(int dy) {
        // 스크롤방향이 바뀌는경우 모든동작을 취소하고 Y값을 다시 처음부터 시작한다
        if (dy > 0 && mDySinceDirectionChange < 0
                || dy < 0 && mDySinceDirectionChange > 0) {

            lyBottom.animate().cancel();
            mDySinceDirectionChange = 0;
        }

        mDySinceDirectionChange += dy;
        if (mDySinceDirectionChange > GAP && lyBottom.getVisibility() == View.VISIBLE && !mIsHiding) {
            hideView(lyBottom);
        } else if (mDySinceDirectionChange < -GAP && lyBottom.getVisibility() == View.GONE && !mIsShowing) {
            showView(lyBottom);
        }
    }

    public void reset() {
        mDySinceDirectionChange = 0;
        showView(lyBottom);
    }

    /**
     * View를 숨긴다
     * <p/>
     * 아래로 슬라이딩하는 애니메이션.
     * 애니메이션 종료후 View를 없앤다.
     *
     * @param view The quick return view
     */
    private void hideView(final View view) {
        mIsHiding = true;
        ViewPropertyAnimator animator = view.animate()
                .translationY(view.getHeight())
                .setInterpolator(INTERPOLATOR)
                .setDuration(200);

        animator.setListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animator) {
            }

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

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

            @Override
            public void onAnimationRepeat(Animator animator) {
            }
        });

        animator.start();
    }

    /**
     * View를 보여준다.
     * <p/>
     * 아래서 위로 슬라이딩 애니메이션.
     * 애니메이션을 시작하기전 View를 보여준다.
     *
     * @param view The quick return view
     */
    private void showView(final View view) {
        mIsShowing = true;
        ViewPropertyAnimator animator = view.animate()
                .translationY(0)
                .setInterpolator(INTERPOLATOR)
                .setDuration(200);

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

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

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

            @Override
            public void onAnimationRepeat(Animator animator) {
            }
        });

        animator.start();
    }
    public void visibleBottomLayout(int visibility){
       lyBottom.setVisibility(visibility);
        if (visibility == View.VISIBLE) {
            reset();
        }
    }