ViewPager2 OnApplyWindowInsetsListener 未调用
ViewPager2 OnApplyWindowInsetsListener not called
我在 ViewPager2
中的 Fragment 上有一个 FAB,它在边到边时应该尊重 window 插入。我在 FAB 上添加了一个 OnApplyWindowInsetsListener
来更新它的边距。这在使用旧的 ViewPager
.
时工作正常
更新到 ViewPager2
时,OnApplyWindowInsetsListener
似乎没有在开头调用。不过,当我启动 ActionMode
时。然后,调用侦听器并使用新边距,直到我离开父 Fragment。
我已经分叉了演示项目来说明问题。请参阅 https://github.com/hardysim/views-widgets-samples/tree/edge-to-edge 分支 edge-to-edge
上的 "ViewPager2 with Nested RecyclerViews" 示例 (ParallelNestedScrollingActivity
)。
在这里,我向 ViewPager2 页面上使用的(嵌套)RecyclerView
添加了一个 FAB,并将 Activity-UI 设置为边到边(参见 View.goEdgeToEdge()
)。然后,FAB 在导航栏后面,我们需要更新它的边距以添加 window 插图。
这就是它不起作用的地方(但它在旧的 ViewPager
上运行良好)。
这似乎是 ViewPager2
实施错误。
pager 第一次获取我们创建的视图时,pager 会为其调用 requestApplyInsets
。但不幸的是,该视图没有附加父视图,因此 requestApplyInsets
的调用无效。
可以通过在onViewAttachedToWindow
上调用requestApplyInsets
添加View.OnAttachStateChangeListener
来解决。
您的 ParallelNestedScrollingActivity
示例似乎运行良好:
diff --git a/ViewPager2/app/src/main/java/androidx/viewpager2/integration/testapp/ParallelNestedScrollingActivity.kt b/ViewPager2/app/src/main/java/androidx/viewpager2/integration/testapp/ParallelNestedScrollingActivity.kt
index 4e3753a..d2683df 100644
--- a/ViewPager2/app/src/main/java/androidx/viewpager2/integration/testapp/ParallelNestedScrollingActivity.kt
+++ b/ViewPager2/app/src/main/java/androidx/viewpager2/integration/testapp/ParallelNestedScrollingActivity.kt
@@ -29,0 +30 @@ import android.widget.TextView
+import androidx.core.view.ViewCompat
@@ -57 +58,3 @@ class ParallelNestedScrollingActivity : Activity() {
- val root = inflater.inflate(R.layout.item_nested_recyclerviews, parent, false)
+ val root = inflater.inflate(R.layout.item_nested_recyclerviews, parent, false).apply {
+ addOnAttachStateChangeListener(RequestApplyInsetsOnAttached)
+ }
@@ -132,0 +136,5 @@ internal val CELL_COLORS = listOf(
+
+private object RequestApplyInsetsOnAttached : View.OnAttachStateChangeListener {
+ override fun onViewAttachedToWindow(view: View) = ViewCompat.requestApplyInsets(view)
+ override fun onViewDetachedFromWindow(view: View) = Unit
+}
这已在 issue tracker 最初提出的问题中得到回答:
The problem here is that the pages are not yet attached to the view hierarchy when the window insets are dispatched. The system doesn't call the OnApplyWindowInsetsListener
with the current insets when a view is attached, so you'll have to call requestApplyInsets()
when the view is attached to the hierarchy.
所以我创造了一个小帮手
/**
* Call this everytime when using [ViewCompat.setOnApplyWindowInsetsListener]
* to ensure that insets are always received.
*/
private fun View.requestApplyInsetsWhenAttached() {
// https://chris.banes.dev/2019/04/12/insets-listeners-to-layouts/
if (isAttachedToWindow) {
// We're already attached, just request as normal
requestApplyInsets()
} else {
// We're not attached to the hierarchy, add a listener to request when we are
addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener {
override fun onViewAttachedToWindow(v: View) {
v.removeOnAttachStateChangeListener(this)
v.requestApplyInsets()
}
override fun onViewDetachedFromWindow(v: View) = Unit
})
}
}
在 View
:
上调用 ViewCompat.setOnApplyWindowInsetsListener()
后立即调用
ViewCompat.setOnApplyWindowInsetsListener(view) { view, insets ->
// [do stuff]
insets
}
view.requestApplyInsetsWhenAttached()
我在 ViewPager2
中的 Fragment 上有一个 FAB,它在边到边时应该尊重 window 插入。我在 FAB 上添加了一个 OnApplyWindowInsetsListener
来更新它的边距。这在使用旧的 ViewPager
.
更新到 ViewPager2
时,OnApplyWindowInsetsListener
似乎没有在开头调用。不过,当我启动 ActionMode
时。然后,调用侦听器并使用新边距,直到我离开父 Fragment。
我已经分叉了演示项目来说明问题。请参阅 https://github.com/hardysim/views-widgets-samples/tree/edge-to-edge 分支 edge-to-edge
上的 "ViewPager2 with Nested RecyclerViews" 示例 (ParallelNestedScrollingActivity
)。
在这里,我向 ViewPager2 页面上使用的(嵌套)RecyclerView
添加了一个 FAB,并将 Activity-UI 设置为边到边(参见 View.goEdgeToEdge()
)。然后,FAB 在导航栏后面,我们需要更新它的边距以添加 window 插图。
这就是它不起作用的地方(但它在旧的 ViewPager
上运行良好)。
这似乎是 ViewPager2
实施错误。
pager 第一次获取我们创建的视图时,pager 会为其调用 requestApplyInsets
。但不幸的是,该视图没有附加父视图,因此 requestApplyInsets
的调用无效。
可以通过在onViewAttachedToWindow
上调用requestApplyInsets
添加View.OnAttachStateChangeListener
来解决。
您的 ParallelNestedScrollingActivity
示例似乎运行良好:
diff --git a/ViewPager2/app/src/main/java/androidx/viewpager2/integration/testapp/ParallelNestedScrollingActivity.kt b/ViewPager2/app/src/main/java/androidx/viewpager2/integration/testapp/ParallelNestedScrollingActivity.kt
index 4e3753a..d2683df 100644
--- a/ViewPager2/app/src/main/java/androidx/viewpager2/integration/testapp/ParallelNestedScrollingActivity.kt
+++ b/ViewPager2/app/src/main/java/androidx/viewpager2/integration/testapp/ParallelNestedScrollingActivity.kt
@@ -29,0 +30 @@ import android.widget.TextView
+import androidx.core.view.ViewCompat
@@ -57 +58,3 @@ class ParallelNestedScrollingActivity : Activity() {
- val root = inflater.inflate(R.layout.item_nested_recyclerviews, parent, false)
+ val root = inflater.inflate(R.layout.item_nested_recyclerviews, parent, false).apply {
+ addOnAttachStateChangeListener(RequestApplyInsetsOnAttached)
+ }
@@ -132,0 +136,5 @@ internal val CELL_COLORS = listOf(
+
+private object RequestApplyInsetsOnAttached : View.OnAttachStateChangeListener {
+ override fun onViewAttachedToWindow(view: View) = ViewCompat.requestApplyInsets(view)
+ override fun onViewDetachedFromWindow(view: View) = Unit
+}
这已在 issue tracker 最初提出的问题中得到回答:
The problem here is that the pages are not yet attached to the view hierarchy when the window insets are dispatched. The system doesn't call the
OnApplyWindowInsetsListener
with the current insets when a view is attached, so you'll have to callrequestApplyInsets()
when the view is attached to the hierarchy.
所以我创造了一个小帮手
/**
* Call this everytime when using [ViewCompat.setOnApplyWindowInsetsListener]
* to ensure that insets are always received.
*/
private fun View.requestApplyInsetsWhenAttached() {
// https://chris.banes.dev/2019/04/12/insets-listeners-to-layouts/
if (isAttachedToWindow) {
// We're already attached, just request as normal
requestApplyInsets()
} else {
// We're not attached to the hierarchy, add a listener to request when we are
addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener {
override fun onViewAttachedToWindow(v: View) {
v.removeOnAttachStateChangeListener(this)
v.requestApplyInsets()
}
override fun onViewDetachedFromWindow(v: View) = Unit
})
}
}
在 View
:
ViewCompat.setOnApplyWindowInsetsListener()
后立即调用
ViewCompat.setOnApplyWindowInsetsListener(view) { view, insets ->
// [do stuff]
insets
}
view.requestApplyInsetsWhenAttached()