如何在 CoordinatorLayout 中禁用 AppBarLayout 的滚动?
How to disable scrolling of AppBarLayout in CoordinatorLayout?
-
android
-
supportmapfragment
-
android-coordinatorlayout
-
android-collapsingtoolbarlayout
-
android-appbarlayout
我有 MapFragment
里面有视差效果 AppBarLayout
:
我想在 AppBarLayout
上禁用滚动,因为无法在地图上移动,因为地图上的触摸事件始终作为滚动事件处理。
我只想通过滚动 RecyclerView
来处理 AppBarLayout
的折叠,它位于屏幕底部。
这是我的 xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
app:contentScrim="@color/white"
app:expandedTitleMarginEnd="64dp"
app:expandedTitleMarginStart="48dp"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
app:titleEnabled="false">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_collapseMode="parallax"
android:fitsSystemWindows="true">
<fragment
android:id="@+id/map"
android:name="com.androidmapsextensions.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="73dp"
app:contentInsetLeft="0dp"
app:contentInsetStart="0dp"
app:layout_collapseMode="pin"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light">
<include
android:id="@+id/search_bar"
layout="@layout/layout_searchbar" />
</android.support.v7.widget.Toolbar>
<View
android:id="@+id/toolbar_shadow"
android:layout_width="match_parent"
android:layout_height="3dp"
android:layout_below="@id/search_bar"
android:layout_gravity="bottom"
android:background="@drawable/toolbar_dropshadow"
android:visibility="gone" />
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<RecyclerView
android:id="@+id/farm_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/transparent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
感谢您的回复。
所以经过两个小时的尝试,我找到了一个非常简单的解决方案。我只需要扩展 CoordinatorLayout
并覆盖 OnInterceptTouchEvent
方法,所以 class 看起来像这样:
public class NonTouchableCoordinatorLayout extends CoordinatorLayout {
public NonTouchableCoordinatorLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return false;
}
}
我不确定我是否收到了,但我认为您正在寻找 DragCallback
。
DragCallback
界面允许选择兄弟滚动视图是否应该由滚动到 AppBarLayout
上来控制。
您可以通过调用定义一个:
CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();
AppBarLayout.Behavior behavior = (AppBarLayout.Behavior) params.getBehavior();
behavior.setDragCallback(new AppBarLayout.Behavior.DragCallback() {
@Override
public boolean canDrag(@NonNull AppBarLayout appBarLayout) {
return false;
}
});
通过始终 returning false
,您的滚动视图将不再受 ABL 控制。
注意: 在调用这个之前你应该检查 ViewCompat.isLaidOut(appBarLayout)
,否则 params.getBehavior()
将 return null.
问题
- 即使滚动内容适合屏幕,AppBarLayout 也会滚动。
- 因为默认情况下,我们可以通过触摸和拖动AppBarLayout来拖动AppBarLayout。
解决方案
我们将禁用 AppBarLayout 的 "Dragging" 行为。
// Disable "Drag" for AppBarLayout (i.e. User can't scroll appBarLayout by directly touching appBarLayout - User can only scroll appBarLayout by only using scrollContent)
if (appBarLayout.getLayoutParams() != null) {
CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();
AppBarLayout.Behavior appBarLayoutBehaviour = new AppBarLayout.Behavior();
appBarLayoutBehaviour.setDragCallback(new AppBarLayout.Behavior.DragCallback() {
@Override
public boolean canDrag(@NonNull AppBarLayout appBarLayout) {
return false;
}
});
layoutParams.setBehavior(appBarLayoutBehaviour);
}
参考
这只是上面 "natario's" 已接受答案的扩展。
您可以通过在 xml 中定义自定义 app:layout_behavior
来完成此操作。使用这种方法,您不必担心获取对 LayoutParams
的引用并进行空值检查。
<android.support.design.widget.AppBarLayout
android:id="@+id/app_bar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="com.yourcompany.FixedAppBarLayoutBehavior"
>
然后创建一个从 AppBarLayout.Behavior
延伸的自定义 class。
public class FixedAppBarLayoutBehavior extends AppBarLayout.Behavior {
public FixedAppBarLayoutBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
setDragCallback(new DragCallback() {
@Override public boolean canDrag(@NonNull AppBarLayout appBarLayout) {
return false;
}
});
}
}
Kotlin 版本更新:
class FixedAppBarLayoutBehavior(context: Context, attrs: AttributeSet) : AppBarLayout.Behavior(context, attrs) {
init {
setDragCallback(object : DragCallback() {
override fun canDrag(appBarLayout: AppBarLayout): Boolean = false
})
}
}
您可以使用 NestedScrollView.setNestedScrollingEnabled(false)
禁用 AppBarLayout nestScroll 事件
android
supportmapfragment
android-coordinatorlayout
android-collapsingtoolbarlayout
android-appbarlayout
我有 MapFragment
里面有视差效果 AppBarLayout
:
我想在 AppBarLayout
上禁用滚动,因为无法在地图上移动,因为地图上的触摸事件始终作为滚动事件处理。
我只想通过滚动 RecyclerView
来处理 AppBarLayout
的折叠,它位于屏幕底部。
这是我的 xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
app:contentScrim="@color/white"
app:expandedTitleMarginEnd="64dp"
app:expandedTitleMarginStart="48dp"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
app:titleEnabled="false">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_collapseMode="parallax"
android:fitsSystemWindows="true">
<fragment
android:id="@+id/map"
android:name="com.androidmapsextensions.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="73dp"
app:contentInsetLeft="0dp"
app:contentInsetStart="0dp"
app:layout_collapseMode="pin"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light">
<include
android:id="@+id/search_bar"
layout="@layout/layout_searchbar" />
</android.support.v7.widget.Toolbar>
<View
android:id="@+id/toolbar_shadow"
android:layout_width="match_parent"
android:layout_height="3dp"
android:layout_below="@id/search_bar"
android:layout_gravity="bottom"
android:background="@drawable/toolbar_dropshadow"
android:visibility="gone" />
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<RecyclerView
android:id="@+id/farm_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/transparent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
感谢您的回复。
所以经过两个小时的尝试,我找到了一个非常简单的解决方案。我只需要扩展 CoordinatorLayout
并覆盖 OnInterceptTouchEvent
方法,所以 class 看起来像这样:
public class NonTouchableCoordinatorLayout extends CoordinatorLayout {
public NonTouchableCoordinatorLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return false;
}
}
我不确定我是否收到了,但我认为您正在寻找 DragCallback
。
DragCallback
界面允许选择兄弟滚动视图是否应该由滚动到 AppBarLayout
上来控制。
您可以通过调用定义一个:
CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();
AppBarLayout.Behavior behavior = (AppBarLayout.Behavior) params.getBehavior();
behavior.setDragCallback(new AppBarLayout.Behavior.DragCallback() {
@Override
public boolean canDrag(@NonNull AppBarLayout appBarLayout) {
return false;
}
});
通过始终 returning false
,您的滚动视图将不再受 ABL 控制。
注意: 在调用这个之前你应该检查 ViewCompat.isLaidOut(appBarLayout)
,否则 params.getBehavior()
将 return null.
问题
- 即使滚动内容适合屏幕,AppBarLayout 也会滚动。
- 因为默认情况下,我们可以通过触摸和拖动AppBarLayout来拖动AppBarLayout。
解决方案
我们将禁用 AppBarLayout 的 "Dragging" 行为。
// Disable "Drag" for AppBarLayout (i.e. User can't scroll appBarLayout by directly touching appBarLayout - User can only scroll appBarLayout by only using scrollContent) if (appBarLayout.getLayoutParams() != null) { CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams(); AppBarLayout.Behavior appBarLayoutBehaviour = new AppBarLayout.Behavior(); appBarLayoutBehaviour.setDragCallback(new AppBarLayout.Behavior.DragCallback() { @Override public boolean canDrag(@NonNull AppBarLayout appBarLayout) { return false; } }); layoutParams.setBehavior(appBarLayoutBehaviour); }
参考
这只是上面 "natario's" 已接受答案的扩展。
您可以通过在 xml 中定义自定义 app:layout_behavior
来完成此操作。使用这种方法,您不必担心获取对 LayoutParams
的引用并进行空值检查。
<android.support.design.widget.AppBarLayout
android:id="@+id/app_bar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="com.yourcompany.FixedAppBarLayoutBehavior"
>
然后创建一个从 AppBarLayout.Behavior
延伸的自定义 class。
public class FixedAppBarLayoutBehavior extends AppBarLayout.Behavior {
public FixedAppBarLayoutBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
setDragCallback(new DragCallback() {
@Override public boolean canDrag(@NonNull AppBarLayout appBarLayout) {
return false;
}
});
}
}
Kotlin 版本更新:
class FixedAppBarLayoutBehavior(context: Context, attrs: AttributeSet) : AppBarLayout.Behavior(context, attrs) {
init {
setDragCallback(object : DragCallback() {
override fun canDrag(appBarLayout: AppBarLayout): Boolean = false
})
}
}
您可以使用 NestedScrollView.setNestedScrollingEnabled(false)
禁用 AppBarLayout nestScroll 事件