背景
侧滑删除的功能和效果很棒,而且用户体验感会很好,更加效率点吧!我体验了好多的app,感觉删除的功能还是QQ的侧滑删除最适合我的习惯。查找了github上的开源优秀项目,找了一个使用起来比较简单的框架,下面来实现。
参考
Android 仿QQ侧滑删除—一个满足ListView、RecyclerView以及其他View通用的侧滑删除
该链接可以让你熟悉自定义VIewGroup的一些基本步骤,然后大体的讲了一些侧滑菜单实现基本原理,个人觉得是可以让人学到知识点的好文
该链接就是我使用的框架,点开可以阅读该框架的一些基本使用方法。当然,有时间可以去好好的研究一下源码,肯定可以学习很多的好东西。
框架引入
想要使用这个框架我们需要在项目中引用框架。
- 在项目根build.gradle文件中增加JitPack仓库依赖
allprojects {
repositories {
...
maven { url "https://jitpack.io" }
}
}
- 添加依赖
dependencies {
...
implementation 'com.github.mcxtzhang:SwipeDelMenuLayout:V1.3.0'
}
这里说明一下添加依赖时为什么不是compile,因为我刚刚更新了一下studio,然后添加依赖的时候它建议我使用implementation 来代替compile。如果你的不是高版本的studio,那么可以继续使用compile。
- 在需要侧滑删除的ContentItem外面套上本控件,在本控件内依次排列ContentItem、菜单即可
我的Demo说明
这里我就简单的使用listview来展现数据,并实现侧滑菜单的功能。因为方法都是通用的,所以大家根据需求自己去具体实现即可。阅读上面我参考的框架使用文档,上面有讲很多应用场景,基本适用于大多数的ViewGroup。
主界面布局和代码
就是简单的一个listview控件,然后呈现数据即可。
package com.example.administrator.sideslipdeletedemo;
import android.app.Activity;
import android.os.Bundle;
import android.widget.ListView;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends Activity {
private ListView lsv_side_slip_delete;
private List<String> list = new ArrayList<>();
private SideSlipAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setViews();// 控件初始化
setData();// 初始化模拟数据
setAdapter();// 创建adapter,listview设置adapter
setListeners();// 设置监听
}
/**
* 设置监听
*/
private void setListeners() {
if (adapter != null){
// 注册监听器,回调用来刷新数据显示
adapter.setDelItemListener(new SideSlipAdapter.DeleteItem() {
@Override
public void delete(int pos) {
list.remove(pos);
adapter.notifyDataSetChanged();
}
});
}
}
/**
* 创建adapter并且listview设置adapter
*/
private void setAdapter() {
adapter = new SideSlipAdapter(this, list);
lsv_side_slip_delete.setAdapter(adapter);
}
/**
* 模拟初始化数据
*/
private void setData() {
for (int i = 0;i < 16;i++){
list.add("侧滑删除" + (i + 1));
}
}
/**
* 控件初始化
*/
private void setViews() {
lsv_side_slip_delete = findViewById(R.id.lsv_side_slip_delete);
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<ListView
android:id="@+id/lsv_side_slip_delete"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
适配器代码以及itemView的布局
package com.example.administrator.sideslipdeletedemo;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import com.mcxtzhang.swipemenulib.SwipeMenuLayout;
import java.util.List;
public class SideSlipAdapter extends BaseAdapter{
private LayoutInflater inflater;
private List<String> list;
private Context context;
public SideSlipAdapter(Context context, List<String> list) {
this.inflater = LayoutInflater.from(context);
this.list = list;
this.context = context;
}
@Override
public int getCount() {
return list.size();
}
@Override
public Object getItem(int position) {
return list.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
View closeView = null;
if (convertView == null){
convertView = inflater.inflate(R.layout.listview_item_delete, parent, false);
holder = new ViewHolder();
holder.tv_delete = convertView.findViewById(R.id.content);
holder.btn_top = convertView.findViewById(R.id.btnTop);
holder.btn_delete = convertView.findViewById(R.id.btnDelete);
convertView.setTag(holder);
}
if (closeView == null){
closeView = convertView;
}
final View finalCloseView = closeView;// listView的itemView
holder = (ViewHolder) convertView.getTag();
holder.tv_delete.setText(list.get(position));
// 置顶按钮的单击事件
holder.btn_top.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(context, "置顶", Toast.LENGTH_SHORT).show();
((SwipeMenuLayout)(finalCloseView)).quickClose();// 关闭侧滑菜单:需要将itemView强转,然后调用quickClose()方法
}
});
// 删除按钮的单击事件
holder.btn_delete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
((SwipeMenuLayout)(finalCloseView)).quickClose();// 关闭侧滑菜单
if (delItemListener != null){
delItemListener.delete(position);// 调用接口的方法,回调删除该项数据
}
}
});
return convertView;
}
/**
* 缓存控件用
*/
static class ViewHolder{
TextView tv_delete;// 展示内容
Button btn_top;// 置顶
Button btn_delete;// 删除
}
// 定义接口,包含了删除数据的方法
interface DeleteItem{
void delete(int pos);
}
private DeleteItem delItemListener;
// 设置监听器的方法
public void setDelItemListener(DeleteItem delItemListener){
this.delItemListener = delItemListener;
}
}
<?xml version="1.0" encoding="utf-8"?>
<com.mcxtzhang.swipemenulib.SwipeMenuLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:clickable="true"
app:swipeEnable="true"
app:leftSwipe="true"
app:ios="true">
<!-- itemView的内容,这里我简单的使用了一个textview。
如果是更加复杂的布局,大家可以在外面包裹一个父布局,如LineatLayout,
然后在这个父布局里面设置你想要展示的复杂内容。listview的每一个item展示的
内容就是这个布局确定的,必须要有。-->
<TextView
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?android:attr/selectableItemBackground"
android:gravity="center"
android:text="项目中我是任意复杂的原ContentItem布局"/>
<!-- 侧滑菜单选项,这里可以有多个选项。我这里就用了置顶和删除两个选项-->
<Button
android:id="@+id/btnTop"
android:layout_width="60dp"
android:layout_height="match_parent"
android:background="@android:color/darker_gray"
android:text="置顶"
android:textColor="@android:color/white"/>
<Button
android:id="@+id/btnDelete"
android:layout_width="60dp"
android:background="@android:color/holo_red_dark"
android:layout_height="match_parent"
android:text="删除"
android:textColor="@android:color/white"/>
</com.mcxtzhang.swipemenulib.SwipeMenuLayout>
效果图示
关键说明
我上面给出的代码和布局中,关键的就是listView的itemView的布局,这个布局我使用的根布局就是框架中的布局:SwipeMenuLayout。
需要设置一些必要的属性。
android:clickable="true"// 必要
app:swipeEnable="true"// 设置true
app:leftSwipe="true"// ture表示支持左滑,false表示支持右滑
app:ios="true"// 是否是IOS阻塞式交互
根布局设置的时候,上面就用如上设置即可。
我还在itemView的布局中添加了一些注释说明,itemView需要包含哪些内容。
若是在ListView、RecyclerView中使用,点击事件正确的设置应该是在 Adapter 里对 ContentItem 设置,不能使用listview.setOnItemClickListener。 因为此时 Item 是本控件了,不是里面的 ContentItem 那块区域了,且本控件区域有很多触摸的判断,内部包含 ContentItem 和侧滑菜单 Menu。
A little bit of progress every day!Come on!