Android滑动列表(拖拽,左滑删除,右滑完成)功能实现(1)
场景:
近期做的TODO APP需要在主页添加一个功能,就是可以左滑删除,右滑完成。看了一下当前其他人做的例如仿探探式的效果,核心功能基本一样,但是和我预想的还是有少量区别,于是干脆自己重头学一遍如何自定义layout并且实现我所期望的功能。顺便写个傻瓜式教程,总结一下前人的经验。
需要:
Android Studio, RecyclerView
方法:
1. ItemTouchHelper
首先来看一下这个类的官方定义:
This is a utility class to add swipe to dismiss and drag & drop support to RecyclerView.
It works with a RecyclerView and a Callback class, which configures what type of interactions are enabled and also receives events when user performs these actions.
Depending on which functionality you support, you should override onMove(RecyclerView, ViewHolder, ViewHolder)
and / or onSwiped(ViewHolder, int)
.
This class is designed to work with any LayoutManager but for certain situations, it can be optimized for your custom LayoutManager by extending methods in the ItemTouchHelper.Callback
class or implementing ItemTouchHelper.ViewDropHandler
interface in your LayoutManager.
By default, ItemTouchHelper moves the items' translateX/Y properties to reposition them. You can customize these behaviors by overriding onChildDraw(Canvas, RecyclerView, ViewHolder, float, float, int, boolean)
or onChildDrawOver(Canvas, RecyclerView, ViewHolder, float, float, int, boolean)
.
Most of the time you only need to override onChildDraw
.
可以看出,这是一个可以支持RecyclerView实现用于滑动删除,拖拽效果的类。
他和recyclerview配合工作以确定什么样的交互方式可以使用,并且创建回调来对这些事件来进行接收
我们可以复写onMove和onSwiped来定义它的功能
这个类通常需要配合LayoutManager来使用
ItemHelper会将item重新移动,可以通过复写onChildDraw和onChildDrawOver来重新定义其行为
ok,我们直接用一下试试看
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerview);
recyclerView.setLayoutManager(new LinearLayoutManager(this, RecyclerView.VERTICAL, false));
MyAdapter adapter = new MyAdapter(list);
recyclerView.setAdapter(adapter);
ItemTouchHelper helper = new ItemTouchHelper(new ItemTouchHelper.Callback() {
@Override
public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
return 0;
} @Override
public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
return false;
} @Override
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) { }
});
helper.attachToRecyclerView(recyclerView);
运行之后,并没有任何效果,显然,这里我们需要定义之前说的回调来定义事件的接收,直接来看一下这个ItemTouchHelper.Callback的定义:
This class is the contract between ItemTouchHelper and your application. It lets you control which touch behaviors are enabled per each ViewHolder and also receive callbacks when user performs these actions.
To control which actions user can take on each view, you should override getMovementFlags(RecyclerView, ViewHolder)
and return appropriate set of direction flags. (LEFT
, RIGHT
, START
, END
, UP
, DOWN
). You can usemakeMovementFlags(int, int)
to easily construct it. Alternatively, you can use ItemTouchHelper.SimpleCallback
.
If user drags an item, ItemTouchHelper will call onMove(recyclerView, dragged, target)
. Upon receiving this callback, you should move the item from the old position (dragged.getAdapterPosition()
) to new position (target.getAdapterPosition()
) in your adapter and also call notifyItemMoved(int, int)
. To control where a View can be dropped, you can override canDropOver(RecyclerView, ViewHolder, ViewHolder)
. When a dragging View overlaps multiple other views, Callback chooses the closest View with which dragged View might have changed positions. Although this approach works for many use cases, if you have a custom LayoutManager, you can overridechooseDropTarget(ViewHolder, java.util.List, int, int)
to select a custom drop target.
When a View is swiped, ItemTouchHelper animates it until it goes out of bounds, then calls onSwiped(ViewHolder, int)
. At this point, you should update your adapter (e.g. remove the item) and call related Adapter#notify event.
这个包含三个主要函数:
getMovementFlags(): 用来定义哪些方向可以用,例如上下左右,用来处理拖拽,START和END用来处理侧滑
onMove() 在这里需要定义item是怎么移动的,从哪移动到哪,并且可以修改被移动所遮挡的其他view的行为,这里主要实现的是拖拽
onSwipe() 同理,这里实现滑动
ok,我们来具体实现上面各个方法:
getMovementFlags()
int makeMovementFlags (int dragFlags,
int swipeFlags)
Convenience method to create movement flags.
For instance, if you want to let your items be drag & dropped vertically and swiped left to be dismissed, you can call this method with: makeMovementFlags(UP | DOWN, LEFT);
这里我们使用它推荐的makeMovementFlags(int dragFlag,int swipeFlag)来构建返回结果,这里两个参数是由二进制表示的,转化成二进制后各位01表示是否有这个方向, 因此我们对这些方向做 或 ( | ) 操作来构成参数。
onMove()
boolean onMove (RecyclerView recyclerView,
RecyclerView.ViewHolder viewHolder,
RecyclerView.ViewHolder target)
Called when ItemTouchHelper wants to move the dragged item from its old position to the new position.
If this method returns true, ItemTouchHelper assumes viewHolder
has been moved to the adapter position of target
ViewHolder (ViewHolder#getAdapterPosition()
).
If you don't support drag & drop, this method will never be called.
viewHolder就是你正在拖拽的view,target就是你移动时被覆盖的view,想要实现拖拽效果,我们必须要更新从拖拽view到覆盖view之间所有item的位置,具体逻辑请看示例
onSwipe()
void onSwiped (RecyclerView.ViewHolder viewHolder,
int direction)
Called when a ViewHolder is swiped by the user.
If you are returning relative directions (START
, END
) from the getMovementFlags(RecyclerView, ViewHolder)
method, this method will also use relative directions. Otherwise, it will use absolute directions.
If you don't support swiping, this method will never be called.
ItemTouchHelper will keep a reference to the View until it is detached from RecyclerView. As soon as it is detached, ItemTouchHelper will call clearView(RecyclerView, ViewHolder)
.
这里我们直接找到当前的item,然后删掉它,接着notify一下就行了,当然我们可以定义方向来判断到底是左滑还是右滑
完整代码如下:
这里由于需要传入adapter的信息,因此我们重新创建个类extend ItemTouchHelper.Callback
package com.wjk32.myapplication; import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView; import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import android.widget.TextView; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; public class MainActivity extends AppCompatActivity { public static final String TAG="123";
public static final String TAG2="MainActivity"; String s="MainAc";
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i(TAG, TAG2+" onCreate");
setContentView(R.layout.activity_main);
List<String> list = new ArrayList<>();
for(int i=0;i<100;i++) {
list.add(""+i);
}
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerview);
recyclerView.setLayoutManager(new LinearLayoutManager(this, RecyclerView.VERTICAL, false));
final MyAdapter adapter = new MyAdapter(list);
recyclerView.setAdapter(adapter);
ItemTouchHelper helper = new ItemTouchHelper(new MyItemTouchCallback(adapter));
helper.attachToRecyclerView(recyclerView);
} public class MyItemTouchCallback extends ItemTouchHelper.Callback { private final MyAdapter adapter; public MyItemTouchCallback(MyAdapter adapter) {
this.adapter = adapter;
} @Override
public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
return makeMovementFlags(ItemTouchHelper.DOWN|ItemTouchHelper.RIGHT|ItemTouchHelper.UP|ItemTouchHelper.LEFT,
ItemTouchHelper.START|ItemTouchHelper.END);
} @Override
public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
int startPosition = viewHolder.getAdapterPosition();
int endPosition = target.getAdapterPosition();
//the item to swap
int index=startPosition; //drag direction
int dir=startPosition-endPosition>0?-1:1; while(index<endPosition){
Collections.swap(adapter.getmItemLists(), index,index+dir );
index+=dir;
} recyclerView.getAdapter().notifyItemMoved(startPosition, endPosition);
return true;
} @Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
int position = viewHolder.getAdapterPosition();
if (direction == ItemTouchHelper.END||direction == ItemTouchHelper.START) {
adapter.getmItemLists().remove(position);
adapter.notifyItemRemoved(position);
}
} } public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
private List<String> mItemLists; public class MyViewHolder extends RecyclerView.ViewHolder {
public TextView textView;
public MyViewHolder(TextView v) {
super(v);
textView = v;
}
} public List<String> getmItemLists() {
return mItemLists;
}
public MyAdapter(List<String> myDataset) {
mItemLists = myDataset;
} @Override
public MyAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
TextView v = (TextView) LayoutInflater.from(parent.getContext())
.inflate(R.layout.item, parent, false);
MyViewHolder vh = new MyViewHolder(v);
return vh;
} @Override
public void onBindViewHolder(MyViewHolder holder, int position) {
holder.textView.setText(mItemLists.get(position)); }
@Override
public int getItemCount() {
return mItemLists.size();
}
}
}
好了,到现在我们已经实现了基本的一些功能。
接下来我们将进行一些深入的探索。
参考
1. https://yuqirong.me/2017/02/03/RecyclerView%E5%AE%9E%E7%8E%B0%E6%8B%96%E6%8B%BD%E6%8E%92%E5%BA%8F%E5%92%8C%E4%BE%A7%E6%BB%91%E5%88%A0%E9%99%A4/
Android滑动列表(拖拽,左滑删除,右滑完成)功能实现(1)的更多相关文章
- Android滑动列表(拖拽,左滑删除,右滑完成)功能实现(2)
ItemTouchHelper类 之前我们实现了滑动列表的一些基本功能,为了实现更多的效果,我们来仔细看一下ItemTouchHelper中的类: ItemTouchHelper.SimpleCall ...
- RecyclerView进阶:使用ItemTouchHelper实现拖拽和侧滑删除
现在RecyclerView的应用越来越广泛了,不同的应用场景需要其作出不同的改变.有时候我们可能需要实现侧滑删除的功能,比如知乎首页的侧滑删除,又或者长按Item进行拖动与其他Item进行位置的交换 ...
- ListView列表拖拽排序
ListView列表拖拽排序能够參考Android源代码下的Music播放列表,他是能够拖拽的,源代码在[packages/apps/Music下的TouchInterceptor.java下]. 首 ...
- h5页面ios,双击向上滑动,拖拽到底部还能继续拖拽(露出黑色背景)
h5页面ios,双击向上滑动,拖拽到底部还能继续拖拽 标签: 手机 2016-02-02 18:09 696人阅读 评论(0) 收藏 举报 在ios下,双击屏幕某些地方,滚动条会自动向上走一段. ...
- Appium(九):Appium API(三) 滑动和拖拽、高级手势、手机操作
1. 滑动和拖拽 我们在做自动化测试的时候,有些按钮是需要滑动几次屏幕后才会出现,此时,我们需要使用代码来模拟手指的滑动,也就是接下来要学的滑动和拖拽了. 1.1 swipe滑动事件 从一个坐标位置滑 ...
- Taro UI开发小程序实现左滑喜欢右滑不喜欢效果
前言:年后入职了一家新公司,与前同事交接完之后,发现公司有一个四端的项目(iOS,Android,H5,小程序),iOS和安卓都实现了左滑右滑的效果,而h5和小程序端没实现,询问得知前同事因网上没找到 ...
- js判断手指的上滑,下滑,左滑,右滑,事件监听
原理:1:当开始一个touchstart事件的时候,获取此刻手指的横坐标startX和staerY: 2:当触发touchmove事件的时候,再获取此时手指的横坐标moveEndX和纵坐标moveEn ...
- Android中GridView拖拽的效果【android进化三十六】
最 近看到联想,摩托罗拉等,手机launcher中有个效果,进入mainmenu后,里面的应用程序的图标可以拖来拖去,所以我也参照网上给的代码,写了 一个例子.还是很有趣的,实现的流畅度没有人家的 ...
- Android中GridView拖拽的效果
最 近看到联想,摩托罗拉等,手机launcher中有个效果,进入mainmenu后,里面的应用程序的图标可以拖来拖去,所以我也参照网上给的代码,写了 一个例子.还是很有趣的,实现的流畅度没有人家的那么 ...
随机推荐
- SVN的安装与使用教程
转载:http://www.cnblogs.com/armyfai/p/3985660.html SVN简介: 为什么要使用SVN? 程序员在编写程序的过程中,每个程序员都会生成很多不同的版本,这就需 ...
- EOCS 最低资源保障机制
本期小E将为大家带来EOCS 最低资源保障机制. 为满足普通用户日常的转账等基本需求,无需再为较少的初始资源抵押担心无法使用链上功能.EOCS可以通过链的参数来调整分配给每个用户免费的资源额度,相当于 ...
- linux中gcc和g++的区别
1.两者都是编译器 2.gcc编译c语言:g++既可以编译c语言,也可以编译c++语言 3.gcc不能自动链接库文件,一般用g++来链接库文件,非要用gcc的话,一般使用gcc -lstdc++命令 ...
- 【原创】Linux基础之vi
vi配置文件 ~/.vimrcor/etc/vimrc 模式 命令模式(Command Mode) 1 上/下/左/右移动光标 i/k/j/l 2 跳到文件末尾 G 3 跳到文件开头 gg 4 向下搜 ...
- JVM内存模型分析(一个程序运行的例子)
(.class字节码)类加载到内存之后,内存模型:(ps:.class文件可以通过javap 指令反编译成一个可读文件) 1.java栈,本地方法栈,程序计数器(每个线程私有) 看如下程序: 以该程序 ...
- String,下表和切片,分割
字符串介绍 1.字符串在内存中的存储 2.字符串的加法 3.字符串的格式化 1. 下标索引 所谓“下标”,就是编号,就好比超市中的存储柜的编号,通过这个编号就能找到相应的存储空间 字符串中" ...
- html获取输入框的值
https://zhinan.sogou.com/guide/detail/?id=316512383339
- 《剑指offer》左旋转字符串
本题来自<剑指offer> 反转链表 题目: 思路: C++ Code: Python Code: 总结:
- js &运算符什么意思,什么用处
“&&”连接两个表达式,当两侧表达式都为真时,返回TRUE.有一个为假则返回FALSE. 也就是说,符号前面的如果为true,就会执行符号后面的语句,如果符号前面的为false,那么后 ...
- PDF中的空白页面怎么删除,PDF页面删除技巧
在Word中想要删除其中一页文档的怎么办?直接打开就可以删除了,那么我们如何删除PDF其中几页呢?下面小编就来告诉大家PDF删除页面跟空白页面的方法.想要删除PDF文档中的页面,可以使用PDF编辑器, ...