Toolbar in AppBarLayout is scrollable although RecyclerView has not enough content to scroll

前端 未结 9 725
挽巷
挽巷 2020-12-12 15:34

Is it really intended that the Toolbar in a AppBarLayout is scrollable although the main container with the "appbar_scrolling_view_behavior" has not enough content

相关标签:
9条回答
  • 2020-12-12 16:17

    Something like this in a LayoutManager subclass seems to result in the desired behavior:

    @Override
    public boolean canScrollVertically() {
        int firstCompletelyVisibleItemPosition = findFirstCompletelyVisibleItemPosition();
        if (firstCompletelyVisibleItemPosition == RecyclerView.NO_POSITION) return false;
    
        int lastCompletelyVisibleItemPosition = findLastCompletelyVisibleItemPosition();
        if (lastCompletelyVisibleItemPosition == RecyclerView.NO_POSITION) return false;
    
        if (firstCompletelyVisibleItemPosition == 0 &&
                lastCompletelyVisibleItemPosition == getItemCount() - 1)
            return false;
    
        return super.canScrollVertically();
    }
    

    The documentation for canScrollVertically() says:

    /**
     * Query if vertical scrolling is currently supported. The default implementation
     * returns false.
     *
     * @return True if this LayoutManager can scroll the current contents vertically
     */
    

    Notice the wording of "can scroll the current contents vertically", which I believe implies that the current state should be reflected by the return value.

    However, that is not done by any of the LayoutManager subclasses provided through the v7 recyclerview library (23.1.1), which makes me somewhat hesitant whether it is a correct solution; it might cause undesired effects in other situations than the one discussed in this question.

    0 讨论(0)
  • 2020-12-12 16:18

    I would like to add a little to user3623735's answer. The following code is absolutely incorrect.

    // Find out if RecyclerView are scrollable, delay required
        final Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                if (rv.canScrollVertically(DOWN) || rv.canScrollVertically(UP)) {
                    controller.enableScroll();
                } else {
                    controller.disableScroll();
                }
            }
        }, 100);
    

    And even when it works - it doesn't cover all cases. There is absolutely no guarantee that a data will be displayed in 100 ms, and the data can stretch the height of the view in the process of working with it, not only in the onCreateView method. That's why you should use next code and track changes in view height:

    view.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
            @Override
            public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
                if(bottom != oldBottom)
                {
                    mActivity.setScrollEnabled(view.canScrollVertically(0) || view.canScrollVertically(1));
                }
            }
        });
    

    Moreover no need to create two separated method to control scrolling status, you should use one setScrollEnabled method:

    public void setScrollEnabled(boolean enabled) {
        final AppBarLayout.LayoutParams params = (AppBarLayout.LayoutParams)
                mToolbar.getLayoutParams();
    
        params.setScrollFlags(enabled ?
                AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL | AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS : 0);
    
        mToolbar.setLayoutParams(params);
    }
    
    0 讨论(0)
  • 2020-12-12 16:25

    It is not a bug, all the events in a viewGroup are handled this way. Because your recyclerview is a child of coordinatorLayout so whenever the event is generated, it is first checked for parent and if parent is not interested only then it is passed down to child. See google documentation

    0 讨论(0)
提交回复
热议问题