Android 实现QQ侧滑删除效果
2020-06-21 本文已影响0人
因为我的心
一、前言:
分析: Android中什么组件自带了水平滑动? 我首当其冲就想到HorizontalScrollView。既然是简单实现,那我们何方不继承一下HorizontalScrollView呢?
接下来我们将HorizontalScrollView分成ItemView + 抽屉部分。
我们只需要监听用户的滑动事件,当用户滑动超过指定距离时,就移动HorizontalScrollView,将隐藏的“抽屉部分”显示出来,当用户做相反的滑动时,隐藏“抽屉部分”即可。
gitee地址:https://gitee.com/luoyanyong/SlidingDeleteDemo
效果图:
图片.png
二、实现:
1、依赖:
//recyclerview使用
implementation 'androidx.recyclerview:recyclerview:1.0.0'
// implementation 'com.android.support:recyclerview-v7:29.0.0'
//BRVAH使用
implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.47'
//万能插件
implementation 'com.blankj:utilcodex:1.25.2'
2、 自定义SlidingDeleteView
/**
* 滑动删除widget
*
* @author Junhui
*/
public class SlidingDeleteView extends HorizontalScrollView {
private static final String TAG = "SlidingDeleteView";
/**
* 抽屉视图(注意:recyclerview/listview中不能使用button,button会抢夺焦点) - 父件
*/
private LinearLayout slidingParent;
/**
* 是否开启滑动抽屉
*/
public boolean isEnable = true;
/**
* 抽屉视图是否可见
*/
public boolean deleteViewVisibile = false;
private boolean isFirst = true;
//监听器
private OnDeleteViewStateChangedListener onStateChangedListener;
/**
* 抽屉视图状态变化回调接口
*/
public interface OnDeleteViewStateChangedListener {
void onVisibile();
void onGone();
void onDownOrMove();
}
public SlidingDeleteView(Context context) {
this(context, null);
}
public SlidingDeleteView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SlidingDeleteView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (isFirst) {
init();
isFirst = false;
}
}
private void init() {
slidingParent = (LinearLayout) findViewById(R.id.lay_sliding);
}
public void setOnDeleteViewStateChangedListener(OnDeleteViewStateChangedListener onStateChangedListener) {
this.onStateChangedListener = onStateChangedListener;
}
public boolean isEnable() {
return isEnable;
}
public void setEnable(boolean enable) {
isEnable = enable;
}
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_MOVE:
if (!isEnable) {
return false;
}
case MotionEvent.ACTION_DOWN:
if (onStateChangedListener != null) {
onStateChangedListener.onDownOrMove();
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
measureScrollX();
return true;
default:
break;
}
return super.onTouchEvent(ev);
}
/**
* 计算X轴滑动距离,并做出相应操作
*/
private void measureScrollX() {
if (getScrollX() < slidingParent.getWidth() / 3) {
//TODO 当滑动距离小于 抽屉视图宽度 * 1/3 时,隐藏删除视图
setDeleteViewGone();
} else {
setDeleteViewVisibile();
}
}
/**
* 隐藏滑动布局
*/
public void setDeleteViewGone() {
deleteViewVisibile = false;
this.smoothScrollTo(0, 0);
if (onStateChangedListener != null) {
onStateChangedListener.onGone();
}
}
/**
* 显示滑动布局
*/
public void setDeleteViewVisibile() {
Log.d(TAG, "抽屉的固定宽度为 == " + slidingParent.getWidth());
deleteViewVisibile = true;
this.smoothScrollTo(slidingParent.getWidth(), 0);
if (onStateChangedListener != null) {
onStateChangedListener.onVisibile();
}
}
}
2、 MainActivity
public class MainActivity extends AppCompatActivity {
RecyclerView rv_list;
private List<LoginBean> list = new ArrayList<>();
private MyListAdapter myListAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
rv_list = (RecyclerView) findViewById(R.id.rv_list);
init();
}
/**
* 初始化数据
*/
private void init() {
try {
for (int i=1;i<21;i++){
list.add(new LoginBean("第"+i+"条数据"));
}
if (myListAdapter==null){
rv_list.setLayoutManager(new LinearLayoutManager(this));
rv_list.addItemDecoration(new DividerItemDecoration(this, LinearLayout.VERTICAL));
myListAdapter = new MyListAdapter(R.layout.sample_slidingview,list);
rv_list.setAdapter(myListAdapter);
}else {
myListAdapter.notifyDataSetChanged();
}
myListAdapter.setOnItemChildClickListener(new BaseQuickAdapter.OnItemChildClickListener() {
@Override
public void onItemChildClick(BaseQuickAdapter adapter, View view, int position) {
switch (view.getId()){
case R.id.tv_delete:
list.remove(position);
myListAdapter.notifyDataSetChanged();
Log.d("LUO","===删除==");
break;
case R.id.tv_cancel:
// SlidingDeleteView slidingDeleteView = (SlidingDeleteView) adapter.getViewByPosition(rv_list, position, R.id.slidingview);
//slidingDeleteView.setDeleteViewGone();
// myListAdapter.notifyItemChanged(position);
myListAdapter.notifyDataSetChanged();
Log.d("LUO","===隐藏==");
break;
default:
break;
}
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
}
3、MyListAdapter 类
public class MyListAdapter extends BaseQuickAdapter<LoginBean, BaseViewHolder> {
public MyListAdapter(int layoutResId, List<LoginBean> data) {
super(layoutResId, data);
}
@Override
protected void convert(BaseViewHolder helper, LoginBean item) {
//TODO 这里需要重新计算 item - containerView的宽度,否则containerView会显示错误(重要)
LinearLayout containerView = helper.getView(R.id.lay_container);
final SlidingDeleteView slidingDeleteView = helper.getView(R.id.slidingview);
TextView tv_key = helper.getView(R.id.tv_key);
TextView tv_cancel = helper.getView(R.id.tv_cancel);
TextView tv_delete = helper.getView(R.id.tv_delete);
containerView.getLayoutParams().width = ScreenUtils.getScreenWidth();
slidingDeleteView.setEnable(true);
//默认隐藏
slidingDeleteView.setDeleteViewGone();
tv_key.setText(item.getName());
slidingDeleteView.setOnDeleteViewStateChangedListener(new SlidingDeleteView.OnDeleteViewStateChangedListener() {
@Override
public void onVisibile() {
Log.d("LUO", "显示抽屉视图");
}
@Override
public void onGone() {
Log.d("LUO", "隐藏抽屉视图");
}
@Override
public void onDownOrMove() {
}
});
//添加点击事件
helper.addOnClickListener(R.id.tv_key);
helper.addOnClickListener(R.id.tv_cancel);
helper.addOnClickListener(R.id.tv_delete);
}
}