feat(meal): 添加餐品列表下拉刷新和上拉加载功能
- 集成 SmartRefreshLayout 实现下拉刷新和上拉加载更多 - 修改 MealListActivity 添加分页加载逻辑,每页30条数据 - 实现空视图显示功能,当无数据时展示暂无数据提示 - 优化 RecyclerView 点击事件处理,使用 startActivity 扩展函数 - 添加加载状态管理,区分首次加载和后续加载情况 - 实现加载失败时的状态回退和错误处理机制 - 统一网络请求回调处理,优化 Loading 状态显示逻辑
This commit is contained in:
@@ -114,7 +114,8 @@ class NetViewModelV2(
|
|||||||
) {
|
) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
onLoading()
|
onLoading()
|
||||||
onResult(repository.getFoodOptions(keyword, pageNum, pageSize))
|
val state = repository.getFoodOptions(keyword, pageNum, pageSize)
|
||||||
|
onResult(state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,14 +2,17 @@ package com.shuwei.dish.match.ui
|
|||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import com.shuwei.dish.match.adapter.MealListAdapter
|
import com.shuwei.dish.match.adapter.MealListAdapter
|
||||||
import com.shuwei.dish.match.base.BaseActivity
|
import com.shuwei.dish.match.base.BaseActivity
|
||||||
import com.shuwei.dish.match.databinding.ActivityMealListBinding
|
import com.shuwei.dish.match.databinding.ActivityMealListBinding
|
||||||
|
import com.shuwei.dish.match.databinding.LayoutEmptyViewBinding
|
||||||
import com.shuwei.dish.match.model.NutFoodOptionVO
|
import com.shuwei.dish.match.model.NutFoodOptionVO
|
||||||
import com.shuwei.dish.match.net.NetViewModelV2
|
import com.shuwei.dish.match.net.NetViewModelV2
|
||||||
import com.shuwei.dish.match.net.UiState
|
import com.shuwei.dish.match.net.UiState
|
||||||
import com.shuwei.dish.match.utils.ext.gone
|
import com.shuwei.dish.match.utils.ext.gone
|
||||||
|
import com.shuwei.dish.match.utils.ext.startActivity
|
||||||
import com.shuwei.dish.match.utils.ext.toast
|
import com.shuwei.dish.match.utils.ext.toast
|
||||||
import com.shuwei.dish.match.utils.ext.visible
|
import com.shuwei.dish.match.utils.ext.visible
|
||||||
|
|
||||||
@@ -20,13 +23,24 @@ class MealListActivity : BaseActivity() {
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val MEAL_ITEM = "mealItem"
|
const val MEAL_ITEM = "mealItem"
|
||||||
|
const val PAGE_SIZE = 30
|
||||||
}
|
}
|
||||||
|
|
||||||
private val binding by lazy { ActivityMealListBinding.inflate(layoutInflater) }
|
private val binding by lazy { ActivityMealListBinding.inflate(layoutInflater) }
|
||||||
private val viewModelV2 by lazy { NetViewModelV2() }
|
private val viewModelV2 by lazy { NetViewModelV2() }
|
||||||
|
|
||||||
private val mealList = mutableListOf<NutFoodOptionVO>()
|
private val mealList = mutableListOf<NutFoodOptionVO>()
|
||||||
private val mealAdapter by lazy { MealListAdapter(mealList) }
|
private val mealAdapter by lazy { MealListAdapter(mealList).apply {
|
||||||
|
isStateViewEnable = true
|
||||||
|
setOnItemClickListener { _, _, position ->
|
||||||
|
val item = mealList.getOrNull(position) ?: return@setOnItemClickListener
|
||||||
|
startActivity<PackActivity>{
|
||||||
|
putExtra(PackActivity.MEAL_ITEM, item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} }
|
||||||
|
private var emptyViewBinding: LayoutEmptyViewBinding? = null
|
||||||
|
private var currentPage = 1
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
@@ -54,12 +68,15 @@ class MealListActivity : BaseActivity() {
|
|||||||
private fun initRecyclerView() {
|
private fun initRecyclerView() {
|
||||||
binding.rvMealList.layoutManager = LinearLayoutManager(this)
|
binding.rvMealList.layoutManager = LinearLayoutManager(this)
|
||||||
binding.rvMealList.adapter = mealAdapter
|
binding.rvMealList.adapter = mealAdapter
|
||||||
mealAdapter.setOnItemClickListener { _, _, position ->
|
binding.refreshLayout.setEnableRefresh(true)
|
||||||
val item = mealList.getOrNull(position) ?: return@setOnItemClickListener
|
binding.refreshLayout.setEnableLoadMore(true)
|
||||||
val intent = Intent(this, PackActivity::class.java).apply {
|
binding.refreshLayout.setOnRefreshListener {
|
||||||
putExtra(PackActivity.MEAL_ITEM, item)
|
currentPage = 1
|
||||||
}
|
loadMealList()
|
||||||
startActivity(intent)
|
}
|
||||||
|
binding.refreshLayout.setOnLoadMoreListener {
|
||||||
|
currentPage++
|
||||||
|
loadMealList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,32 +84,70 @@ class MealListActivity : BaseActivity() {
|
|||||||
* 加载餐品列表
|
* 加载餐品列表
|
||||||
*/
|
*/
|
||||||
private fun loadMealList() {
|
private fun loadMealList() {
|
||||||
|
showLoading("加载中……")
|
||||||
viewModelV2.getFoodOptionsWithCallback(
|
viewModelV2.getFoodOptionsWithCallback(
|
||||||
keyword = null,
|
keyword = null,
|
||||||
pageNum = 1,
|
pageNum = currentPage,
|
||||||
pageSize = 100,
|
pageSize = PAGE_SIZE,
|
||||||
onLoading = {
|
onLoading = {},
|
||||||
showLoading("加载中……")
|
|
||||||
},
|
|
||||||
onResult = { state ->
|
onResult = { state ->
|
||||||
dismissLoading()
|
dismissLoading()
|
||||||
when (state) {
|
when (state) {
|
||||||
is UiState.Success -> {
|
is UiState.Success -> {
|
||||||
val records = state.data?.records
|
val records = state.data?.records
|
||||||
if (records.isNullOrEmpty()) {
|
if (currentPage == 1 && records.isNullOrEmpty()) {
|
||||||
toast("暂无数据")
|
binding.refreshLayout.finishRefresh()
|
||||||
|
loadEmptyView()
|
||||||
return@getFoodOptionsWithCallback
|
return@getFoodOptionsWithCallback
|
||||||
}
|
}
|
||||||
mealList.clear()
|
if (currentPage == 1) {
|
||||||
mealList.addAll(records)
|
mealList.clear()
|
||||||
|
}
|
||||||
|
mealList.addAll(records!!)
|
||||||
mealAdapter.notifyDataSetChanged()
|
mealAdapter.notifyDataSetChanged()
|
||||||
|
val isLoadMore = records.size >= PAGE_SIZE
|
||||||
|
binding.refreshLayout.setEnableLoadMore(isLoadMore)
|
||||||
|
if (isLoadMore) {
|
||||||
|
binding.refreshLayout.finishLoadMore()
|
||||||
|
} else {
|
||||||
|
binding.refreshLayout.finishLoadMoreWithNoMoreData()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
is UiState.Error -> {
|
is UiState.Error -> {
|
||||||
toast(state.msg)
|
toast(state.msg)
|
||||||
|
if (currentPage == 1) {
|
||||||
|
binding.refreshLayout.finishRefresh()
|
||||||
|
loadEmptyView()
|
||||||
|
} else {
|
||||||
|
currentPage--
|
||||||
|
binding.refreshLayout.finishLoadMore()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else -> {}
|
else -> {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加载空视图
|
||||||
|
*/
|
||||||
|
private fun loadEmptyView() {
|
||||||
|
mealList.clear()
|
||||||
|
mealAdapter.notifyDataSetChanged()
|
||||||
|
if (emptyViewBinding == null) {
|
||||||
|
emptyViewBinding = LayoutEmptyViewBinding.inflate(
|
||||||
|
LayoutInflater.from(this), binding.rvMealList, false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
emptyViewBinding?.run {
|
||||||
|
tvContent.text = "暂无数据"
|
||||||
|
tvSubContent.text = "暂无餐品数据"
|
||||||
|
mealAdapter.stateView = root
|
||||||
|
}
|
||||||
|
binding.refreshLayout.run {
|
||||||
|
setEnableRefresh(true)
|
||||||
|
setEnableLoadMore(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,15 +26,30 @@
|
|||||||
android:textColor="@color/black666"
|
android:textColor="@color/black666"
|
||||||
android:textSize="28sp" />
|
android:textSize="28sp" />
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<com.scwang.smart.refresh.layout.SmartRefreshLayout
|
||||||
android:id="@+id/rvMealList"
|
android:id="@+id/refreshLayout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent">
|
||||||
android:layout_marginBottom="20dp"
|
|
||||||
android:overScrollMode="never"
|
<com.scwang.smart.refresh.header.ClassicsHeader
|
||||||
android:scrollbars="vertical"
|
android:layout_width="match_parent"
|
||||||
tools:itemCount="3"
|
android:layout_height="wrap_content" />
|
||||||
tools:listitem="@layout/list_item_food2" />
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/rvMealList"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginBottom="20dp"
|
||||||
|
android:overScrollMode="never"
|
||||||
|
android:scrollbars="vertical"
|
||||||
|
tools:itemCount="3"
|
||||||
|
tools:listitem="@layout/list_item_food2" />
|
||||||
|
|
||||||
|
<com.scwang.smart.refresh.footer.ClassicsFooter
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
|
</com.scwang.smart.refresh.layout.SmartRefreshLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user