返回

如何解决 AppBarLayout 吞没 Fling 的问题?

Android

AppBarLayout 是一个布局组件,可以为您的应用程序添加一个可滚动的应用程序栏。它可以包含标题、导航栏和其他元素。AppBarLayout 的一个常见问题是,它会吞没 Fling 手势,从而导致其他控件无法响应 Fling 手势。

这个问题通常发生在 AppBarLayout 与 RecyclerView 或 NestedScrollView 等其他可滚动控件一起使用时。当用户尝试在 RecyclerView 或 NestedScrollView 中滚动时,AppBarLayout 会拦截 Fling 手势并将其消化掉。这会导致 RecyclerView 或 NestedScrollView 无法滚动。

解决此问题的其中一种方法是使用自定义 Behavior。Behavior 是一个类,它可以定义如何协调布局中的多个控件。通过创建自定义 Behavior,您可以控制 AppBarLayout 如何响应 Fling 手势。

要创建自定义 Behavior,您需要创建一个类并将其扩展自 CoordinatorLayout.Behavior 类。T 是您要控制的控件的类型。

public class MyBehavior extends CoordinatorLayout.Behavior<AppBarLayout> {

    // ...

}

在 MyBehavior 类中,您需要重写 onInterceptTouchEvent() 方法。此方法在用户触摸屏幕时被调用。您可以使用此方法来拦截 Fling 手势并将其传递给其他控件。

@Override
public boolean onInterceptTouchEvent(CoordinatorLayout parent, AppBarLayout child, MotionEvent ev) {
    if (ev.getAction() == MotionEvent.ACTION_DOWN) {
        // ...
    } else if (ev.getAction() == MotionEvent.ACTION_MOVE) {
        // ...
    } else if (ev.getAction() == MotionEvent.ACTION_UP) {
        // ...
    }

    return super.onInterceptTouchEvent(parent, child, ev);
}

在 onInterceptTouchEvent() 方法中,您可以使用 MotionEvent 对象来获取用户触摸屏幕的位置和速度。您可以使用此信息来确定是否要拦截 Fling 手势。

如果要拦截 Fling 手势,您可以使用 CoordinatorLayout.dispatchNestedFling() 方法将 Fling 手势传递给其他控件。

parent.dispatchNestedFling(velocityX, velocityY, consumed);

使用自定义 Behavior 可以解决 AppBarLayout 吞没 Fling 手势的问题。这种方法简单易用,而且可以与任何使用 CoordinatorLayout 的控件一起使用。

除了使用自定义 Behavior 之外,您还可以使用以下方法来解决此问题:

  • 将 AppBarLayout 的 elevation 属性设置为 0。这将导致 AppBarLayout 不再投射阴影,从而不会再吞没 Fling 手势。
  • 将 AppBarLayout 的 clipChildren 属性设置为 false。这将导致 AppBarLayout 不再裁剪其子控件,从而使其他控件可以响应 Fling 手势。
  • 将 AppBarLayout 的 clipToPadding 属性设置为 false。这将导致 AppBarLayout 不再裁剪其填充区域,从而使其他控件可以响应 Fling 手势。

这些方法都可以解决 AppBarLayout 吞没 Fling 手势的问题,但是使用自定义 Behavior 是最简单和最通用的方法。