SwipeRefreshLayout 是否与具有多个 viewType 的适配器兼容?
Is SwipeRefreshLayout compatible with an adapter that has multiple viewType?
我正在制作一个列表,当我走到列表底部时,它会得到更多的项目。我也希望这个列表可以刷新,所以我需要一个 SwipeRefreshLayout
.
假设我有这样的适配器:
class OrdersListAdapter(val selected : (Order) -> Unit) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
fun addOrders(orders: ArrayList<Order>) {
this.orders.addAll(orders)
notifyItemRangeInserted(this.orders.size - orders.size + FIRST_ITEM_INDEX, orders.size)
}
fun setFirstOrders(orders: ArrayList<Order>) {
this.orders = orders
notifyDataSetChanged()
}
override fun getItemCount(): Int {
return (orders.size + 1 + FIRST_ITEM_INDEX)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when (viewType) {
TYPE_ORDERS -> OrdersViewHolder(DataBindingUtil.inflate<OrdersItemBinding>(LayoutInflater.from(parent.context),
R.layout.orders_item, parent, false).apply {
viewModel = OrdersViewModel()
})
else -> LoadingMoreOrdersViewHolder(DataBindingUtil.inflate<LoadingMoreOrdersItemBinding>(LayoutInflater.from(parent.context),
R.layout.loading_more_orders_item, parent, false).apply {
viewModel = LoadingMoreOrdersViewModel()
})
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (getItemViewType(position)) {
TYPE_ORDERS -> (holder as? OrdersViewHolder)?.setData(orders[position - FIRST_ITEM_INDEX])
TYPE_LOADING -> (holder as? LoadingMoreOrdersViewHolder)?.setState(loading, error, noMoreItems)
}
}
override fun getItemViewType(position: Int): Int =
if (position == FIRST_ITEM_INDEX - 1) TYPE_HEADER else if (position == itemCount - 1) TYPE_LOADING else TYPE_ORDERS
好吧,如果我像这样把我的 RecyclerView
放在 SwipeRefreshLayout
中:
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/refresh_layout"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/toolbar">
<android.support.v7.widget.RecyclerView
android:id="@+id/orders_rv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layoutManager="android.support.v7.widget.LinearLayoutManager" />
</android.support.v4.widget.SwipeRefreshLayout>
这将显示所有项目,但 refreshLayout 将不起作用:如果我拉出我的视图,什么也不会发生。
但是如果我没有在我的适配器中设置任何加载布局(列表底部的那个,加载更多项目,从 R.layout.loading_more_orders_item
膨胀),那么 SwipeRefreshLayout 将正常工作。
如何在我的适配器中有 2 种视图类型,并在 SwipeRefreshLayout 中设置我的 RecyclerView?
编辑:
这是我的 onRefreshListener :
refreshLayout = binding.swipeRefreshLayout
refreshLayout?.setOnRefreshListener { reloadOrders() }
并且在 reloadOrders() 中:
private fun reloadOrders() {
viewModel.setLoading()
refreshLayout?.isRefreshing = false
Observable.timer(1, TimeUnit.SECONDS)
.subscribe { getOrders() }
}
回答你的问题,兼容性不是你遇到的问题。不确定布局的大小,因为它的高度是 0dp。我会玩弄视图大小和视图层次结构。
我相信发生的事情是 recyclerview 从 swiperefreshlayout 接管了 ontouch 事件。您可以尝试将 linearlayout 及其 canScrollVertically()
方法覆盖为 return false。干杯!
好的,感谢@r2rek,我找到了适合我的解决方案:
在代码中,我们创建一个 class 扩展 LinearLayoutManager
并覆盖方法 canScrollVertically()
以始终 return false :
inner class MyLinearLayout(context: Context) : LinearLayoutManager(context) {
override fun canScrollVertically(): Boolean {
return (false)
}
}
然后,当我们初始化我们的 RecyclerView
时,我们将这个 class 应用到我们的 layoutManager
:
ordersRv?.layoutManager = MyLinearLayout(this)
这将允许您刷新,但是您将无法滚动 RecyclerView
(呃)。
要解决此问题,请在 xml 中添加一个 NestedScrollView
,如下所示:
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/refresh_layout"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:visibility="@{viewModel.ordersVisibility}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/toolbar">
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/orders_rv"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</android.support.v4.widget.NestedScrollView>
</android.support.v4.widget.SwipeRefreshLayout>
您现在可以在 RecyclerView
中滚动,然后用 SwipeRefreshLayout
拉动刷新。
我觉得这个方法有点hacky,所以如果有人有更好的解决方案,请随时告诉我们!
我正在制作一个列表,当我走到列表底部时,它会得到更多的项目。我也希望这个列表可以刷新,所以我需要一个 SwipeRefreshLayout
.
假设我有这样的适配器:
class OrdersListAdapter(val selected : (Order) -> Unit) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
fun addOrders(orders: ArrayList<Order>) {
this.orders.addAll(orders)
notifyItemRangeInserted(this.orders.size - orders.size + FIRST_ITEM_INDEX, orders.size)
}
fun setFirstOrders(orders: ArrayList<Order>) {
this.orders = orders
notifyDataSetChanged()
}
override fun getItemCount(): Int {
return (orders.size + 1 + FIRST_ITEM_INDEX)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when (viewType) {
TYPE_ORDERS -> OrdersViewHolder(DataBindingUtil.inflate<OrdersItemBinding>(LayoutInflater.from(parent.context),
R.layout.orders_item, parent, false).apply {
viewModel = OrdersViewModel()
})
else -> LoadingMoreOrdersViewHolder(DataBindingUtil.inflate<LoadingMoreOrdersItemBinding>(LayoutInflater.from(parent.context),
R.layout.loading_more_orders_item, parent, false).apply {
viewModel = LoadingMoreOrdersViewModel()
})
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (getItemViewType(position)) {
TYPE_ORDERS -> (holder as? OrdersViewHolder)?.setData(orders[position - FIRST_ITEM_INDEX])
TYPE_LOADING -> (holder as? LoadingMoreOrdersViewHolder)?.setState(loading, error, noMoreItems)
}
}
override fun getItemViewType(position: Int): Int =
if (position == FIRST_ITEM_INDEX - 1) TYPE_HEADER else if (position == itemCount - 1) TYPE_LOADING else TYPE_ORDERS
好吧,如果我像这样把我的 RecyclerView
放在 SwipeRefreshLayout
中:
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/refresh_layout"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/toolbar">
<android.support.v7.widget.RecyclerView
android:id="@+id/orders_rv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layoutManager="android.support.v7.widget.LinearLayoutManager" />
</android.support.v4.widget.SwipeRefreshLayout>
这将显示所有项目,但 refreshLayout 将不起作用:如果我拉出我的视图,什么也不会发生。
但是如果我没有在我的适配器中设置任何加载布局(列表底部的那个,加载更多项目,从 R.layout.loading_more_orders_item
膨胀),那么 SwipeRefreshLayout 将正常工作。
如何在我的适配器中有 2 种视图类型,并在 SwipeRefreshLayout 中设置我的 RecyclerView?
编辑:
这是我的 onRefreshListener :
refreshLayout = binding.swipeRefreshLayout
refreshLayout?.setOnRefreshListener { reloadOrders() }
并且在 reloadOrders() 中:
private fun reloadOrders() {
viewModel.setLoading()
refreshLayout?.isRefreshing = false
Observable.timer(1, TimeUnit.SECONDS)
.subscribe { getOrders() }
}
回答你的问题,兼容性不是你遇到的问题。不确定布局的大小,因为它的高度是 0dp。我会玩弄视图大小和视图层次结构。
我相信发生的事情是 recyclerview 从 swiperefreshlayout 接管了 ontouch 事件。您可以尝试将 linearlayout 及其 canScrollVertically()
方法覆盖为 return false。干杯!
好的,感谢@r2rek,我找到了适合我的解决方案:
在代码中,我们创建一个 class 扩展 LinearLayoutManager
并覆盖方法 canScrollVertically()
以始终 return false :
inner class MyLinearLayout(context: Context) : LinearLayoutManager(context) {
override fun canScrollVertically(): Boolean {
return (false)
}
}
然后,当我们初始化我们的 RecyclerView
时,我们将这个 class 应用到我们的 layoutManager
:
ordersRv?.layoutManager = MyLinearLayout(this)
这将允许您刷新,但是您将无法滚动 RecyclerView
(呃)。
要解决此问题,请在 xml 中添加一个 NestedScrollView
,如下所示:
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/refresh_layout"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:visibility="@{viewModel.ordersVisibility}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/toolbar">
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/orders_rv"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</android.support.v4.widget.NestedScrollView>
</android.support.v4.widget.SwipeRefreshLayout>
您现在可以在 RecyclerView
中滚动,然后用 SwipeRefreshLayout
拉动刷新。
我觉得这个方法有点hacky,所以如果有人有更好的解决方案,请随时告诉我们!