feat: update claude md file
This commit is contained in:
702
CLAUDE.md
702
CLAUDE.md
@@ -594,6 +594,708 @@ companion object {
|
||||
}
|
||||
```
|
||||
|
||||
### 列表查询+多选+批量处理页面开发 (完整指南)
|
||||
|
||||
这是项目中最常见的业务场景之一:列表查询、多选Item、批量操作。本指南基于`IntExpOutHandoverActivity`(国际出港-出库交接)的实际案例总结。
|
||||
|
||||
#### 典型场景特征
|
||||
|
||||
- ✅ 顶部多条件搜索区域
|
||||
- ✅ 列表支持多选(图片切换表示选择状态)
|
||||
- ✅ 底部全选按钮+统计信息+批量操作按钮
|
||||
- ✅ 分页加载数据
|
||||
|
||||
#### 开发步骤总览 (8步)
|
||||
|
||||
1. 修改/创建Bean (添加ObservableBoolean选择状态)
|
||||
2. 定义API接口 (列表查询+统计查询+批量操作)
|
||||
3. 创建ViewHolder (处理选择图标点击)
|
||||
4. 创建ViewModel (继承BasePageViewModel)
|
||||
5. 创建Activity布局 (搜索区+列表+底部栏)
|
||||
6. 创建列表项布局 (使用completeSpace对齐)
|
||||
7. 创建Activity (绑定数据+观察全选状态)
|
||||
8. 在AndroidManifest.xml中注册
|
||||
|
||||
---
|
||||
|
||||
#### 步骤1: 修改/创建Bean
|
||||
|
||||
**关键点**: 使用`ObservableBoolean`支持实时UI更新
|
||||
|
||||
```kotlin
|
||||
import androidx.databinding.ObservableBoolean
|
||||
|
||||
class GjcUldUseBean {
|
||||
// ... 业务字段 ...
|
||||
|
||||
// ========== UI扩展字段 ==========
|
||||
val checked: ObservableBoolean = ObservableBoolean(false) // 选中状态
|
||||
|
||||
// 兼容现有API的isSelected属性
|
||||
var isSelected: Boolean
|
||||
get() = checked.get()
|
||||
set(value) = checked.set(value)
|
||||
}
|
||||
```
|
||||
|
||||
**为什么用ObservableBoolean而不是Boolean?**
|
||||
- DataBinding会自动观察ObservableBoolean的变化
|
||||
- 调用`checked.set(true)`会立即触发UI刷新
|
||||
- 普通Boolean需要手动调用`notifyDataSetChanged()`
|
||||
|
||||
---
|
||||
|
||||
#### 步骤2: 定义API接口
|
||||
|
||||
```kotlin
|
||||
// Api.kt
|
||||
/**
|
||||
* 列表查询(分页)
|
||||
*/
|
||||
@POST("IntExpOutHandover/pageQuery")
|
||||
suspend fun getIntExpOutHandoverList(@Body data: RequestBody): BaseListBean<GjcUldUseBean>
|
||||
|
||||
/**
|
||||
* 统计查询(合计信息)
|
||||
*/
|
||||
@POST("IntExpOutHandover/pageQueryTotal")
|
||||
suspend fun getIntExpOutHandoverTotal(@Body data: RequestBody): BaseResultBean<ManifestTotalDto>
|
||||
|
||||
/**
|
||||
* 批量操作(交接完成)
|
||||
*/
|
||||
@POST("IntExpOutHandover/handover")
|
||||
suspend fun completeHandover(@Body data: RequestBody): BaseResultBean<Boolean>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### 步骤3: 创建ViewHolder
|
||||
|
||||
**关键点**: 添加选择图标点击事件
|
||||
|
||||
```kotlin
|
||||
class IntExpOutHandoverViewHolder(view: View) :
|
||||
BaseViewHolder<GjcUldUseBean, ItemIntExpOutHandoverBinding>(view) {
|
||||
|
||||
override fun onBind(item: Any?, position: Int) {
|
||||
val bean = getItemBean(item) ?: return
|
||||
binding.bean = bean
|
||||
binding.position = position
|
||||
binding.executePendingBindings()
|
||||
|
||||
// 添加图标点击事件 - 切换选择状态
|
||||
binding.ivIcon.setOnClickListener {
|
||||
// 反转checked状态
|
||||
bean.checked.set(!bean.checked.get())
|
||||
|
||||
// 立即更新UI (图片自动切换)
|
||||
binding.executePendingBindings()
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### 步骤4: 创建ViewModel
|
||||
|
||||
**关键点**: 继承`BasePageViewModel`,实现全选逻辑
|
||||
|
||||
```kotlin
|
||||
class IntExpOutHandoverViewModel : BasePageViewModel() {
|
||||
|
||||
// ========== 搜索条件 ==========
|
||||
val flightDate = MutableLiveData("")
|
||||
val flightNo = MutableLiveData("")
|
||||
val fdest = MutableLiveData("")
|
||||
val uldNo = MutableLiveData("")
|
||||
|
||||
// ========== 统计信息 ==========
|
||||
val totalCount = MutableLiveData("0")
|
||||
val totalPc = MutableLiveData("0")
|
||||
val totalWeight = MutableLiveData("0")
|
||||
|
||||
// ========== 全选状态 ==========
|
||||
val isAllChecked = MutableLiveData(false)
|
||||
|
||||
init {
|
||||
// 监听全选状态,自动更新所有列表项
|
||||
isAllChecked.observeForever { checked ->
|
||||
val list = pageModel.rv?.commonAdapter()?.items as? List<GjcUldUseBean> ?: return@observeForever
|
||||
list.forEach { it.checked.set(checked) }
|
||||
pageModel.rv?.commonAdapter()?.notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
|
||||
// ========== 适配器配置 ==========
|
||||
val itemViewHolder = IntExpOutHandoverViewHolder::class.java
|
||||
val itemLayoutId = R.layout.item_int_exp_out_handover
|
||||
|
||||
/**
|
||||
* 搜索按钮点击
|
||||
*/
|
||||
fun searchClick() {
|
||||
refresh()
|
||||
}
|
||||
|
||||
/**
|
||||
* 全选按钮点击 (切换全选状态)
|
||||
*/
|
||||
fun checkAllClick() {
|
||||
val list = pageModel.rv?.commonAdapter()?.items as? List<GjcUldUseBean> ?: return
|
||||
|
||||
// 切换全选状态
|
||||
val shouldCheckAll = !isAllChecked.value!!
|
||||
list.forEach { it.checked.set(shouldCheckAll) }
|
||||
isAllChecked.value = shouldCheckAll
|
||||
|
||||
pageModel.rv?.commonAdapter()?.notifyDataSetChanged()
|
||||
}
|
||||
|
||||
/**
|
||||
* 扫码ULD
|
||||
*/
|
||||
fun scanUld() {
|
||||
ScanModel.startScan(getTopActivity(), Constant.RequestCode.ULD)
|
||||
}
|
||||
|
||||
/**
|
||||
* 完成交接 (批量操作)
|
||||
*/
|
||||
fun completeHandover() {
|
||||
val list = pageModel.rv?.commonAdapter()?.items as? List<GjcUldUseBean> ?: return
|
||||
val selectedItems = list.filter { it.isSelected }
|
||||
|
||||
if (selectedItems.isEmpty()) {
|
||||
showToast("请选择要交接的ULD")
|
||||
return
|
||||
}
|
||||
|
||||
val requestData = selectedItems.toRequestBody()
|
||||
|
||||
launchLoadingCollect({ NetApply.api.completeHandover(requestData) }) {
|
||||
onSuccess = {
|
||||
showToast("交接完成")
|
||||
viewModelScope.launch {
|
||||
FlowBus.with<String>(ConstantEvent.EVENT_REFRESH).emit("refresh")
|
||||
}
|
||||
refresh()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取数据 (重写BasePageViewModel)
|
||||
*/
|
||||
override fun getData() {
|
||||
// 构建搜索条件
|
||||
val filterParams = mapOf(
|
||||
"fdate" to flightDate.value?.ifEmpty { null },
|
||||
"fno" to flightNo.value?.ifEmpty { null },
|
||||
"fdest" to fdest.value?.ifEmpty { null },
|
||||
"uld" to uldNo.value?.ifEmpty { null }
|
||||
)
|
||||
|
||||
// 列表参数 (含分页)
|
||||
val listParams = (filterParams + mapOf(
|
||||
"pageNum" to pageModel.page,
|
||||
"pageSize" to pageModel.limit
|
||||
)).toRequestBody()
|
||||
|
||||
// 统计参数 (无分页)
|
||||
val totalParams = filterParams.toRequestBody()
|
||||
|
||||
// 获取列表 (带Loading)
|
||||
launchLoadingCollect({ NetApply.api.getIntExpOutHandoverList(listParams) }) {
|
||||
onSuccess = { pageModel.handleListBean(it) }
|
||||
}
|
||||
|
||||
// 获取统计信息 (后台请求,不阻塞列表)
|
||||
launchCollect({ NetApply.api.getIntExpOutHandoverTotal(totalParams) }) {
|
||||
onSuccess = { result ->
|
||||
val data = result.data
|
||||
totalCount.value = (data?.wbNumber ?: 0).toString()
|
||||
totalPc.value = (data?.totalPc ?: 0).toString()
|
||||
totalWeight.value = (data?.totalWeight ?: 0.0).toString()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### 步骤5: 创建Activity布局
|
||||
|
||||
**关键要素**: 搜索区 + 列表 + 底部栏
|
||||
|
||||
```xml
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<!-- 标题栏 -->
|
||||
<include layout="@layout/title_tool_bar" />
|
||||
|
||||
<!-- 搜索区域 -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<!-- 航班日期 -->
|
||||
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
type="@{SearchLayoutType.DATE}"
|
||||
value="@={viewModel.flightDate}" />
|
||||
|
||||
<!-- 航班号 -->
|
||||
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
type="@{SearchLayoutType.INPUT}"
|
||||
value="@={viewModel.flightNo}" />
|
||||
|
||||
<!-- ULD编号 (带扫码) -->
|
||||
<com.lukouguoji.module_base.ui.weight.search.layout.PadSearchLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
type="@{SearchLayoutType.INPUT}"
|
||||
value="@={viewModel.uldNo}"
|
||||
icon="@{@drawable/scan_code}"
|
||||
setOnIconClickListener="@{(v)-> viewModel.scanUld()}" />
|
||||
|
||||
<!-- 搜索按钮 -->
|
||||
<ImageView
|
||||
style="@style/iv_search_action"
|
||||
android:onClick="@{()-> viewModel.searchClick()}"
|
||||
android:src="@drawable/img_search" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 列表 -->
|
||||
<com.scwang.smart.refresh.layout.SmartRefreshLayout
|
||||
android:id="@+id/srl"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rv"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
itemLayoutId="@{viewModel.itemLayoutId}"
|
||||
viewHolder="@{viewModel.itemViewHolder}" />
|
||||
|
||||
</com.scwang.smart.refresh.layout.SmartRefreshLayout>
|
||||
|
||||
<!-- 底部栏: 全选 + 统计 + 操作按钮 -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="50dp"
|
||||
android:background="@color/color_bottom_layout"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<!-- 全选按钮 (图标+文字) -->
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:onClick="@{()-> viewModel.checkAllClick()}">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/checkIcon"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:src="@drawable/img_check_all" />
|
||||
|
||||
<TextView
|
||||
android:text="全选"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="18sp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 统计信息 -->
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:text='@{"合计:"+viewModel.totalCount+"票"}'
|
||||
android:textColor="@color/white" />
|
||||
|
||||
<TextView
|
||||
android:text='@{"总件数:"+viewModel.totalPc}'
|
||||
android:textColor="@color/white" />
|
||||
|
||||
<TextView
|
||||
android:text='@{"总重量:"+viewModel.totalWeight}'
|
||||
android:textColor="@color/white" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 批量操作按钮 -->
|
||||
<TextView
|
||||
style="@style/tv_bottom_btn"
|
||||
android:onClick="@{()-> viewModel.completeHandover()}"
|
||||
android:text="交接完成" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### 步骤6: 创建列表项布局
|
||||
|
||||
**关键点**: 使用`completeSpace`属性实现Key左对齐
|
||||
|
||||
```xml
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/bg_white_radius_8"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<!-- 选中图标 (根据checked状态切换图片) -->
|
||||
<ImageView
|
||||
android:id="@+id/iv_icon"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
loadImage="@{bean.checked.get() ? @drawable/img_plane_s : @drawable/img_plane}"
|
||||
android:src="@drawable/img_plane" />
|
||||
|
||||
<!-- 数据展示区域 -->
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
|
||||
<!-- 第一行数据 -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<!-- ULD编号 (weight=1.5) -->
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1.5"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
completeSpace="@{5}"
|
||||
android:text="ULD编号:"
|
||||
android:textColor="@color/text_normal" />
|
||||
|
||||
<TextView
|
||||
android:text="@{bean.uld}"
|
||||
android:textColor="@color/colorPrimary"
|
||||
android:textStyle="bold" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 架子车号 (weight=1) -->
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
completeSpace="@{5}"
|
||||
android:text="架子车号:"
|
||||
android:textColor="@color/text_normal" />
|
||||
|
||||
<TextView
|
||||
android:text="@{String.valueOf(bean.carId)}"
|
||||
android:textColor="@color/text_normal" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 总重 (weight=1) -->
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
completeSpace="@{3}"
|
||||
android:text="总重:"
|
||||
android:textColor="@color/text_normal" />
|
||||
|
||||
<TextView
|
||||
android:text="@{String.valueOf((int)bean.totalWeight)}"
|
||||
android:textColor="@color/text_normal" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 装机重量 (weight=1) -->
|
||||
<!-- 货重 (weight=1.5) -->
|
||||
<!-- ... 其他字段 ... -->
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 第二行数据 -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<!-- 航班日期 (weight=1.5) -->
|
||||
<!-- 航班号 (weight=1) -->
|
||||
<!-- 目的港 (weight=1) -->
|
||||
<!-- 交接人 (weight=1) -->
|
||||
<!-- 交接时间 (weight=1.5) -->
|
||||
<!-- ... -->
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
```
|
||||
|
||||
**权重分配原则**:
|
||||
- 较长字段(如"ULD编号"、"交接时间")使用较大权重(1.5)
|
||||
- 较短字段(如"总重"、"航班号")使用较小权重(1.0)
|
||||
- `completeSpace`根据文字字数设置(3-5个字符宽度)
|
||||
|
||||
---
|
||||
|
||||
#### 步骤7: 创建Activity
|
||||
|
||||
```kotlin
|
||||
@Route(path = ARouterConstants.ACTIVITY_URL_INT_EXP_OUT_HANDOVER)
|
||||
class IntExpOutHandoverActivity :
|
||||
BaseBindingActivity<ActivityIntExpOutHandoverBinding, IntExpOutHandoverViewModel>() {
|
||||
|
||||
override fun layoutId() = R.layout.activity_int_exp_out_handover
|
||||
override fun viewModelClass() = IntExpOutHandoverViewModel::class.java
|
||||
|
||||
override fun initOnCreate(savedInstanceState: Bundle?) {
|
||||
setBackArrow("出库交接")
|
||||
binding.viewModel = viewModel
|
||||
|
||||
// 观察全选状态,更新图标透明度
|
||||
viewModel.isAllChecked.observe(this) { isAllChecked ->
|
||||
binding.checkIcon.alpha = if (isAllChecked) 1.0f else 0.5f
|
||||
}
|
||||
|
||||
// 绑定分页
|
||||
viewModel.pageModel.bindSmartRefreshLayout(binding.srl, binding.rv, viewModel, this)
|
||||
|
||||
// 设置item点击监听
|
||||
binding.rv.addOnItemClickListener(viewModel)
|
||||
|
||||
// 监听刷新事件
|
||||
FlowBus.with<String>(ConstantEvent.EVENT_REFRESH).observe(this) {
|
||||
viewModel.refresh()
|
||||
}
|
||||
|
||||
// 初始加载数据
|
||||
viewModel.refresh()
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
if (requestCode == Constant.RequestCode.ULD && resultCode == Activity.RESULT_OK) {
|
||||
viewModel.uldNo.value = data?.getStringExtra(Constant.Result.CODED_CONTENT)
|
||||
viewModel.searchClick()
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### 步骤8: 注册Activity
|
||||
|
||||
```xml
|
||||
<!-- app/src/main/AndroidManifest.xml -->
|
||||
<activity
|
||||
android:name="com.lukouguoji.gjc.activity.IntExpOutHandoverActivity"
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:exported="false"
|
||||
android:screenOrientation="userLandscape" />
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### 关键技术点总结
|
||||
|
||||
##### 1. ObservableBoolean vs Boolean
|
||||
|
||||
| 特性 | ObservableBoolean | Boolean |
|
||||
|------|------------------|---------|
|
||||
| DataBinding支持 | ✅ 自动观察 | ❌ 不支持 |
|
||||
| UI实时更新 | ✅ 调用set()自动刷新 | ❌ 需手动notifyDataSetChanged() |
|
||||
| 代码简洁性 | ✅ 更简洁 | ❌ 需额外代码 |
|
||||
|
||||
##### 2. 全选交互逻辑
|
||||
|
||||
```
|
||||
用户点击全选按钮
|
||||
↓
|
||||
checkAllClick() 被调用
|
||||
↓
|
||||
遍历列表,调用 bean.checked.set(shouldCheckAll)
|
||||
↓
|
||||
ObservableBoolean触发DataBinding更新
|
||||
↓
|
||||
列表项图片自动切换 (img_plane ↔ img_plane_s)
|
||||
```
|
||||
|
||||
##### 3. 图片资源切换
|
||||
|
||||
```xml
|
||||
<!-- loadImage 是自定义BindingAdapter -->
|
||||
loadImage="@{bean.checked.get() ? @drawable/img_plane_s : @drawable/img_plane}"
|
||||
```
|
||||
|
||||
**图片资源**:
|
||||
- `img_plane.png` - 未选中状态
|
||||
- `img_plane_s.png` - 已选中状态 (通常是高亮/彩色版本)
|
||||
- `img_check_all.png` - 全选图标
|
||||
|
||||
##### 4. completeSpace属性原理
|
||||
|
||||
`completeSpace`是自定义BindingAdapter,用于实现Key左对齐:
|
||||
|
||||
```kotlin
|
||||
// TextViewAdapter.kt
|
||||
@BindingAdapter("completeSpace")
|
||||
fun completeSpace(tv: TextView, count: Int) {
|
||||
// 1. 根据count个"一"字宽度设置TextView宽度
|
||||
val s = StringBuilder()
|
||||
(1..count).forEach { _ -> s.append("一") }
|
||||
val measureText = tv.paint.measureText(s.toString())
|
||||
ViewUtils.setWidth(tv, measureText.roundToInt())
|
||||
|
||||
// 2. 自动填充全角空格使文本均匀分布
|
||||
// 确保"航班日期:"与"航班号:"的冒号位置对齐
|
||||
}
|
||||
```
|
||||
|
||||
**使用示例**:
|
||||
- `completeSpace="@{5}"` - 5个"一"字宽度 (适合"ULD编号:"、"航班日期:")
|
||||
- `completeSpace="@{4}"` - 4个"一"字宽度 (适合"航班号:"、"交接人:")
|
||||
- `completeSpace="@{3}"` - 3个"一"字宽度 (适合"总重:"、"货重:")
|
||||
|
||||
##### 5. 分页处理
|
||||
|
||||
BasePageViewModel自动处理分页逻辑:
|
||||
- `pageModel.page` - 当前页码
|
||||
- `pageModel.limit` - 每页条数
|
||||
- `pageModel.handleListBean(it)` - 自动处理列表数据和分页状态
|
||||
|
||||
##### 6. 批量操作最佳实践
|
||||
|
||||
```kotlin
|
||||
fun completeHandover() {
|
||||
// 1. 获取列表
|
||||
val list = pageModel.rv?.commonAdapter()?.items as? List<GjcUldUseBean> ?: return
|
||||
|
||||
// 2. 过滤选中项
|
||||
val selectedItems = list.filter { it.isSelected }
|
||||
|
||||
// 3. 验证
|
||||
if (selectedItems.isEmpty()) {
|
||||
showToast("请选择要交接的ULD")
|
||||
return
|
||||
}
|
||||
|
||||
// 4. 转换为RequestBody
|
||||
val requestData = selectedItems.toRequestBody()
|
||||
|
||||
// 5. 发起请求
|
||||
launchLoadingCollect({ NetApply.api.completeHandover(requestData) }) {
|
||||
onSuccess = {
|
||||
showToast("交接完成")
|
||||
// 6. 发送刷新事件
|
||||
viewModelScope.launch {
|
||||
FlowBus.with<String>(ConstantEvent.EVENT_REFRESH).emit("refresh")
|
||||
}
|
||||
// 7. 刷新当前页
|
||||
refresh()
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### 常见错误与解决方案
|
||||
|
||||
##### 错误1: 点击图标不切换
|
||||
|
||||
```kotlin
|
||||
// ❌ 错误: 使用普通Boolean
|
||||
var isSelected: Boolean = false
|
||||
|
||||
// ✅ 正确: 使用ObservableBoolean
|
||||
val checked: ObservableBoolean = ObservableBoolean(false)
|
||||
```
|
||||
|
||||
##### 错误2: 全选不生效
|
||||
|
||||
```kotlin
|
||||
// ❌ 错误: 直接修改isSelected
|
||||
list.forEach { it.isSelected = checked }
|
||||
|
||||
// ✅ 正确: 调用ObservableBoolean的set方法
|
||||
list.forEach { it.checked.set(checked) }
|
||||
```
|
||||
|
||||
##### 错误3: 布局不对齐
|
||||
|
||||
```xml
|
||||
<!-- ❌ 错误: 直接拼接key和value -->
|
||||
<TextView android:text='@{"航班日期 " + bean.fdate}' />
|
||||
|
||||
<!-- ✅ 正确: 使用completeSpace属性 -->
|
||||
<LinearLayout>
|
||||
<TextView completeSpace="@{5}" android:text="航班日期:" />
|
||||
<TextView android:text="@{bean.fdate}" />
|
||||
</LinearLayout>
|
||||
```
|
||||
|
||||
##### 错误4: 忘记观察全选状态
|
||||
|
||||
```kotlin
|
||||
// ❌ 错误: 没有观察isAllChecked
|
||||
|
||||
// ✅ 正确: 在Activity中观察全选状态
|
||||
viewModel.isAllChecked.observe(this) { isAllChecked ->
|
||||
binding.checkIcon.alpha = if (isAllChecked) 1.0f else 0.5f
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### 参考示例
|
||||
|
||||
**完整实现参考**:
|
||||
- Activity: `module_gjc/src/main/java/com/lukouguoji/gjc/activity/IntExpOutHandoverActivity.kt`
|
||||
- ViewModel: `module_gjc/src/main/java/com/lukouguoji/gjc/viewModel/IntExpOutHandoverViewModel.kt`
|
||||
- ViewHolder: `module_gjc/src/main/java/com/lukouguoji/gjc/holder/IntExpOutHandoverViewHolder.kt`
|
||||
- Activity布局: `module_gjc/src/main/res/layout/activity_int_exp_out_handover.xml`
|
||||
- Item布局: `module_gjc/src/main/res/layout/item_int_exp_out_handover.xml`
|
||||
- Bean: `module_base/src/main/java/com/lukouguoji/module_base/bean/GjcUldUseBean.kt`
|
||||
|
||||
**其他类似实现**:
|
||||
- `GjcAssembleAllocateActivity` - 国际出港组装分配
|
||||
|
||||
---
|
||||
|
||||
### 常见业务场景
|
||||
|
||||
#### 扫码
|
||||
|
||||
Reference in New Issue
Block a user