refactor(swipe): 迁移侧滑删除至 SwipeRecyclerView,移除 SwipeRevealLayout
- 新增 SwipeRecyclerView.aar 及使用说明文档 - 删除 SwipeRevealLayout.java / ViewBinderHelper.java - DishListFragment、SamplingModeActivity、PrepareFoodActivity 改用 setSwipeMenuCreator API - FoodListAdapter、DishPartAdapter 移除 ViewBinderHelper 侧滑状态管理代码 - 布局文件将 RecyclerView 替换为 SwipeRecyclerView,item 布局移除 SwipeRevealLayout 根节点
This commit is contained in:
@@ -0,0 +1,356 @@
|
|||||||
|
# SwipeRecyclerView
|
||||||
|
|
||||||
|
作者的主页:[https://www.yanzhenjie.com](https://www.yanzhenjie.com)
|
||||||
|
技术交流群:[46505645](https://jq.qq.com/?_wv=1027&k=5wY8UWl)
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
本库是基于RecyclerView的封装,提供了Item侧滑菜单、Item滑动删除、Item长按拖拽、添加HeaderView/FooterView、加载更多、Item点击监听等基本功能。
|
||||||
|
|
||||||
|
## 特性
|
||||||
|
1. Item侧滑菜单,支持水平分布、垂直分布
|
||||||
|
2. Item长按拖拽、侧滑删除
|
||||||
|
3. 添加/移除HeaderView/FooterView
|
||||||
|
4. **自动/点击**加载更多的功能
|
||||||
|
5. 支持二级列表,List形式、Grid形式、Staggered形式
|
||||||
|
6. Sticky普通布局黏贴和ReyclerView分组黏贴
|
||||||
|
7. 支持AndroidX
|
||||||
|
|
||||||
|
> 使用本库只需要使用SwipeRecyclerView即可,用法和原生RecyclerView一模一样,本库比原生的RecyclerView多了几个扩展方法。
|
||||||
|
|
||||||
|
## 截图
|
||||||
|
对上面提到的效果基本都有演示,但不是全部,更多效果可以下载Demo查看。
|
||||||
|
|
||||||
|
### Item侧滑菜单
|
||||||
|
<img src="./image/1.gif" width="180px"/> <img src="./image/2.gif" width="180px"/> <img src="./image/3.gif" width="180px"/>
|
||||||
|
|
||||||
|
### Item侧滑删除、拖拽
|
||||||
|
<img src="./image/4.gif" width="180px"/> <img src="./image/5.gif" width="180px"/> <img src="./image/6.gif" width="180px"/>
|
||||||
|
|
||||||
|
### 下拉刷新和加载更多
|
||||||
|
<img src="./image/7.gif" width="180px"/>
|
||||||
|
|
||||||
|
### HeaderView和FooterView
|
||||||
|
<img src="./image/8.gif" width="180px"/>
|
||||||
|
|
||||||
|
### Sticky效果和Item分组
|
||||||
|
<img src="./image/9.gif" width="180px"/> <img src="./image/10.gif" width="180px"/>
|
||||||
|
|
||||||
|
### 和DrawerLayout嵌套
|
||||||
|
<img src="./image/11.gif" width="180px"/>
|
||||||
|
|
||||||
|
## 如何使用
|
||||||
|
如果你使用的是android support库,那么请添加下述依赖:
|
||||||
|
```groovy
|
||||||
|
implementation 'com.yanzhenjie.recyclerview:support:1.3.2'
|
||||||
|
```
|
||||||
|
|
||||||
|
如果你使用的是android x库,那么请添加下述依赖:
|
||||||
|
```groovy
|
||||||
|
implementation 'com.yanzhenjie.recyclerview:x:1.3.2'
|
||||||
|
```
|
||||||
|
|
||||||
|
> **1. SwipeRecyclerView从1.3.0版本开始支持AndroidX和二级列表,因此相对于低版本的包名和类名有所改动,从低版本升级的开发者需要考量是否要升级。**
|
||||||
|
**2. 为了让开发者方便切换support库和x库,SwipeRecyclerView的support库和x库除了依赖时的名称不一样外,包名、控件名和类名都是一样的,因此两个库不能共存。**
|
||||||
|
|
||||||
|
### 加入布局
|
||||||
|
在布局的xml中加入`SwipeRecyclerView`:
|
||||||
|
```xml
|
||||||
|
<com.yanzhenjie.recyclerview.SwipeRecyclerView
|
||||||
|
.../>
|
||||||
|
```
|
||||||
|
|
||||||
|
### ItemDecoration
|
||||||
|
也就是分割线,支持Grid形式和Linear形式,可以选择某个ViewType不画分割线:
|
||||||
|
```java
|
||||||
|
// 默认构造,传入颜色即可。
|
||||||
|
ItemDecoration itemDecoration = new DefaultDecoration(color);
|
||||||
|
|
||||||
|
// 或者:颜色,宽,高,最后一个参数是不画分割线的ViewType,可以传入多个。
|
||||||
|
itemDecoration = new DefaultDecoration(color, width, height, excludeViewType);
|
||||||
|
|
||||||
|
// 或者:例如下面的123都是不画分割线的ViewType:
|
||||||
|
itemDecoration = new DefaultDecoration(color, width, height, 1, 2, 3);
|
||||||
|
|
||||||
|
SwipeRecyclerView recyclerView = ...;
|
||||||
|
recyclerView.setDecoration(itemDecoration);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Item点击监听
|
||||||
|
```java
|
||||||
|
recyclerView.setOnItemClickListener(new OnItemClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onItemClick(View view, int position) {
|
||||||
|
// TODO...
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### 侧滑菜单
|
||||||
|
```java
|
||||||
|
// 设置监听器。
|
||||||
|
swipeRecyclerView.setSwipeMenuCreator(mSwipeMenuCreator);
|
||||||
|
|
||||||
|
// 创建菜单:
|
||||||
|
SwipeMenuCreator mSwipeMenuCreator = new SwipeMenuCreator() {
|
||||||
|
@Override
|
||||||
|
public void onCreateMenu(SwipeMenu leftMenu, SwipeMenu rightMenu, int position) {
|
||||||
|
SwipeMenuItem deleteItem = new SwipeMenuItem(mContext)
|
||||||
|
...; // 各种文字和图标属性设置。
|
||||||
|
leftMenu.addMenuItem(deleteItem); // 在Item左侧添加一个菜单。
|
||||||
|
|
||||||
|
SwipeMenuItem deleteItem = new SwipeMenuItem(mContext)
|
||||||
|
...; // 各种文字和图标属性设置。
|
||||||
|
leftMenu.addMenuItem(deleteItem); // 在Item右侧添加一个菜单。
|
||||||
|
|
||||||
|
// 注意:哪边不想要菜单,那么不要添加即可。
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 菜单点击监听。
|
||||||
|
swipeRecyclerView.setOnItemMenuClickListener(mItemMenuClickListener);
|
||||||
|
|
||||||
|
OnItemMenuClickListener mItemMenuClickListener = new OnItemMenuClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onItemClick(SwipeMenuBridge menuBridge, int position) {
|
||||||
|
// 任何操作必须先关闭菜单,否则可能出现Item菜单打开状态错乱。
|
||||||
|
menuBridge.closeMenu();
|
||||||
|
|
||||||
|
// 左侧还是右侧菜单:
|
||||||
|
int direction = menuBridge.getDirection();
|
||||||
|
// 菜单在Item中的Position:
|
||||||
|
int menuPosition = menuBridge.getPosition();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
**注意**:菜单需要设置高度,关于菜单高度:
|
||||||
|
1. `MATCH_PARENT`,自动适应Item高度,保持和Item一样高,比较推荐;
|
||||||
|
2. 指定具体的高,比如80;
|
||||||
|
3. `WRAP_CONTENT`,自身高度,极不推荐;
|
||||||
|
|
||||||
|
### 侧滑删除和拖拽
|
||||||
|
拖拽和侧滑删除的功能默认关闭的,所以先要打开功能:
|
||||||
|
```java
|
||||||
|
recyclerView.setLongPressDragEnabled(true); // 拖拽排序,默认关闭。
|
||||||
|
recyclerView.setItemViewSwipeEnabled(true); // 侧滑删除,默认关闭。
|
||||||
|
```
|
||||||
|
|
||||||
|
只需要设置上面两个属性就可以进行相应的动作了,如果不需要哪个,不要打开就可以了。
|
||||||
|
|
||||||
|
然后监听拖拽和侧滑的动作,进行数据更新:
|
||||||
|
```java
|
||||||
|
recyclerView.setOnItemMoveListener(mItemMoveListener);// 监听拖拽,更新UI。
|
||||||
|
|
||||||
|
OnItemMoveListener mItemMoveListener = new OnItemMoveListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onItemMove(ViewHolder srcHolder, ViewHolder targetHolder) {
|
||||||
|
// 此方法在Item拖拽交换位置时被调用。
|
||||||
|
// 第一个参数是要交换为之的Item,第二个是目标位置的Item。
|
||||||
|
|
||||||
|
// 交换数据,并更新adapter。
|
||||||
|
int fromPosition = srcHolder.getAdapterPosition();
|
||||||
|
int toPosition = targetHolder.getAdapterPosition();
|
||||||
|
Collections.swap(mDataList, fromPosition, toPosition);
|
||||||
|
adapter.notifyItemMoved(fromPosition, toPosition);
|
||||||
|
|
||||||
|
// 返回true,表示数据交换成功,ItemView可以交换位置。
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onItemDismiss(ViewHolder srcHolder) {
|
||||||
|
// 此方法在Item在侧滑删除时被调用。
|
||||||
|
|
||||||
|
// 从数据源移除该Item对应的数据,并刷新Adapter。
|
||||||
|
int position = srcHolder.getAdapterPosition();
|
||||||
|
mDataList.remove(position);
|
||||||
|
adapter.notifyItemRemoved(position);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
**特别注意**:如果`LayoutManager`是`List`形式,那么Item拖拽时只能从1-2-3-4这样走,如果你的`LayoutManager`是`Grid`形式的,那么Item可以从1直接到3或者5或者6...,这样数据就会错乱,所以**当`LayoutManager`是Grid形式时**这里要特别注意转换数据位置的算法:
|
||||||
|
```java
|
||||||
|
@Override
|
||||||
|
public boolean onItemMove(ViewHolder srcHolder, ViewHolder targetHolder) {
|
||||||
|
int fromPosition = srcHolder.getAdapterPosition();
|
||||||
|
int toPosition = targetHolder.getAdapterPosition();
|
||||||
|
if (fromPosition < toPosition) {
|
||||||
|
for (int i = fromPosition; i < toPosition; i++) {
|
||||||
|
Collections.swap(mDataList, i, i + 1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int i = fromPosition; i > toPosition; i--) {
|
||||||
|
Collections.swap(mDataList, i, i - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mMenuAdapter.notifyItemMoved(fromPosition, toPosition);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
我们还可以监听用户的侧滑删除和拖拽Item时的手指状态:
|
||||||
|
```java
|
||||||
|
recyclerView.setOnItemStateChangedListener(mStateChangedListener);
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
private OnItemStateChangedListener mStateChangedListener = (viewHolder, actionState) -> {
|
||||||
|
if (actionState == OnItemStateChangedListener.ACTION_STATE_DRAG) {
|
||||||
|
// 状态:正在拖拽。
|
||||||
|
} else if (actionState == OnItemStateChangedListener.ACTION_STATE_SWIPE) {
|
||||||
|
// 状态:滑动删除。
|
||||||
|
} else if (actionState == OnItemStateChangedListener.ACTION_STATE_IDLE) {
|
||||||
|
// 状态:手指松开。
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
想用户触摸到某个`Item`时就开始拖拽或者侧滑删除时,只需要调用`startDrag()`和`startSwipe()`并转入当前`Item`的`ViewHoler`即可。
|
||||||
|
|
||||||
|
触摸拖拽:
|
||||||
|
```java
|
||||||
|
swipeRecyclerView.startDrag(ViewHolder);
|
||||||
|
```
|
||||||
|
|
||||||
|
触摸侧滑删除:
|
||||||
|
```java
|
||||||
|
swipeRecyclerView.startSwipe(ViewHolder);
|
||||||
|
```
|
||||||
|
|
||||||
|
### HeaderView和FooterView
|
||||||
|
主要方法:
|
||||||
|
```java
|
||||||
|
addHeaderView(View); // 添加HeaderView。
|
||||||
|
removeHeaderView(View); // 移除HeaderView。
|
||||||
|
addFooterView(View); // 添加FooterView。
|
||||||
|
removeFooterView(View); // 移除FooterView。
|
||||||
|
getHeaderItemCount(); // 获取HeaderView个数。
|
||||||
|
getFooterItemCount(); // 获取FooterView个数。
|
||||||
|
getItemViewType(int); // 获取Item的ViewType,包括HeaderView、FooterView、普通ItemView。
|
||||||
|
```
|
||||||
|
添加/移除`HeaderView`/`FooterView`和`setAdapter()`的调用不分先后顺序。
|
||||||
|
|
||||||
|
**特别注意**:
|
||||||
|
1. 如果添加了`HeaderView`,凡是通过`ViewHolder`拿到的`position`都要减掉`HeaderView`的数量才能得到正确的`position`。
|
||||||
|
|
||||||
|
### 加载更多
|
||||||
|
本库默认提供了加载更多的动画和View,开发者也可以自定义,默认支持`RecyclerView`自带的三种布局管理器。
|
||||||
|
|
||||||
|
默认加载更多:
|
||||||
|
```java
|
||||||
|
RecyclerView recyclerView = ...;
|
||||||
|
...
|
||||||
|
|
||||||
|
recyclerView.useDefaultLoadMore(); // 使用默认的加载更多的View。
|
||||||
|
recyclerView.setLoadMoreListener(mLoadMoreListener); // 加载更多的监听。
|
||||||
|
|
||||||
|
LoadMoreListener mLoadMoreListener = new LoadMoreListener() {
|
||||||
|
@Override
|
||||||
|
public void onLoadMore() {
|
||||||
|
// 该加载更多啦。
|
||||||
|
|
||||||
|
... // 请求数据,并更新数据源操作。
|
||||||
|
mMainAdapter.notifyDataSetChanged();
|
||||||
|
|
||||||
|
// 数据完更多数据,一定要调用这个方法。
|
||||||
|
// 第一个参数:表示此次数据是否为空。
|
||||||
|
// 第二个参数:表示是否还有更多数据。
|
||||||
|
mRecyclerView.loadMoreFinish(false, true);
|
||||||
|
|
||||||
|
// 如果加载失败调用下面的方法,传入errorCode和errorMessage。
|
||||||
|
// errorCode随便传,你自定义LoadMoreView时可以根据errorCode判断错误类型。
|
||||||
|
// errorMessage是会显示到loadMoreView上的,用户可以看到。
|
||||||
|
// mRecyclerView.loadMoreError(0, "请求网络失败");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
自定义加载更多View也很简单,自定义一个View,并实现一个接口即可:
|
||||||
|
```java
|
||||||
|
public class DefineLoadMoreView extends LinearLayout
|
||||||
|
implements SwipeRecyclerView.LoadMoreView,
|
||||||
|
View.OnClickListener {
|
||||||
|
|
||||||
|
private LoadMoreListener mLoadMoreListener;
|
||||||
|
|
||||||
|
public DefineLoadMoreView(Context context) {
|
||||||
|
super(context);
|
||||||
|
...
|
||||||
|
setOnClickListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 马上开始回调加载更多了,这里应该显示进度条。
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void onLoading() {
|
||||||
|
// 展示加载更多的动画和提示信息。
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加载更多完成了。
|
||||||
|
*
|
||||||
|
* @param dataEmpty 是否请求到空数据。
|
||||||
|
* @param hasMore 是否还有更多数据等待请求。
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void onLoadFinish(boolean dataEmpty, boolean hasMore) {
|
||||||
|
// 根据参数,显示没有数据的提示、没有更多数据的提示。
|
||||||
|
// 如果都不存在,则都不用显示。
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加载出错啦,下面的错误码和错误信息二选一。
|
||||||
|
*
|
||||||
|
* @param errorCode 错误码。
|
||||||
|
* @param errorMessage 错误信息。
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void onLoadError(int errorCode, String errorMessage) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 调用了setAutoLoadMore(false)后,在需要加载更多的时候,此方法被调用,并传入listener。
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void onWaitToLoadMore(SwipeRecyclerView.LoadMoreListener loadMoreListener) {
|
||||||
|
this.mLoadMoreListener = loadMoreListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 非自动加载更多时mLoadMoreListener才不为空。
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
if (mLoadMoreListener != null) mLoadMoreListener.onLoadMore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 感谢与参考
|
||||||
|
* [cube-sdk](https://github.com/liaohuqiu/cube-sdk)
|
||||||
|
* [SwipeMenu](https://github.com/TUBB/SwipeMenu/)
|
||||||
|
* [HeaderAndFooterWrapper](https://github.com/hongyangAndroid/baseAdapter/blob/master/baseadapter-recyclerview/src/main/java/com/zhy/adapter/recyclerview/wrapper/HeaderAndFooterWrapper.java)
|
||||||
|
|
||||||
|
加载更多的灵感来自`cube-sdk`,侧滑菜单参考了`SwipeMenu`,添加`HeaderView`参考了`HeaderAndFooterWrapper`类,特别感谢上述开源库及其作者。
|
||||||
|
|
||||||
|
## License
|
||||||
|
```text
|
||||||
|
Copyright 2019 Zhenjie Yan
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
```
|
||||||
Binary file not shown.
@@ -12,22 +12,13 @@ import com.shuwei.dish.match.entity.CookFoodGoodsEntity
|
|||||||
import com.shuwei.dish.match.utils.ext.gone
|
import com.shuwei.dish.match.utils.ext.gone
|
||||||
import com.shuwei.dish.match.utils.ext.roundedOneDecimalPlace
|
import com.shuwei.dish.match.utils.ext.roundedOneDecimalPlace
|
||||||
import com.shuwei.dish.match.utils.ext.visible
|
import com.shuwei.dish.match.utils.ext.visible
|
||||||
import com.shuwei.dish.match.view.swipereveallayout.ViewBinderHelper
|
|
||||||
|
|
||||||
class DishPartAdapter(list: MutableList<CookFoodGoodsEntity>) :
|
class DishPartAdapter(list: MutableList<CookFoodGoodsEntity>) :
|
||||||
BaseQuickAdapter<CookFoodGoodsEntity, DishPartAdapter.VH>(list) {
|
BaseQuickAdapter<CookFoodGoodsEntity, DishPartAdapter.VH>(list) {
|
||||||
|
|
||||||
var onDeleteClick: ((position: Int) -> Unit)? = null
|
/** item 主体点击回调 */
|
||||||
var onItemClick: ((position: Int) -> Unit)? = null
|
var onItemClick: ((position: Int) -> Unit)? = null
|
||||||
|
|
||||||
private val viewBinderHelper = ViewBinderHelper().apply {
|
|
||||||
setOpenOnlyOne(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun closeAll() {
|
|
||||||
viewBinderHelper.closeAll()
|
|
||||||
}
|
|
||||||
|
|
||||||
inner class VH(var binding: ListItemDishCookBinding) : QuickViewHolder(binding.root)
|
inner class VH(var binding: ListItemDishCookBinding) : QuickViewHolder(binding.root)
|
||||||
|
|
||||||
override fun onCreateViewHolder(context: Context, parent: ViewGroup, viewType: Int): VH {
|
override fun onCreateViewHolder(context: Context, parent: ViewGroup, viewType: Int): VH {
|
||||||
@@ -39,16 +30,7 @@ class DishPartAdapter(list: MutableList<CookFoodGoodsEntity>) :
|
|||||||
override fun onBindViewHolder(holder: VH, position: Int, item: CookFoodGoodsEntity?) {
|
override fun onBindViewHolder(holder: VH, position: Int, item: CookFoodGoodsEntity?) {
|
||||||
holder.binding.run {
|
holder.binding.run {
|
||||||
val data = item ?: return
|
val data = item ?: return
|
||||||
val itemId = data.goodsId ?: "${position}_${data.goodsName ?: ""}"
|
|
||||||
viewBinderHelper.bind(swipeRevealLayout, itemId)
|
|
||||||
// 暂时禁用侧滑能力,后续需要放开时改回 unlockSwipe + layoutDelete.visible()
|
|
||||||
viewBinderHelper.lockSwipe(itemId)
|
|
||||||
swipeRevealLayout.close(false)
|
|
||||||
layoutDelete.gone()
|
|
||||||
|
|
||||||
layoutDelete.setOnClickListener {
|
|
||||||
onDeleteClick?.invoke(holder.bindingAdapterPosition)
|
|
||||||
}
|
|
||||||
clBlock.setOnClickListener {
|
clBlock.setOnClickListener {
|
||||||
onItemClick?.invoke(holder.bindingAdapterPosition)
|
onItemClick?.invoke(holder.bindingAdapterPosition)
|
||||||
}
|
}
|
||||||
@@ -76,12 +58,10 @@ class DishPartAdapter(list: MutableList<CookFoodGoodsEntity>) :
|
|||||||
if (data.isSetFinished) R.drawable.ic_dish_selected
|
if (data.isSetFinished) R.drawable.ic_dish_selected
|
||||||
else R.drawable.ic_dish_unselected
|
else R.drawable.ic_dish_unselected
|
||||||
)
|
)
|
||||||
clBlock.run {
|
clBlock.setBackgroundResource(
|
||||||
setBackgroundResource(
|
|
||||||
if (data.isItemClicked) R.drawable.shape_item_cook_dish
|
if (data.isItemClicked) R.drawable.shape_item_cook_dish
|
||||||
else R.drawable.shape_white_fb_15_corners
|
else R.drawable.shape_white_fb_15_corners
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -9,7 +9,6 @@ import com.chad.library.adapter4.viewholder.QuickViewHolder
|
|||||||
import com.shuwei.dish.match.R
|
import com.shuwei.dish.match.R
|
||||||
import com.shuwei.dish.match.databinding.ListItemFoodListBinding
|
import com.shuwei.dish.match.databinding.ListItemFoodListBinding
|
||||||
import com.shuwei.dish.match.entity.FoodRecord
|
import com.shuwei.dish.match.entity.FoodRecord
|
||||||
import com.shuwei.dish.match.view.swipereveallayout.ViewBinderHelper
|
|
||||||
import com.shuwei.dish.match.utils.ext.gone
|
import com.shuwei.dish.match.utils.ext.gone
|
||||||
import com.shuwei.dish.match.utils.ext.visible
|
import com.shuwei.dish.match.utils.ext.visible
|
||||||
import java.text.DecimalFormat
|
import java.text.DecimalFormat
|
||||||
@@ -35,35 +34,16 @@ class FoodListAdapter(
|
|||||||
SAMPLING_MODE
|
SAMPLING_MODE
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 删除按钮点击回调,由外部(Activity/Fragment)设置 */
|
/** item 主体点击回调 */
|
||||||
var onDeleteClick: ((position: Int) -> Unit)? = null
|
|
||||||
|
|
||||||
/**
|
|
||||||
* item 主体点击回调,绑定在 mainView(clBlock)上,绕过 SwipeRevealLayout 的触摸拦截。
|
|
||||||
* 外部使用此回调替代 setOnDebouncedItemClick。
|
|
||||||
*/
|
|
||||||
var onItemClick: ((position: Int) -> Unit)? = null
|
var onItemClick: ((position: Int) -> Unit)? = null
|
||||||
|
|
||||||
/**
|
|
||||||
* ViewBinderHelper 负责:
|
|
||||||
* - 同一时间只允许一个 item 展开(setOpenOnlyOne)
|
|
||||||
* - RecyclerView 复用时恢复开合状态
|
|
||||||
*/
|
|
||||||
private val viewBinderHelper = ViewBinderHelper().apply {
|
|
||||||
setOpenOnlyOne(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 关闭所有已展开的侧滑 item,供外部在点击空白区域时调用 */
|
|
||||||
fun closeAll() {
|
|
||||||
viewBinderHelper.closeAll()
|
|
||||||
}
|
|
||||||
|
|
||||||
inner class VH(var binding: ListItemFoodListBinding) : QuickViewHolder(binding.root)
|
inner class VH(var binding: ListItemFoodListBinding) : QuickViewHolder(binding.root)
|
||||||
|
|
||||||
override fun onCreateViewHolder(context: Context, parent: ViewGroup, viewType: Int): VH {
|
override fun onCreateViewHolder(context: Context, parent: ViewGroup, viewType: Int): VH {
|
||||||
val binding = ListItemFoodListBinding.inflate(LayoutInflater.from(context), parent, false)
|
val binding = ListItemFoodListBinding.inflate(LayoutInflater.from(context), parent, false)
|
||||||
return VH(binding)
|
return VH(binding)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* - 烹饪中:黑色文字、实线背景、显示"烹饪中"
|
* - 烹饪中:黑色文字、实线背景、显示"烹饪中"
|
||||||
* - 有累计重量:绿色文字、实线背景、显示累计统计
|
* - 有累计重量:绿色文字、实线背景、显示累计统计
|
||||||
@@ -75,36 +55,12 @@ class FoodListAdapter(
|
|||||||
val totalWeight = item.totalWeight ?: 0.0
|
val totalWeight = item.totalWeight ?: 0.0
|
||||||
val foodWeight = item.foodWeight ?: 0.0
|
val foodWeight = item.foodWeight ?: 0.0
|
||||||
|
|
||||||
// 用 foodId 作为唯一 key 恢复开合状态;不可滑动时锁定
|
|
||||||
val itemId = item.foodId ?: position.toString()
|
|
||||||
viewBinderHelper.bind(swipeRevealLayout, itemId)
|
|
||||||
if (isCooking) {
|
|
||||||
viewBinderHelper.unlockSwipe(itemId)
|
|
||||||
layoutDelete.visible()
|
|
||||||
} else {
|
|
||||||
viewBinderHelper.lockSwipe(itemId)
|
|
||||||
// 非烹饪中不允许侧滑,关闭可能的复用残留状态并隐藏删除按钮
|
|
||||||
swipeRevealLayout.close(false)
|
|
||||||
layoutDelete.gone()
|
|
||||||
}
|
|
||||||
// 绑定删除按钮回调
|
|
||||||
layoutDelete.setOnClickListener { onDeleteClick?.invoke(holder.bindingAdapterPosition) }
|
|
||||||
// 点击主内容区域:
|
|
||||||
// 1) 非烹饪中:先收起所有侧滑,再继续触发点击
|
|
||||||
// 2) 烹饪中:当前 item 若已展开则只收起,不触发点击
|
|
||||||
clBlock.setOnClickListener {
|
clBlock.setOnClickListener {
|
||||||
if (!isCooking) {
|
|
||||||
viewBinderHelper.closeAll()
|
|
||||||
onItemClick?.invoke(holder.bindingAdapterPosition)
|
onItemClick?.invoke(holder.bindingAdapterPosition)
|
||||||
} else if (!swipeRevealLayout.isClosed) {
|
|
||||||
viewBinderHelper.closeAll()
|
|
||||||
} else {
|
|
||||||
onItemClick?.invoke(holder.bindingAdapterPosition)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tvDishName.text = item.foodName
|
tvDishName.text = item.foodName
|
||||||
//烹饪中
|
// 烹饪中
|
||||||
if (isCooking) {
|
if (isCooking) {
|
||||||
tvDishName.setTextColor(ContextCompat.getColor(holder.itemView.context, R.color.black))
|
tvDishName.setTextColor(ContextCompat.getColor(holder.itemView.context, R.color.black))
|
||||||
clBlock.setBackgroundResource(R.drawable.shape_white_fb_15_corners)
|
clBlock.setBackgroundResource(R.drawable.shape_white_fb_15_corners)
|
||||||
@@ -113,7 +69,7 @@ class FoodListAdapter(
|
|||||||
tvShowState.text = "烹饪中"
|
tvShowState.text = "烹饪中"
|
||||||
return@run
|
return@run
|
||||||
}
|
}
|
||||||
//非烹饪中,制作模式
|
// 非烹饪中,制作模式
|
||||||
if (mode == DisplayMode.COOKING_MODE) {
|
if (mode == DisplayMode.COOKING_MODE) {
|
||||||
if (totalWeight > 0.0) {
|
if (totalWeight > 0.0) {
|
||||||
tvDishName.setTextColor(ContextCompat.getColor(holder.itemView.context, R.color.dish_green))
|
tvDishName.setTextColor(ContextCompat.getColor(holder.itemView.context, R.color.dish_green))
|
||||||
@@ -129,7 +85,7 @@ class FoodListAdapter(
|
|||||||
}
|
}
|
||||||
return@run
|
return@run
|
||||||
}
|
}
|
||||||
//非烹饪中,采样模式
|
// 非烹饪中,采样模式
|
||||||
val realTotalWeight = if (totalWeight > 0.0) totalWeight else foodWeight
|
val realTotalWeight = if (totalWeight > 0.0) totalWeight else foodWeight
|
||||||
val showTotalWeight = if (realTotalWeight == 0.0) "-" else df.format(realTotalWeight / 1000.0F)
|
val showTotalWeight = if (realTotalWeight == 0.0) "-" else df.format(realTotalWeight / 1000.0F)
|
||||||
tvDishCount.text = "累计统计:${showTotalWeight}kg(${item.count ?: "-"}次)"
|
tvDishCount.text = "累计统计:${showTotalWeight}kg(${item.count ?: "-"}次)"
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import com.shuwei.dish.match.utils.ext.startActivity
|
|||||||
import com.shuwei.dish.match.utils.ext.toJsonString
|
import com.shuwei.dish.match.utils.ext.toJsonString
|
||||||
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
|
||||||
|
import com.yanzhenjie.recyclerview.SwipeMenuItem
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
@@ -359,22 +360,6 @@ class PrepareFoodActivity : BaseActivity() {
|
|||||||
}
|
}
|
||||||
notifyDataSetChanged()
|
notifyDataSetChanged()
|
||||||
}
|
}
|
||||||
onDeleteClick = onDeleteClick@{ positon ->
|
|
||||||
Log.d(TAG, "onFoodItemClick: ${list[positon].toJsonString()}")
|
|
||||||
if (list[positon].isNewDishType.not()) {
|
|
||||||
toast("只能删除刚添加的食材")
|
|
||||||
return@onDeleteClick
|
|
||||||
}
|
|
||||||
CommonDialog(this@PrepareFoodActivity)
|
|
||||||
.setTitle("删除确认")
|
|
||||||
.setContent("确定删除食材「${list[positon].goodsName}」吗?")
|
|
||||||
.setNegativeButton("取消")
|
|
||||||
.setPositiveButton("删除") {
|
|
||||||
adapter.removeAt(positon)
|
|
||||||
toast("已删除")
|
|
||||||
}
|
|
||||||
.show()
|
|
||||||
}
|
|
||||||
addOnItemChildClickListener(R.id.ivClearIcon) { _, _, positon ->
|
addOnItemChildClickListener(R.id.ivClearIcon) { _, _, positon ->
|
||||||
Log.d(TAG, "onFoodItemClick: ${list[positon].toJsonString()}")
|
Log.d(TAG, "onFoodItemClick: ${list[positon].toJsonString()}")
|
||||||
if (list[positon].isOriginalData) {
|
if (list[positon].isOriginalData) {
|
||||||
@@ -398,21 +383,52 @@ class PrepareFoodActivity : BaseActivity() {
|
|||||||
binding.rvDishPartList.run {
|
binding.rvDishPartList.run {
|
||||||
layoutManager =
|
layoutManager =
|
||||||
LinearLayoutManager(this@PrepareFoodActivity, LinearLayoutManager.VERTICAL, false)
|
LinearLayoutManager(this@PrepareFoodActivity, LinearLayoutManager.VERTICAL, false)
|
||||||
|
// 仅 isNewDishType=true 的 item 显示侧滑删除菜单(必须在 setAdapter 之前调用)
|
||||||
|
setSwipeMenuCreator { _, rightMenu, position ->
|
||||||
|
if (list.getOrNull(position)?.isNewDishType == true) {
|
||||||
|
rightMenu.addMenuItem(buildDeleteMenuItem())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 点击侧滑菜单项:先关闭菜单,再弹窗确认删除
|
||||||
|
setOnItemMenuClickListener { menuBridge, position ->
|
||||||
|
menuBridge.closeMenu()
|
||||||
|
val item = list.getOrNull(position) ?: return@setOnItemMenuClickListener
|
||||||
|
CommonDialog(this@PrepareFoodActivity)
|
||||||
|
.setTitle("删除确认")
|
||||||
|
.setContent("确定删除食材「${item.goodsName}」吗?")
|
||||||
|
.setNegativeButton("取消")
|
||||||
|
.setPositiveButton("删除") {
|
||||||
|
dishPartAdapter.removeAt(position)
|
||||||
|
toast("已删除")
|
||||||
|
}.show()
|
||||||
|
}
|
||||||
|
// item 点击事件
|
||||||
|
setOnItemClickListener { _, position ->
|
||||||
|
dishPartAdapter.onItemClick?.invoke(position)
|
||||||
|
}
|
||||||
adapter = dishPartAdapter
|
adapter = dishPartAdapter
|
||||||
addOnItemTouchListener(object : androidx.recyclerview.widget.RecyclerView.SimpleOnItemTouchListener() {
|
|
||||||
override fun onInterceptTouchEvent(
|
|
||||||
rv: androidx.recyclerview.widget.RecyclerView,
|
|
||||||
e: android.view.MotionEvent
|
|
||||||
): Boolean {
|
|
||||||
if (e.action == android.view.MotionEvent.ACTION_DOWN) {
|
|
||||||
dishPartAdapter.closeAll()
|
|
||||||
}
|
}
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
/**
|
||||||
|
* 构建侧滑删除菜单项
|
||||||
|
*/
|
||||||
|
private fun buildDeleteMenuItem(): SwipeMenuItem {
|
||||||
|
return SwipeMenuItem(this).apply {
|
||||||
|
setImage(R.drawable.ic_trash_white)
|
||||||
|
setBackground(R.drawable.bg_swipe_delete)
|
||||||
|
width = dp2px(160)
|
||||||
|
height = ViewGroup.LayoutParams.MATCH_PARENT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dp 转 px
|
||||||
|
*/
|
||||||
|
private fun dp2px(dp: Int): Int {
|
||||||
|
return (dp * resources.displayMetrics.density + 0.5f).toInt()
|
||||||
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
pageVisible = true
|
pageVisible = true
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import android.annotation.SuppressLint
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.MotionEvent
|
import android.view.ViewGroup
|
||||||
import androidx.activity.addCallback
|
import androidx.activity.addCallback
|
||||||
import androidx.lifecycle.Lifecycle
|
import androidx.lifecycle.Lifecycle
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
@@ -18,14 +18,15 @@ import com.shuwei.dish.match.databinding.ActivitySamplingModeBinding
|
|||||||
import com.shuwei.dish.match.databinding.LayoutEmptyViewBinding
|
import com.shuwei.dish.match.databinding.LayoutEmptyViewBinding
|
||||||
import com.shuwei.dish.match.dialog.CommonDialog
|
import com.shuwei.dish.match.dialog.CommonDialog
|
||||||
import com.shuwei.dish.match.entity.FoodRecord
|
import com.shuwei.dish.match.entity.FoodRecord
|
||||||
|
import com.shuwei.dish.match.net.UiState
|
||||||
import com.shuwei.dish.match.utils.DateTimeUtil
|
import com.shuwei.dish.match.utils.DateTimeUtil
|
||||||
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.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
|
||||||
|
import com.yanzhenjie.recyclerview.SwipeMenuItem
|
||||||
import java.io.Serializable
|
import java.io.Serializable
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import com.shuwei.dish.match.net.UiState
|
|
||||||
/**
|
/**
|
||||||
* 采样模式
|
* 采样模式
|
||||||
*/
|
*/
|
||||||
@@ -161,23 +162,6 @@ class SamplingModeActivity : BaseActivity() {
|
|||||||
private val dishAdapter by lazy {
|
private val dishAdapter by lazy {
|
||||||
FoodListAdapter(list = list, mode = FoodListAdapter.DisplayMode.SAMPLING_MODE).apply {
|
FoodListAdapter(list = list, mode = FoodListAdapter.DisplayMode.SAMPLING_MODE).apply {
|
||||||
isStateViewEnable = true
|
isStateViewEnable = true
|
||||||
onDeleteClick = { position ->
|
|
||||||
CommonDialog(this@SamplingModeActivity)
|
|
||||||
.setTitle("删除确认")
|
|
||||||
.setContent("确定要删除「${list[position].foodName}」吗?")
|
|
||||||
.setNegativeButton("取消")
|
|
||||||
.setPositiveButton("删除") {
|
|
||||||
deleteCookFoodAndGoods(foodId = list[position].foodId ?: "") {
|
|
||||||
if (list.size > 1) {
|
|
||||||
removeAt(position)
|
|
||||||
} else {
|
|
||||||
loadEmptyView()
|
|
||||||
}
|
|
||||||
toast("已删除")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.show()
|
|
||||||
}
|
|
||||||
onItemClick = { position ->
|
onItemClick = { position ->
|
||||||
judgeDeviceConfig {
|
judgeDeviceConfig {
|
||||||
onItemClick(position)
|
onItemClick(position)
|
||||||
@@ -207,19 +191,58 @@ class SamplingModeActivity : BaseActivity() {
|
|||||||
binding.rvSamplingList.run {
|
binding.rvSamplingList.run {
|
||||||
layoutManager =
|
layoutManager =
|
||||||
LinearLayoutManager(this@SamplingModeActivity, LinearLayoutManager.VERTICAL, false)
|
LinearLayoutManager(this@SamplingModeActivity, LinearLayoutManager.VERTICAL, false)
|
||||||
|
// 根据 isCooking 决定是否显示侧滑删除菜单(必须在 setAdapter 之前调用)
|
||||||
|
setSwipeMenuCreator { _, rightMenu, position ->
|
||||||
|
if (list.getOrNull(position)?.isCooking == true) {
|
||||||
|
rightMenu.addMenuItem(buildDeleteMenuItem())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 点击侧滑菜单项:先关闭菜单,再弹窗确认删除
|
||||||
|
setOnItemMenuClickListener { menuBridge, position ->
|
||||||
|
menuBridge.closeMenu()
|
||||||
|
val item = list.getOrNull(position) ?: return@setOnItemMenuClickListener
|
||||||
|
CommonDialog(this@SamplingModeActivity)
|
||||||
|
.setTitle("删除确认")
|
||||||
|
.setContent("确定要删除「${item.foodName}」吗?")
|
||||||
|
.setNegativeButton("取消")
|
||||||
|
.setPositiveButton("删除") {
|
||||||
|
deleteCookFoodAndGoods(foodId = item.foodId ?: "") {
|
||||||
|
if (list.size > 1) {
|
||||||
|
dishAdapter.removeAt(position)
|
||||||
|
} else {
|
||||||
|
loadEmptyView()
|
||||||
|
}
|
||||||
|
toast("已删除")
|
||||||
|
}
|
||||||
|
}.show()
|
||||||
|
}
|
||||||
|
// item 点击事件
|
||||||
|
setOnItemClickListener { _, position ->
|
||||||
|
judgeDeviceConfig { onItemClick(position) }
|
||||||
|
}
|
||||||
adapter = dishAdapter
|
adapter = dishAdapter
|
||||||
// 点击列表空白区域时关闭已展开的侧滑 item
|
|
||||||
addOnItemTouchListener(object : androidx.recyclerview.widget.RecyclerView.SimpleOnItemTouchListener() {
|
|
||||||
override fun onInterceptTouchEvent(rv: androidx.recyclerview.widget.RecyclerView, e: MotionEvent): Boolean {
|
|
||||||
if (e.action == MotionEvent.ACTION_DOWN) {
|
|
||||||
dishAdapter.closeAll()
|
|
||||||
}
|
}
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
/**
|
||||||
|
* 构建侧滑删除菜单项
|
||||||
|
*/
|
||||||
|
private fun buildDeleteMenuItem(): SwipeMenuItem {
|
||||||
|
return SwipeMenuItem(this).apply {
|
||||||
|
setImage(R.drawable.ic_trash_white)
|
||||||
|
setBackground(R.drawable.bg_swipe_delete)
|
||||||
|
width = dp2px(160)
|
||||||
|
height = ViewGroup.LayoutParams.MATCH_PARENT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dp 转 px
|
||||||
|
*/
|
||||||
|
private fun dp2px(dp: Int): Int {
|
||||||
|
return (dp * resources.displayMetrics.density + 0.5f).toInt()
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressLint("ClickableViewAccessibility")
|
@SuppressLint("ClickableViewAccessibility")
|
||||||
private fun addViewListener() {
|
private fun addViewListener() {
|
||||||
binding.btnAddSampling.setOnClickListener {
|
binding.btnAddSampling.setOnClickListener {
|
||||||
|
|||||||
@@ -1,28 +1,30 @@
|
|||||||
package com.shuwei.dish.match.ui.fragment
|
package com.shuwei.dish.match.ui.fragment
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.Context
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.MotionEvent
|
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.lifecycle.Lifecycle
|
import androidx.lifecycle.Lifecycle
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.lifecycle.repeatOnLifecycle
|
import androidx.lifecycle.repeatOnLifecycle
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import com.shuwei.dish.match.R
|
||||||
import com.shuwei.dish.match.adapter.FoodListAdapter
|
import com.shuwei.dish.match.adapter.FoodListAdapter
|
||||||
import com.shuwei.dish.match.base.BaseApp
|
import com.shuwei.dish.match.base.BaseApp
|
||||||
import com.shuwei.dish.match.base.BaseFragment
|
import com.shuwei.dish.match.base.BaseFragment
|
||||||
import com.shuwei.dish.match.databinding.FragmentDishListBinding
|
import com.shuwei.dish.match.databinding.FragmentDishListBinding
|
||||||
import com.shuwei.dish.match.databinding.LayoutEmptyViewBinding
|
import com.shuwei.dish.match.databinding.LayoutEmptyViewBinding
|
||||||
|
import com.shuwei.dish.match.dialog.CommonDialog
|
||||||
import com.shuwei.dish.match.entity.CookFoodEntity
|
import com.shuwei.dish.match.entity.CookFoodEntity
|
||||||
import com.shuwei.dish.match.entity.FoodRecord
|
import com.shuwei.dish.match.entity.FoodRecord
|
||||||
import com.shuwei.dish.match.dialog.CommonDialog
|
|
||||||
import com.shuwei.dish.match.net.UiState
|
import com.shuwei.dish.match.net.UiState
|
||||||
import com.shuwei.dish.match.ui.PrepareFoodActivity
|
|
||||||
import com.shuwei.dish.match.ui.CookingModeActivity
|
import com.shuwei.dish.match.ui.CookingModeActivity
|
||||||
|
import com.shuwei.dish.match.ui.PrepareFoodActivity
|
||||||
import com.shuwei.dish.match.ui.SubmitFoodActivity
|
import com.shuwei.dish.match.ui.SubmitFoodActivity
|
||||||
import com.shuwei.dish.match.utils.ext.startActivity
|
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.yanzhenjie.recyclerview.SwipeMenuItem
|
||||||
import java.io.Serializable
|
import java.io.Serializable
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@@ -53,20 +55,6 @@ class DishListFragment : BaseFragment<FragmentDishListBinding>() {
|
|||||||
private val dishAdapter by lazy {
|
private val dishAdapter by lazy {
|
||||||
FoodListAdapter(list = list).apply {
|
FoodListAdapter(list = list).apply {
|
||||||
isStateViewEnable = true
|
isStateViewEnable = true
|
||||||
onDeleteClick = { position ->
|
|
||||||
CommonDialog(activity)
|
|
||||||
.setTitle("删除确认")
|
|
||||||
.setContent("确定要删除「${list[position].foodName}」吗?")
|
|
||||||
.setNegativeButton("取消")
|
|
||||||
.setPositiveButton("删除") {
|
|
||||||
activity.deleteCookFoodAndGoods(foodId = list[position].foodId ?: "") {
|
|
||||||
activity.toast("已删除")
|
|
||||||
pageNo = 1
|
|
||||||
getDishList()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.show()
|
|
||||||
}
|
|
||||||
onItemClick = { position ->
|
onItemClick = { position ->
|
||||||
if (isAdded && isVisible) {
|
if (isAdded && isVisible) {
|
||||||
activity.judgeDeviceConfig {
|
activity.judgeDeviceConfig {
|
||||||
@@ -80,21 +68,15 @@ class DishListFragment : BaseFragment<FragmentDishListBinding>() {
|
|||||||
private fun onItemClick(position: Int) {
|
private fun onItemClick(position: Int) {
|
||||||
val item = list[position]
|
val item = list[position]
|
||||||
if (item.isCooking) {
|
if (item.isCooking) {
|
||||||
//烹饪中,跳到称熟重页面
|
// 烹饪中,跳到称熟重页面
|
||||||
activity.startActivity<SubmitFoodActivity> {
|
activity.startActivity<SubmitFoodActivity> {
|
||||||
putExtra(
|
putExtra(SubmitFoodActivity.FOOD_ITEM, item as Serializable)
|
||||||
SubmitFoodActivity.FOOD_ITEM,
|
|
||||||
item as Serializable
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
item.dinnerType = dinnerType
|
item.dinnerType = dinnerType
|
||||||
activity.startActivity<PrepareFoodActivity> {
|
activity.startActivity<PrepareFoodActivity> {
|
||||||
putExtra(
|
putExtra(SubmitFoodActivity.FOOD_ITEM, item as Serializable)
|
||||||
SubmitFoodActivity.FOOD_ITEM,
|
|
||||||
item as Serializable
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,18 +91,37 @@ class DishListFragment : BaseFragment<FragmentDishListBinding>() {
|
|||||||
activity = requireActivity() as CookingModeActivity
|
activity = requireActivity() as CookingModeActivity
|
||||||
dinnerType = arguments?.getString(DINNER_TYPE, "0") ?: "0"
|
dinnerType = arguments?.getString(DINNER_TYPE, "0") ?: "0"
|
||||||
binding.rvDishList.run {
|
binding.rvDishList.run {
|
||||||
layoutManager =
|
layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false)
|
||||||
LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false)
|
// 侧滑菜单:仅烹饪中的 item 显示删除按钮(必须在 setAdapter 之前调用)
|
||||||
|
setSwipeMenuCreator { _, rightMenu, position ->
|
||||||
|
if (list.getOrNull(position)?.isCooking == true) {
|
||||||
|
rightMenu.addMenuItem(buildDeleteMenuItem(requireContext()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 菜单点击:先关闭菜单,再弹确认弹窗
|
||||||
|
setOnItemMenuClickListener { menuBridge, position ->
|
||||||
|
menuBridge.closeMenu()
|
||||||
|
val item = list.getOrNull(position) ?: return@setOnItemMenuClickListener
|
||||||
|
CommonDialog(activity)
|
||||||
|
.setTitle("删除确认")
|
||||||
|
.setContent("确定要删除「${item.foodName}」吗?")
|
||||||
|
.setNegativeButton("取消")
|
||||||
|
.setPositiveButton("删除") {
|
||||||
|
activity.deleteCookFoodAndGoods(foodId = item.foodId ?: "") {
|
||||||
|
activity.toast("已删除")
|
||||||
|
pageNo = 1
|
||||||
|
getDishList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
// item 点击
|
||||||
|
setOnItemClickListener { _, position ->
|
||||||
|
if (isAdded && isVisible) {
|
||||||
|
activity.judgeDeviceConfig { onItemClick(position) }
|
||||||
|
}
|
||||||
|
}
|
||||||
adapter = dishAdapter
|
adapter = dishAdapter
|
||||||
// 点击列表空白区域时关闭已展开的侧滑 item
|
|
||||||
addOnItemTouchListener(object : androidx.recyclerview.widget.RecyclerView.SimpleOnItemTouchListener() {
|
|
||||||
override fun onInterceptTouchEvent(rv: androidx.recyclerview.widget.RecyclerView, e: MotionEvent): Boolean {
|
|
||||||
if (e.action == MotionEvent.ACTION_DOWN) {
|
|
||||||
dishAdapter.closeAll()
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
addViewListener()
|
addViewListener()
|
||||||
initObserver()
|
initObserver()
|
||||||
@@ -131,6 +132,22 @@ class DishListFragment : BaseFragment<FragmentDishListBinding>() {
|
|||||||
binding.refreshLayout.setEnableRefresh(true)
|
binding.refreshLayout.setEnableRefresh(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建统一样式的删除菜单项
|
||||||
|
*/
|
||||||
|
private fun buildDeleteMenuItem(context: Context): SwipeMenuItem {
|
||||||
|
return SwipeMenuItem(context).apply {
|
||||||
|
setImage(R.drawable.ic_trash_white)
|
||||||
|
setBackground(R.drawable.bg_swipe_delete)
|
||||||
|
width = dp2px(context, 160)
|
||||||
|
height = ViewGroup.LayoutParams.MATCH_PARENT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun dp2px(context: Context, dp: Int): Int {
|
||||||
|
return (dp * context.resources.displayMetrics.density + 0.5f).toInt()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用 combine 同时监听网络结果与本地数据,网络成功时统一合并渲染
|
* 用 combine 同时监听网络结果与本地数据,网络成功时统一合并渲染
|
||||||
* pageNo > 1(加载更多)时 cookFoodListState 不参与合并,直接追加网络数据
|
* pageNo > 1(加载更多)时 cookFoodListState 不参与合并,直接追加网络数据
|
||||||
@@ -156,7 +173,6 @@ class DishListFragment : BaseFragment<FragmentDishListBinding>() {
|
|||||||
finishRefresh()
|
finishRefresh()
|
||||||
activity.delayDismissLoading()
|
activity.delayDismissLoading()
|
||||||
if (pageNo == 1) {
|
if (pageNo == 1) {
|
||||||
// 网络异常或接口不通时,降级使用本地数据;本地也为空才显示空视图
|
|
||||||
if (localList.isNullOrEmpty()) {
|
if (localList.isNullOrEmpty()) {
|
||||||
loadEmptyView()
|
loadEmptyView()
|
||||||
} else {
|
} else {
|
||||||
@@ -209,7 +225,6 @@ class DishListFragment : BaseFragment<FragmentDishListBinding>() {
|
|||||||
"placeId" to BaseApp.canteenId,
|
"placeId" to BaseApp.canteenId,
|
||||||
"dinnerType" to getDinnerTypeText()
|
"dinnerType" to getDinnerTypeText()
|
||||||
)
|
)
|
||||||
// 网络与本地并行触发,pageNo > 1 时不重复查询本地数据
|
|
||||||
activity.getFoodList(param = param)
|
activity.getFoodList(param = param)
|
||||||
if (pageNo == 1) activity.getCookFoodList()
|
if (pageNo == 1) activity.getCookFoodList()
|
||||||
}
|
}
|
||||||
@@ -233,7 +248,6 @@ class DishListFragment : BaseFragment<FragmentDishListBinding>() {
|
|||||||
emptyViewBinding!!.tvContent.text = "暂无数据"
|
emptyViewBinding!!.tvContent.text = "暂无数据"
|
||||||
emptyViewBinding!!.tvSubContent.text = "获取菜品数据失败,请检查网络设置或稍后重试"
|
emptyViewBinding!!.tvSubContent.text = "获取菜品数据失败,请检查网络设置或稍后重试"
|
||||||
dishAdapter.stateView = emptyViewBinding!!.root
|
dishAdapter.stateView = emptyViewBinding!!.root
|
||||||
//dishAdapter.setStateViewLayout(requireContext(), R.layout-sw800dp.layout_empty_view)
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
}
|
}
|
||||||
@@ -249,7 +263,6 @@ class DishListFragment : BaseFragment<FragmentDishListBinding>() {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 将网络数据与本地烹饪中数据合并后渲染列表
|
* 将网络数据与本地烹饪中数据合并后渲染列表
|
||||||
* pageNo > 1 时忽略本地数据,直接追加网络数据,避免 combine 带入旧的本地状态
|
|
||||||
*/
|
*/
|
||||||
@SuppressLint("NotifyDataSetChanged")
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
private fun loadAndMergeDishList(
|
private fun loadAndMergeDishList(
|
||||||
@@ -258,7 +271,6 @@ class DishListFragment : BaseFragment<FragmentDishListBinding>() {
|
|||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
if (isAdded.not()) return
|
if (isAdded.not()) return
|
||||||
// pageNo > 1 时不参与本地合并,避免 combine 带入旧的本地状态
|
|
||||||
val effectiveLocalList = if (pageNo == 1) localList else null
|
val effectiveLocalList = if (pageNo == 1) localList else null
|
||||||
if (records.isNullOrEmpty() && effectiveLocalList.isNullOrEmpty()) {
|
if (records.isNullOrEmpty() && effectiveLocalList.isNullOrEmpty()) {
|
||||||
if (pageNo == 1) loadEmptyView()
|
if (pageNo == 1) loadEmptyView()
|
||||||
@@ -268,7 +280,6 @@ class DishListFragment : BaseFragment<FragmentDishListBinding>() {
|
|||||||
|
|
||||||
val mergedList = records?.toMutableList() ?: mutableListOf()
|
val mergedList = records?.toMutableList() ?: mutableListOf()
|
||||||
|
|
||||||
// 仅 pageNo == 1 时才有本地数据参与合并
|
|
||||||
if (!effectiveLocalList.isNullOrEmpty()) {
|
if (!effectiveLocalList.isNullOrEmpty()) {
|
||||||
val cookingItems = mutableListOf<FoodRecord>()
|
val cookingItems = mutableListOf<FoodRecord>()
|
||||||
effectiveLocalList.forEachIndexed { index, entity ->
|
effectiveLocalList.forEachIndexed { index, entity ->
|
||||||
@@ -280,7 +291,6 @@ class DishListFragment : BaseFragment<FragmentDishListBinding>() {
|
|||||||
food.dinnerType = entity.dinnerType ?: "0"
|
food.dinnerType = entity.dinnerType ?: "0"
|
||||||
cookingItems.add(food)
|
cookingItems.add(food)
|
||||||
} else {
|
} else {
|
||||||
// 当前网络数据不包含该本地记录,直接构造
|
|
||||||
cookingItems.add(
|
cookingItems.add(
|
||||||
FoodRecord(
|
FoodRecord(
|
||||||
foodId = entity.foodId,
|
foodId = entity.foodId,
|
||||||
@@ -296,7 +306,6 @@ class DishListFragment : BaseFragment<FragmentDishListBinding>() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (pageNo >= 2 && !localList.isNullOrEmpty()) {
|
if (pageNo >= 2 && !localList.isNullOrEmpty()) {
|
||||||
//第2页起,从mergedList中移除localList中的同foodId数据
|
|
||||||
val localIds = localList.map { it.foodId }.toHashSet()
|
val localIds = localList.map { it.foodId }.toHashSet()
|
||||||
mergedList.removeAll { it.foodId in localIds }
|
mergedList.removeAll { it.foodId in localIds }
|
||||||
}
|
}
|
||||||
@@ -310,5 +319,4 @@ class DishListFragment : BaseFragment<FragmentDishListBinding>() {
|
|||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
-1133
File diff suppressed because it is too large
Load Diff
@@ -1,271 +0,0 @@
|
|||||||
/**
|
|
||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2016 Chau Thai
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.shuwei.dish.match.view.swipereveallayout;
|
|
||||||
|
|
||||||
import android.os.Bundle;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ViewBinderHelper provides a quick and easy solution to restore the open/close state
|
|
||||||
* of the items in RecyclerView, ListView, GridView or any view that requires its child view
|
|
||||||
* to bind the view to a data object.
|
|
||||||
*
|
|
||||||
* <p>When you bind you data object to a view, use {@link #bind(SwipeRevealLayout, String)} to
|
|
||||||
* save and restore the open/close state of the view.</p>
|
|
||||||
*
|
|
||||||
* <p>Optionally, if you also want to save and restore the open/close state when the device's
|
|
||||||
* orientation is changed, call {@link #saveStates(Bundle)} in {@link android.app.Activity#onSaveInstanceState(Bundle)}
|
|
||||||
* and {@link #restoreStates(Bundle)} in {@link android.app.Activity#onRestoreInstanceState(Bundle)}</p>
|
|
||||||
*/
|
|
||||||
public class ViewBinderHelper {
|
|
||||||
private static final String BUNDLE_MAP_KEY = "ViewBinderHelper_Bundle_Map_Key";
|
|
||||||
|
|
||||||
private Map<String, Integer> mapStates = Collections.synchronizedMap(new HashMap<String, Integer>());
|
|
||||||
private Map<String, SwipeRevealLayout> mapLayouts = Collections.synchronizedMap(new HashMap<String, SwipeRevealLayout>());
|
|
||||||
private Set<String> lockedSwipeSet = Collections.synchronizedSet(new HashSet<String>());
|
|
||||||
|
|
||||||
private volatile boolean openOnlyOne = false;
|
|
||||||
private final Object stateChangeLock = new Object();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Help to save and restore open/close state of the swipeLayout. Call this method
|
|
||||||
* when you bind your view holder with the data object.
|
|
||||||
*
|
|
||||||
* @param swipeLayout swipeLayout of the current view.
|
|
||||||
* @param id a string that uniquely defines the data object of the current view.
|
|
||||||
*/
|
|
||||||
public void bind(final SwipeRevealLayout swipeLayout, final String id) {
|
|
||||||
if (swipeLayout.shouldRequestLayout()) {
|
|
||||||
swipeLayout.requestLayout();
|
|
||||||
}
|
|
||||||
|
|
||||||
mapLayouts.values().remove(swipeLayout);
|
|
||||||
mapLayouts.put(id, swipeLayout);
|
|
||||||
|
|
||||||
swipeLayout.abort();
|
|
||||||
swipeLayout.setDragStateChangeListener(new SwipeRevealLayout.DragStateChangeListener() {
|
|
||||||
@Override
|
|
||||||
public void onDragStateChanged(int state) {
|
|
||||||
mapStates.put(id, state);
|
|
||||||
|
|
||||||
if (openOnlyOne) {
|
|
||||||
closeOthers(id, swipeLayout);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// first time binding.
|
|
||||||
if (!mapStates.containsKey(id)) {
|
|
||||||
mapStates.put(id, SwipeRevealLayout.STATE_CLOSE);
|
|
||||||
swipeLayout.close(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// not the first time, then close or open depends on the current state.
|
|
||||||
else {
|
|
||||||
int state = mapStates.get(id);
|
|
||||||
|
|
||||||
if (state == SwipeRevealLayout.STATE_CLOSE || state == SwipeRevealLayout.STATE_CLOSING ||
|
|
||||||
state == SwipeRevealLayout.STATE_DRAGGING) {
|
|
||||||
swipeLayout.close(false);
|
|
||||||
} else {
|
|
||||||
swipeLayout.open(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// set lock swipe
|
|
||||||
swipeLayout.setLockDrag(lockedSwipeSet.contains(id));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Only if you need to restore open/close state when the orientation is changed.
|
|
||||||
* Call this method in {@link android.app.Activity#onSaveInstanceState(Bundle)}
|
|
||||||
*/
|
|
||||||
public void saveStates(Bundle outState) {
|
|
||||||
if (outState == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
Bundle statesBundle = new Bundle();
|
|
||||||
for (Map.Entry<String, Integer> entry : mapStates.entrySet()) {
|
|
||||||
statesBundle.putInt(entry.getKey(), entry.getValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
outState.putBundle(BUNDLE_MAP_KEY, statesBundle);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Only if you need to restore open/close state when the orientation is changed.
|
|
||||||
* Call this method in {@link android.app.Activity#onRestoreInstanceState(Bundle)}
|
|
||||||
*/
|
|
||||||
@SuppressWarnings({"unchecked", "ConstantConditions"})
|
|
||||||
public void restoreStates(Bundle inState) {
|
|
||||||
if (inState == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (inState.containsKey(BUNDLE_MAP_KEY)) {
|
|
||||||
HashMap<String, Integer> restoredMap = new HashMap<>();
|
|
||||||
|
|
||||||
Bundle statesBundle = inState.getBundle(BUNDLE_MAP_KEY);
|
|
||||||
Set<String> keySet = statesBundle.keySet();
|
|
||||||
|
|
||||||
if (keySet != null) {
|
|
||||||
for (String key : keySet) {
|
|
||||||
restoredMap.put(key, statesBundle.getInt(key));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mapStates = restoredMap;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Lock swipe for some layouts.
|
|
||||||
* @param id a string that uniquely defines the data object.
|
|
||||||
*/
|
|
||||||
public void lockSwipe(String... id) {
|
|
||||||
setLockSwipe(true, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unlock swipe for some layouts.
|
|
||||||
* @param id a string that uniquely defines the data object.
|
|
||||||
*/
|
|
||||||
public void unlockSwipe(String... id) {
|
|
||||||
setLockSwipe(false, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param openOnlyOne If set to true, then only one row can be opened at a time.
|
|
||||||
*/
|
|
||||||
public void setOpenOnlyOne(boolean openOnlyOne) {
|
|
||||||
this.openOnlyOne = openOnlyOne;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Open a specific layout.
|
|
||||||
* @param id unique id which identifies the data object which is bind to the layout.
|
|
||||||
*/
|
|
||||||
public void openLayout(final String id) {
|
|
||||||
synchronized (stateChangeLock) {
|
|
||||||
mapStates.put(id, SwipeRevealLayout.STATE_OPEN);
|
|
||||||
|
|
||||||
if (mapLayouts.containsKey(id)) {
|
|
||||||
final SwipeRevealLayout layout = mapLayouts.get(id);
|
|
||||||
layout.open(true);
|
|
||||||
}
|
|
||||||
else if (openOnlyOne) {
|
|
||||||
closeOthers(id, mapLayouts.get(id));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Close a specific layout.
|
|
||||||
* @param id unique id which identifies the data object which is bind to the layout.
|
|
||||||
*/
|
|
||||||
public void closeLayout(final String id) {
|
|
||||||
synchronized (stateChangeLock) {
|
|
||||||
mapStates.put(id, SwipeRevealLayout.STATE_CLOSE);
|
|
||||||
|
|
||||||
if (mapLayouts.containsKey(id)) {
|
|
||||||
final SwipeRevealLayout layout = mapLayouts.get(id);
|
|
||||||
layout.close(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 关闭所有已展开的侧滑布局,用于点击空白区域时收起侧滑。
|
|
||||||
*/
|
|
||||||
public void closeAll() {
|
|
||||||
synchronized (stateChangeLock) {
|
|
||||||
for (Map.Entry<String, Integer> entry : mapStates.entrySet()) {
|
|
||||||
entry.setValue(SwipeRevealLayout.STATE_CLOSE);
|
|
||||||
}
|
|
||||||
for (SwipeRevealLayout layout : mapLayouts.values()) {
|
|
||||||
layout.close(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Close others swipe layout.
|
|
||||||
* @param id layout which bind with this data object id will be excluded.
|
|
||||||
* @param swipeLayout will be excluded.
|
|
||||||
*/
|
|
||||||
private void closeOthers(String id, SwipeRevealLayout swipeLayout) {
|
|
||||||
synchronized (stateChangeLock) {
|
|
||||||
// close other rows if openOnlyOne is true.
|
|
||||||
if (getOpenCount() > 1) {
|
|
||||||
for (Map.Entry<String, Integer> entry : mapStates.entrySet()) {
|
|
||||||
if (!entry.getKey().equals(id)) {
|
|
||||||
entry.setValue(SwipeRevealLayout.STATE_CLOSE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (SwipeRevealLayout layout : mapLayouts.values()) {
|
|
||||||
if (layout != swipeLayout) {
|
|
||||||
layout.close(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setLockSwipe(boolean lock, String... id) {
|
|
||||||
if (id == null || id.length == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (lock)
|
|
||||||
lockedSwipeSet.addAll(Arrays.asList(id));
|
|
||||||
else
|
|
||||||
lockedSwipeSet.removeAll(Arrays.asList(id));
|
|
||||||
|
|
||||||
for (String s : id) {
|
|
||||||
SwipeRevealLayout layout = mapLayouts.get(s);
|
|
||||||
if (layout != null) {
|
|
||||||
layout.setLockDrag(lock);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getOpenCount() {
|
|
||||||
int total = 0;
|
|
||||||
|
|
||||||
for (int state : mapStates.values()) {
|
|
||||||
if (state == SwipeRevealLayout.STATE_OPEN || state == SwipeRevealLayout.STATE_OPENING) {
|
|
||||||
total++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return total;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -92,15 +92,15 @@
|
|||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<com.yanzhenjie.recyclerview.SwipeRecyclerView
|
||||||
android:id="@+id/rvDishPartList"
|
android:id="@+id/rvDishPartList"
|
||||||
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:layout_marginBottom="20dp"
|
||||||
android:overScrollMode="never"
|
android:overScrollMode="never"
|
||||||
|
android:scrollbars="vertical"
|
||||||
tools:itemCount="3"
|
tools:itemCount="3"
|
||||||
tools:listitem="@layout/list_item_dish_cook"
|
tools:listitem="@layout/list_item_dish_cook" />
|
||||||
android:scrollbars="vertical" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
|||||||
@@ -76,7 +76,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content" />
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<com.yanzhenjie.recyclerview.SwipeRecyclerView
|
||||||
android:id="@+id/rvSamplingList"
|
android:id="@+id/rvSamplingList"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content" />
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<com.yanzhenjie.recyclerview.SwipeRecyclerView
|
||||||
android:id="@+id/rvDishList"
|
android:id="@+id/rvDishList"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
|||||||
@@ -1,34 +1,13 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<com.shuwei.dish.match.view.swipereveallayout.SwipeRevealLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:id="@+id/swipeRevealLayout"
|
android:id="@+id/clBlock"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="120dp"
|
android:layout_height="120dp"
|
||||||
android:layout_marginStart="30dp"
|
android:layout_marginStart="30dp"
|
||||||
android:layout_marginEnd="30dp"
|
android:layout_marginEnd="30dp"
|
||||||
android:layout_marginBottom="15dp"
|
android:layout_marginBottom="15dp"
|
||||||
app:dragEdge="right">
|
|
||||||
|
|
||||||
<FrameLayout
|
|
||||||
android:id="@+id/layoutDelete"
|
|
||||||
android:layout_width="160dp"
|
|
||||||
android:layout_height="120dp"
|
|
||||||
android:background="@drawable/bg_swipe_delete">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:layout_width="48dp"
|
|
||||||
android:layout_height="48dp"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:contentDescription="删除"
|
|
||||||
android:src="@drawable/ic_trash_white" />
|
|
||||||
|
|
||||||
</FrameLayout>
|
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
android:id="@+id/clBlock"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="120dp"
|
|
||||||
android:background="@drawable/shape_white_fb_15_corners">
|
android:background="@drawable/shape_white_fb_15_corners">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
@@ -104,6 +83,4 @@
|
|||||||
tools:ignore="HardcodedText"
|
tools:ignore="HardcodedText"
|
||||||
tools:text="375克" />
|
tools:text="375克" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
</com.shuwei.dish.match.view.swipereveallayout.SwipeRevealLayout>
|
|
||||||
|
|||||||
@@ -1,38 +1,14 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<com.shuwei.dish.match.view.swipereveallayout.SwipeRevealLayout
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:id="@+id/swipeRevealLayout"
|
android:id="@+id/clBlock"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="150dp"
|
||||||
android:layout_marginStart="15dp"
|
android:layout_marginStart="15dp"
|
||||||
android:layout_marginEnd="15dp"
|
android:layout_marginEnd="15dp"
|
||||||
android:layout_marginTop="7dp"
|
android:layout_marginTop="7dp"
|
||||||
android:layout_marginBottom="8dp"
|
android:layout_marginBottom="8dp"
|
||||||
app:dragEdge="right">
|
|
||||||
|
|
||||||
<!-- 后景层(secondaryView = getChildAt(0)):删除按钮,右对齐 -->
|
|
||||||
<FrameLayout
|
|
||||||
android:id="@+id/layoutDelete"
|
|
||||||
android:layout_width="160dp"
|
|
||||||
android:layout_height="150dp"
|
|
||||||
android:background="@drawable/bg_swipe_delete">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:layout_width="48dp"
|
|
||||||
android:layout_height="48dp"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:contentDescription="删除"
|
|
||||||
android:src="@drawable/ic_trash_white" />
|
|
||||||
|
|
||||||
</FrameLayout>
|
|
||||||
|
|
||||||
<!-- 前景层(mainView = getChildAt(1)):item 主内容 -->
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
android:id="@+id/clBlock"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="150dp"
|
|
||||||
android:background="@drawable/shape_white_fb_15_corners"
|
android:background="@drawable/shape_white_fb_15_corners"
|
||||||
android:foreground="?android:attr/selectableItemBackground"
|
android:foreground="?android:attr/selectableItemBackground"
|
||||||
android:paddingStart="30dp"
|
android:paddingStart="30dp"
|
||||||
@@ -82,6 +58,4 @@
|
|||||||
app:layout_constraintTop_toBottomOf="@id/tvDishName"
|
app:layout_constraintTop_toBottomOf="@id/tvDishName"
|
||||||
tools:text="累计统计:2.3kg(2次)" />
|
tools:text="累计统计:2.3kg(2次)" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
</com.shuwei.dish.match.view.swipereveallayout.SwipeRevealLayout>
|
|
||||||
|
|||||||
Reference in New Issue
Block a user