如何在无需滚动时禁用AppBarLayout的滚动效果
解决AppBarLayout在ViewPager内容不足时的滚动问题
我之前也碰到过一模一样的问题——明明ViewPager里的内容都没填满屏幕,轻轻滑动一下AppBarLayout居然还会跟着滚,太影响体验了。核心问题就是咱们给Toolbar设置的scroll|enterAlways|snap滚动标记,会让AppBarLayout响应任何触摸滚动事件,不管内容够不够长。下面给你两种实用的解决思路:
方案一:动态切换Toolbar的滚动标记
这个方法的思路很直接:当ViewPager切换到某个页面时,判断该页面的内容是否能滚动,再决定要不要让Toolbar保留滚动相关的标记。
步骤1:定义判断滚动能力的接口
先给所有Fragment统一一个判断是否可滚动的接口,方便后续调用:
public interface ScrollableFragment { // 返回当前页面内容是否支持滚动 boolean isScrollable(); }
步骤2:在Fragment中实现接口
根据你Fragment里的内容类型(比如RecyclerView、ScrollView),实现这个方法:
- 如果是RecyclerView:
@Override public boolean isScrollable() { RecyclerView recyclerView = getView().findViewById(R.id.your_recycler_view); LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager(); // 当列表总项数大于可见的最后一项位置时,说明内容可以滚动 return layoutManager.getItemCount() > layoutManager.findLastVisibleItemPosition(); }
- 如果是ScrollView:
@Override public boolean isScrollable() { ScrollView scrollView = getView().findViewById(R.id.your_scroll_view); // 当子View高度大于ScrollView本身高度时,说明内容可以滚动 return scrollView.getChildAt(0).getHeight() > scrollView.getHeight(); }
步骤3:监听ViewPager页面切换,动态修改Toolbar的scrollFlags
在你的Activity里,给ViewPager添加页面切换监听器,根据当前页面的滚动能力调整Toolbar的参数:
home_view_pager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {} @Override public void onPageSelected(int position) { // 获取当前显示的Fragment Fragment currentFragment = getSupportFragmentManager() .findFragmentByTag("android:switcher:" + R.id.home_view_pager + ":" + position); if (currentFragment instanceof ScrollableFragment) { boolean canScroll = ((ScrollableFragment) currentFragment).isScrollable(); AppBarLayout.LayoutParams toolbarParams = (AppBarLayout.LayoutParams) home_toolbar.getLayoutParams(); if (canScroll) { // 恢复滚动标记 toolbarParams.setScrollFlags(AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL | AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS | AppBarLayout.LayoutParams.SCROLL_FLAG_SNAP); } else { // 移除滚动相关标记,只保留enterAlways(或者设为0完全禁用滚动) toolbarParams.setScrollFlags(AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS); } home_toolbar.setLayoutParams(toolbarParams); } } @Override public void onPageScrollStateChanged(int state) {} });
方案二:自定义AppBarLayout的Behavior拦截滚动事件
如果不想频繁修改布局参数,可以自定义一个Behavior,让AppBarLayout只有在当前页面内容可滚动时才响应滚动事件。
步骤1:实现自定义Behavior
public class CustomAppBarBehavior extends AppBarLayout.Behavior { public CustomAppBarBehavior() { super(); } public CustomAppBarBehavior(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean onStartNestedScroll(CoordinatorLayout parent, AppBarLayout child, View directTargetChild, View target, int nestedScrollAxes, int type) { // 当触发滚动的目标是ViewPager时,判断当前页面是否可滚动 if (target instanceof ViewPager) { ViewPager viewPager = (ViewPager) target; FragmentActivity activity = (FragmentActivity) parent.getContext(); Fragment currentFragment = activity.getSupportFragmentManager() .findFragmentByTag("android:switcher:" + viewPager.getId() + ":" + viewPager.getCurrentItem()); if (currentFragment instanceof ScrollableFragment) { // 只有当前页面可滚动时,才允许AppBarLayout响应滚动 return ((ScrollableFragment) currentFragment).isScrollable() && super.onStartNestedScroll(parent, child, directTargetChild, target, nestedScrollAxes, type); } else { return false; } } return super.onStartNestedScroll(parent, child, directTargetChild, target, nestedScrollAxes, type); } }
步骤2:在布局中应用自定义Behavior
修改你的AppBarLayout标签,添加自定义Behavior:
<android.support.design.widget.AppBarLayout android:layout_width="match_parent" android:layout_height="wrap_content" app:layout_behavior="com.yourpackage.name.CustomAppBarBehavior"> <android.support.v7.widget.Toolbar android:id="@+id/home_toolbar" android:layout_width="match_parent" android:layout_height="wrap_content" app:layout_scrollFlags="scroll|enterAlways|snap" app:titleTextColor="@color/colorWhite" /> <android.support.design.widget.TabLayout android:id="@+id/home_tab_layout" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/colorPrimary" app:tabIndicatorColor="@color/colorWhite" app:tabIndicatorHeight="@dimen/tabIndicatorHeight" app:tabMinWidth="@dimen/tabMinWidth" app:tabMode="scrollable" app:tabSelectedTextColor="@color/colorWhite" app:tabTextColor="@color/colorWhite80" /> </android.support.design.widget.AppBarLayout>
两种方案对比
- 方案一实现简单,适合页面切换不频繁的场景,不需要额外的自定义类;
- 方案二更灵活,逻辑封装在Behavior里,Activity代码更简洁,适合复杂的页面场景。
内容的提问来源于stack exchange,提问作者Avijit Karmakar
相关产品推荐
相关产品推荐

