我里面有
RecyclerView
NestedScrollView
。如果NestedScrollView
内容(包括传递给NestedScrollViews
适配器的列表)高于特定高度,我想要的是滚动RecyclerViews
的全部内容。
我有自定义
NestedScrollView
类来处理这个测量onMeasure
内所有儿童的身高,如果儿童总身高超过一定值,它应该启用滚动而不是展开NestedScrollView
高度。 (我需要这个功能,因为 NestedScrollView
被允许扩展到最大显示高度的 40%)。
如果我用包含
NestedScrollView
、RelativeLayouts
、TextViews
等的通用组件填充Buttons
,此功能运行良好。但是RecyclerView
出于某种原因完全阻止了整个NestedScrollView
的滚动。
这里是从
NestedScrollView:
登录
ScrollViewWithMaxHeight: onMeasure curr_height: 11678, max: 966
嵌套滚动视图:
class ScrollViewWithMaxHeight: NestedScrollView{
private var maxHeight = WITHOUT_MAX_HEIGHT_VALUE
constructor(context: Context) : super(context) {}
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {}
constructor(context: Context, attrs: AttributeSet?, defStyle: Int) : super(context, attrs, defStyle) {}
var onHeightChangeListener: ((Int)->Unit)? = null
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
var measuredHeight = heightMeasureSpec
val currHeight = getCurrContentHeight()
try {
val heightSize: Int
App.log("ScrollViewWithMaxHeight: onMeasure curr_height: $currHeight, max: $maxHeight")
if (maxHeight != WITHOUT_MAX_HEIGHT_VALUE && currHeight > maxHeight) {
heightSize = maxHeight
} else {
heightSize = currHeight
}
measuredHeight = MeasureSpec.makeMeasureSpec(heightSize, MeasureSpec.AT_MOST)
layoutParams.height = heightSize
onHeightChangeListener?.invoke(heightSize)
} catch (e: Exception) {
} finally {
App.log("ScrollViewWithMaxHeight: onMeasure final: $measuredHeight")
super.onMeasure(widthMeasureSpec, measuredHeight)
}
}
private fun getCurrContentHeight(): Int{
var height = 0
for (i in 0 until childCount) {
val child = getChildAt(i)
val h = child.measuredHeight
App.log("ScrollViewWithMaxHeight: getCurrChildHeight: $h")
if (h > height) height = h
}
return height
}
fun setOnDynamicHeightChangeListener(l: (Int)->Unit){
onHeightChangeListener = l
}
fun setMaxHeight(maxHeight: Int) {
this.maxHeight = maxHeight
}
companion object {
var WITHOUT_MAX_HEIGHT_VALUE = -1
}
}
RecyclerView 初始化 + 布局:
list = findViewById<RecyclerView>(R.id.list).also { rv ->
rv.isNestedScrollingEnabled = false
rv.setOnTouchListener { _, _ -> false }
rv.adapter = adapter
rv.layoutManager = LinearLayoutManager(a)
}
布局:
<RelativeLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:clipChildren="false">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/list"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:clipToPadding="false"
android:clipChildren="false"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<components.loading_indicator.LoadingIndicator
android:id="@+id/progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true" />
</RelativeLayout>
嵌套滚动视图初始化:
it.findViewById<ScrollViewWithMaxHeight>(R.id.scrollParent).also { sv->
sv.setMaxHeight(getScrollViewHeight())
sv.setOnDynamicHeightChangeListener { h-> }
sv.isFillViewport = true
sv.viewTreeObserver.addOnScrollChangedListener {
isScrollOnTop = sv.scrollY == 0
}
}
这是导致滚动滞后的问题:
2023-03-28 09:48:18.430 I RecyclerViewAdapter: onCreateViewHolder: creating item
2023-03-28 09:48:18.435 I RecyclerViewAdapter: onCreateViewHolder: creating item
2023-03-28 09:48:18.440 I RecyclerViewAdapter: onCreateViewHolder: creating item
2023-03-28 09:48:18.445 I RecyclerViewAdapter: onCreateViewHolder: creating item
2023-03-28 09:48:27.955 I RecyclerViewAdapter: onCreateViewHolder: creating item
2023-03-28 09:48:27.962 I RecyclerViewAdapter: onCreateViewHolder: creating item
2023-03-28 09:48:27.967 I RecyclerViewAdapter: onCreateViewHolder: creating item
2023-03-28 09:48:27.973 I RecyclerViewAdapter: onCreateViewHolder: creating item
2023-03-28 09:48:27.979 I RecyclerViewAdapter: onCreateViewHolder: creating item
2023-03-28 09:48:27.985 I RecyclerViewAdapter: onCreateViewHolder: creating item
2023-03-28 09:48:27.990 I RecyclerViewAdapter: onCreateViewHolder: creating item
2023-03-28 09:48:27.996 I RecyclerViewAdapter: onCreateViewHolder: creating item
2023-03-28 09:48:28.002 I RecyclerViewAdapter: onCreateViewHolder: creating item
2023-03-28 09:48:28.008 I RecyclerViewAdapter: onCreateViewHolder: creating item
2023-03-28 09:48:28.013 I RecyclerViewAdapter: onCreateViewHolder: creating item
2023-03-28 09:48:28.019 I RecyclerViewAdapter: onCreateViewHolder: creating item
2023-03-28 09:48:28.025 I RecyclerViewAdapter: onCreateViewHolder: creating item
2023-03-28 09:48:28.031 I RecyclerViewAdapter: onCreateViewHolder: creating item
2023-03-28 09:48:28.037 I RecyclerViewAdapter: onCreateViewHolder: creating item
...
这是里面的日志
onCreateViewHolder
。它调用列表中的每个项目。即使我尝试滚动,它又被调用了。不确定是什么原因造成的。我的应用程序中到处都是RecyclerViews
,只有这个没有回收。
好的,我找到了造成这种情况的原因。真的很奇怪。我在
RecyclerView
上方有另一个水平的 NestedScrollView
(这显然不是 NestedScrollView
的一部分,因为它是静态的并且它不应该垂直滚动。它只是带有项目的水平选择器。
一旦我将它从布局中删除,垂直滚动就会像往常一样进行适当的回收。
我的布局设计和组件设计是模块化的,我为父母注入了带有膨胀和
addView
功能的布局,所以我可以在代码中制作独立的组件,这些组件可以注入到任何空布局中。
我从中删除了NestedScrollView
,因为它没有必要重建错误。即使只有 RecyclerView
作为组件,它也会发生(所以我根本不需要嵌套滚动)。
一旦
horizontal_picker_content
被注入并使用,它就会阻塞 vertical_list_container
的回收,这是我的垂直 RecyclerView
被注入的地方。
所以我重建了我的最终布局在我的
DialogBottomSheet
中的样子所以你可以看到它的结构:
<RelativeLayout
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
android:clipToPadding="false"
android:orientation="vertical"
tools:ignore="UselessParent">
<LinearLayout
android:id="@+id/topInfo"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
</LinearLayout>
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/bottomContentContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:clipChildren="false">
<FrameLayout
android:id="@+id/bottomSheetContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_insetEdge="bottom"
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">
<RelativeLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:clipChildren="false"
android:background="@color/background_paper"
app:layout_insetEdge="bottom"
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">
<RelativeLayout
android:id="@+id/peekSwiper"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/dialog_title_block"
android:layout_width="match_parent"
android:layout_height="20dp"
android:orientation="horizontal"
android:elevation="0dp"
android:translationZ="4dp"
android:background="@drawable/bg_bottomsheet_top"/>
</RelativeLayout>
<LinearLayout
android:id="@+id/dialog_bottom_block"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_below="@id/peekSwiper"
android:layout_gravity="center_horizontal"
android:gravity="center_horizontal">
<LinearLayout
android:id="@+id/dialog_title_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/background_paper"
android:orientation="vertical">
<RelativeLayout
android:id="@+id/horizontal_picker_content"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:clipChildren="false"
android:gravity="center">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/horizontalPickList"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:scrollbars="horizontal"
android:clipToPadding="false"
android:clipChildren="false"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:paddingTop="8dp"
android:paddingBottom="8dp"/>
<include
layout="@layout/menu_item_separator"
android:id="@+id/separator"
android:layout_width="wrap_content"
android:layout_height="1dp"
android:layout_below="@+id/horizontalPickList"/>
</RelativeLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/dialog_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipChildren="false"
android:clipToPadding="false"
android:background="@color/background_paper">
<LinearLayout
android:id="@+id/vertical_content_parent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:clipChildren="false"
android:orientation="vertical">
<LinearLayout
android:id="@+id/vertical_content_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:clipChildren="false"
android:orientation="vertical">
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/vertical_list_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/vertical_content_parent"
android:clipToPadding="false"
android:clipChildren="false"
android:orientation="vertical">
</LinearLayout>
</RelativeLayout>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/buttonLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@id/dialog_bottom_block"
android:layout_gravity="center_horizontal"
android:gravity="center_horizontal"
android:layout_centerHorizontal="true"
android:orientation="vertical">
</LinearLayout>
</RelativeLayout>
</FrameLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</RelativeLayout>