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

前端 未结 9 740
挽巷
挽巷 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:13

    Edit 2:

    Turns out the only way to ensure Toolbar is not scrollable when RecyclerView is not scrollable is to set setScrollFlags programmatically which requires to check if RecyclerView's is scrollable. This check has to be done every time adapter is modified.

    Interface to communicate with the Activity:

    public interface LayoutController {
        void enableScroll();
        void disableScroll();
    }
    

    MainActivity:

    public class MainActivity extends AppCompatActivity implements 
        LayoutController {
    
        private CollapsingToolbarLayout collapsingToolbarLayout;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
            setSupportActionBar(toolbar);
    
            collapsingToolbarLayout = 
                  (CollapsingToolbarLayout) findViewById(R.id.collapsing_toolbar);
    
            final FragmentManager manager = getSupportFragmentManager();
            final Fragment fragment = new CheeseListFragment();
            manager.beginTransaction()
                    .replace(R.id.root_content, fragment)
                    .commit();
        }
    
        @Override
        public void enableScroll() {
            final AppBarLayout.LayoutParams params = (AppBarLayout.LayoutParams)
                                      collapsingToolbarLayout.getLayoutParams();
            params.setScrollFlags(
                    AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL 
                    | AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS
            );
            collapsingToolbarLayout.setLayoutParams(params);
        }
    
        @Override
        public void disableScroll() {
            final AppBarLayout.LayoutParams params = (AppBarLayout.LayoutParams)
                                      collapsingToolbarLayout.getLayoutParams();
            params.setScrollFlags(0);
            collapsingToolbarLayout.setLayoutParams(params);
        }
    }
    

    activity_main.xml:

    
    
        
    
            
    
                
    
                    
    
                
    
            
    
            
    
        
    
    
    

    Test Fragment:

    public class CheeseListFragment extends Fragment {
    
        private static final int DOWN = 1;
        private static final int UP = 0;
    
        private LayoutController controller;
        private RecyclerView rv;
    
        @Override
        public void onAttach(Context context) {
            super.onAttach(context);
    
            try {
                controller = (MainActivity) getActivity();
            } catch (ClassCastException e) {
                throw new RuntimeException(getActivity().getLocalClassName()
                        + "must implement controller.", e);
            }
        }
    
        @Nullable
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            rv = (RecyclerView) inflater.inflate(
                    R.layout.fragment_cheese_list, container, false);
            setupRecyclerView(rv);
    
            // 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);
    
            return rv;
        }
    
        private void setupRecyclerView(RecyclerView recyclerView) {
            final LinearLayoutManager layoutManager = new LinearLayoutManager(recyclerView.getContext());
    
            recyclerView.setLayoutManager(layoutManager);
    
            final SimpleStringRecyclerViewAdapter adapter =
                    new SimpleStringRecyclerViewAdapter(
                            getActivity(),
                            // Test ToolBar scroll
                            getRandomList(/* with enough items to scroll */)
                            // Test ToolBar pin
                            getRandomList(/* with only 3 items*/)
                    );
    
            recyclerView.setAdapter(adapter);
        }
    }
    

    Sources:

    • Change scroll flags programmatically
    • Original code by Chris Banes
    • Need a postDelayed to ensure RecyclerView children are ready for calculations

    Edit:

    You should CollapsingToolbarLayout to control the behaviour.

    Adding a Toolbar directly to an AppBarLayout gives you access to the enterAlwaysCollapsed and exitUntilCollapsed scroll flags, but not the detailed control on how different elements react to collapsing. [...] setup uses CollapsingToolbarLayout’s app:layout_collapseMode="pin" to ensure that the Toolbar itself remains pinned to the top of the screen while the view collapses.http://android-developers.blogspot.com.tr/2015/05/android-design-support-library.html

    
    
        
    
    
    

    Add

    app:layout_collapseMode="pin"
    

    to your Toolbar in xml.

        
    

提交回复
热议问题