Android Toolbar + Tab Layout + Drawer, Hide toolbar when scrolling and take TabLayout to the top

后端 未结 10 938
遇见更好的自我
遇见更好的自我 2020-12-28 14:41

I have activity which has drawer attached to it. Each menu of the drawer is a fragment, and under one of the menu I have a fragment with TabLayout, and each tab

10条回答
  •  -上瘾入骨i
    2020-12-28 15:24

    First you need to implement a scroll listener. Here you can find an example HidingScrollListener.

    public abstract class HidingScrollListener extends RecyclerView.OnScrollListener {
    
        private static final float HIDE_THRESHOLD = 10;
        private static final float SHOW_THRESHOLD = 70;
    
        private int mToolbarOffset = 0;
        private boolean mControlsVisible = true;
        private int mToolbarHeight;
        private int mTotalScrolledDistance;
        private int previousTotal = 0;
        private boolean loading = true;
        private int visibleThreshold = 4;
        int firstVisibleItem, visibleItemCount, totalItemCount;
        private LinearLayoutManager layoutManager;
    
        public HidingScrollListener(Context context, LinearLayoutManager layoutManager) {
            mToolbarHeight = Tools.getToolbarHeight(context);
            this.layoutManager = layoutManager;
        }
    
        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            super.onScrollStateChanged(recyclerView, newState);
    
            if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                if (mTotalScrolledDistance < mToolbarHeight) {
                    setVisible();
                } else {
                    if (mControlsVisible) {
                        if (mToolbarOffset > HIDE_THRESHOLD) {
                            setInvisible();
                        } else {
                            setVisible();
                        }
                    } else {
                        if ((mToolbarHeight - mToolbarOffset) > SHOW_THRESHOLD) {
                            setVisible();
                        } else {
                            setInvisible();
                        }
                    }
                }
            }
    
        }
    
        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            super.onScrolled(recyclerView, dx, dy);
    
            clipToolbarOffset();
            onMoved(mToolbarOffset);
    
            if ((mToolbarOffset < mToolbarHeight && dy > 0) || (mToolbarOffset > 0 && dy < 0)) {
                mToolbarOffset += dy;
            }
            if (mTotalScrolledDistance < 0) {
                mTotalScrolledDistance = 0;
            } else {
                mTotalScrolledDistance += dy;
            }
            // for load more
            visibleItemCount = recyclerView.getChildCount();
            totalItemCount = layoutManager.getItemCount();
            firstVisibleItem = layoutManager.findFirstVisibleItemPosition();
    
            if (loading) {
                if (totalItemCount > previousTotal) {
                    loading = false;
                    previousTotal = totalItemCount;
                }
            }
            if (!loading && (totalItemCount - visibleItemCount) <= (firstVisibleItem + visibleThreshold)) {
                // End has been reached
                // Do something
    
                loading = true;
                onLoadMore();
            }
        }
    
        private void clipToolbarOffset() {
            if (mToolbarOffset > mToolbarHeight) {
                mToolbarOffset = mToolbarHeight;
            } else if (mToolbarOffset < 0) {
                mToolbarOffset = 0;
            }
        }
    
        private void setVisible() {
            if (mToolbarOffset > 0) {
                onShow();
                mToolbarOffset = 0;
            }
            mControlsVisible = true;
        }
    
        private void setInvisible() {
            if (mToolbarOffset < mToolbarHeight) {
                onHide();
                mToolbarOffset = mToolbarHeight;
            }
            mControlsVisible = false;
        }
    
        public abstract void onMoved(int distance);
    
        public abstract void onShow();
    
        public abstract void onHide();
    
        public abstract void onLoadMore();
    }
    

    Than you need to modify your RecyclerView adapter. You need to add an empty view to top of your RecyclerView as high as your your Tolbar.

    Here is an example layout for your empty view.

    
    
    

    Than you need to override your adapter's getItemViewType and getITemCount methods like below.

    @Override
        public int getItemViewType(int position) {
            if (isPositionHeader(position)) {
                return TYPE_HEADER;
            }
            return TYPE_ITEM;
        }
    
        private boolean isPositionHeader(int position) {
            return position == 0;
        }
    
        @Override
        public int getItemCount() {
            return mObjects.size() + 1;
        }
    

    Than in adapter's onCreateViewHolder method return a proper layout for your RecyclerView's position likew below:

     @Override
        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View view = null;
            switch (viewType) {
                case TYPE_HEADER:
                    view = LayoutInflater.from(mContext).inflate(R.layout.layout_recycler_header, parent, false);
                    return new RecyclerHeaderViewHolder(view);
    
                default:
                    view = LayoutInflater.from(mContext).inflate(R.layout.row_recyclerview_category, parent, false);
                    return new ViewHolder(view);
            }
    
        }
    

    And finally add your HidingScrollListener implementation to your RecyclerView like below:

    final int mToolbarHeight = Tools.getToolbarHeight(getActivity());
            RecyclerView mRecyclerView = (RecyclerView) view.findViewById(R.id.recyclerview);
            LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity());
            linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
            mRecyclerView.setLayoutManager(linearLayoutManager);
            mRecyclerView.setAdapter(mAdapter);
            mViewPager.setPadding(mRecyclerView.getPaddingLeft(),
                    mToolbarHeight,
                    mRecyclerView.getPaddingRight(),
                    mRecyclerView.getPaddingBottom());
    
            mHidingScrollListener = new HidingScrollListener(getActivity(), linearLayoutManager) {
                @Override
                public void onMoved(int distance) {
                  mToolbarContainer.setTranslationY(-distance);
                }
    
                @Override
                public void onShow() {
                    mToolbarContainer.animate().translationY(0).setInterpolator(new DecelerateInterpolator(2)).start();
                }
    
                @Override
                public void onHide() {
                   mToolbarContainer.animate()
                            .translationY(-mToolbarHeight)
                            .setInterpolator(new AccelerateInterpolator(2))
                            .start();
                }
    
                @Override
                public void onLoadMore() {
                }
            };
            mRecyclerView.setOnScrollListener(mHidingScrollListener);
    

    I hope i understand your problem correctly, and my implementation can help you.

    Good luck.

    Edit: You can implement LoadMore and PullToRefresh implementation easily to this solution. You can add your api request to loadMore. There's a tricy part in PullToRefresh. After you pull to refresh, clean your data and notify adapter do not to forget set visibleItemCount and totalItemCount to 0 in your hiding scroll implementation. If you do not set to 0, after you refreshed your load more will not work properly. You'll get less data as your item count in your pagination.

提交回复
热议问题