Android条目拖拽删除功能实例代码
作者:王虎的博客 发布时间:2022-06-19 22:47:37
项目中需求,要做条目条目拖拽删除效果,实际效果和QQ消息删除一样,侧滑有制定和删除。
效果图
第一步效果图
1.0自定义控件 SwipeLayout 继承FrameLayout重写里面三个构造方法,分别调用initView().
2.0在布局中使用自定义控件
3.0在initView()方法中,创建拖拽辅辅助工具 ViewDragHelper()
该方法需要传入回调 MyCallBack()
4.0,创建MyCallBack()回调,继承ViewDragHelper.Callback
在回调中 覆盖tryCaptureView方法,返回true 允许child被拖拽,被 覆盖clampViewPositionHorizontal 返回left系统提供拖拽位置
5.0 onInterceptTouchEvent 返回:让ViewDragHelper判断是否需要拦截事件
6.0 onTouchEvent 返回true 并且让ViewDragHelper分析事件
具体代码:
布局:
<cn.itheima.swipelayout.SwipeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!--正文部分-->
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#fff"
android:orientation="horizontal">
<TextView
android:id="@+id/item_tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="张三"
android:textSize="20sp" />
</RelativeLayout>
<!--按钮部分-->
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#888888"
android:padding="10dp"
android:text="呼叫"
android:textSize="20sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#f00"
android:padding="10dp"
android:text="删除"
android:textSize="20sp" />
</LinearLayout>
</cn.itheima.swipelayout.SwipeLayout>
SwipeLayout 代码:
public class SwipeLayout extends FrameLayout {
private ViewDragHelper mDragHelper;
public SwipeLayout(Context context) {
super(context);
initView();
}
public SwipeLayout(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
public SwipeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView();
}
private void initView() {
mDragHelper = ViewDragHelper.create(this,new MyCallBack());
}
// 让ViewDragHelper就是拖拽辅助工具 返回true 则表示要拦截触摸事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
//让拖拽辅助工具判断是否需要拦截 事件
return mDragHelper.shouldInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
//让拖拽辅助工具分析事件 分析用户手势
mDragHelper.processTouchEvent(event);
return true;
}
private class MyCallBack extends ViewDragHelper.Callback{
/**
* 如果返回 true 则表示 child 允许被拖拽
*/
@Override
public boolean tryCaptureView(View child, int pointerId) {
return true;
}
/**
* 固定被拖拽控件的水平位置,
* 参数里的 left 是系统推荐移动到的位置,可以进行修正,
* 方法返回的值就是 child 将要移动到的位置
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
return left;
}
}
}
第二步:
1.0创建onFinishInflate方法获取子控件,并且判断健壮性
/*
控件初始化时执行,可以用于获取子控件
*/
@Override
protected void onFinishInflate() {
// 健壮性检查
if (getChildCount()!=2){
throw new RuntimeException("SwipeLayout 必须存放两个子控件");
}
if (!(getChildAt(0) instanceof ViewGroup)||!(getChildAt(1) instanceof ViewGroup)){
throw new RuntimeException("SwipeLayout 的子控件必须是 ViewGroup");
}
mContent = (ViewGroup) getChildAt(0);
mDeletePanel = (ViewGroup) getChildAt(1);
}
2.0创建onSizeChanged方法,在控件大小改变的时候调用,获取控件的宽高,和删除的面板的最大移动范围
/**
* 当控件大小改变的时候调用这个方法
*/
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
int mWith = w;
int mHeigth = h;
//界面创建过程中,不能使用 getWidth 方法
int mRang = mDeletePanel.getMeasuredWidth();
}
3.0在onLayout中指定侧拉面板的位置
//指定侧拉面板的位置
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
mDeletePanel.layout(mWith,0,mWith+mRang,mHeigth);
}4.0在onViewPositionChanged方法中实现联动效果
/**
* 当被拖拽的控件已经移动过后,会调用这个方法,可以用于处理控件间的联动效果
* @left 被拖拽控件的真实移动位置
* @dx 被拖拽控件的真实偏移大小
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
if (changedView==mContent){
// 移动正文的同时也要移动侧栏
mDeletePanel.offsetLeftAndRight(dx);
}else{
mContent.offsetLeftAndRight(dx);
}
}
5.0在 clampViewPositionHorizontal方法中 固定被拖拽控件的水平位置,
/**
* 固定被拖拽控件的水平位置,
* 参数里的 left 是系统推荐移动到的位置,可以进行修正,
* 方法返回的值就是 child 将要移动到的位置
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
if (child==mContent){
if (left>0){
left=0;
}else if (left<-mRang){
left=-mRang;
}
}else{
if (left>mWith){//mWith是屏幕的宽度
left=mWith;
}else if (left<mWith-mRang){
left=mWith-mRang;
}
}
return left;
}
第三步:
效果图
1.0onViewReleased中根据来开局里面,判断是否打开还是关闭
2.0 在 moveContent中第一次滑动
3.0computeScroll中,继续滑动,直到滑动到指定的位置
4.0注意在onViewPositionChanged中手动刷新界面,调用invalidate方法
如果不手动刷新界面,效果展示不出来
/**
* 当用户松手时执行
* @xvel 松手时在 X 方向的移动速度,如果为 正数 则说明是向右移动,如果是 负数 则说明是向左移动,如果为零,说明是静止状态
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
if (xvel>0){
//向右移动
close();
}else if (xvel<0){
//向左移动
opend();
}else if (xvel>-mRang/2){// 静止状态
close();// 展开不到一半,关闭面板
}else{
opend();
}
}
}
/**
* 打开面板
*/
private void opend() {
int left=-mRang;
moveContent(left);
}
/**
* 关闭面板
*/
private void close() {
int left=0;
moveContent(left);
}
private void moveContent(int left) {
// 开启平滑滚动,如果返回 true 则说明要继续刷新界面,保持滚动
if(mDragHelper.smoothSlideViewTo(mContent,left,0)){
invalidate();
}
}
@Override
public void computeScroll() {
// 继续平滑滚动,如果返回 true 则说明要继续刷新界面,保持滚动
if (mDragHelper.continueSettling(true)){
invalidate();
}
}
第四步:
1.0现给ListView赋值 在这就省略
2.0在SwipeLayout中使用枚举记录面板的状态
private enum Status{
CLOSED,OPENED,DRAGING;
}
private Status status = Status.CLOSED;
public Status getStatus() {
return status;
}
3.0// 记录上一个打开的面板。注意:一定要是 静态变量
private static SwipeLayout preSwipeLayout;
4.0在onViewPositionChanged中创建一个方法操作关闭面板
// 关闭上一个打开的面板
closePre();5.0closePre()在这个方法中,判断当前面板的状态,并且根据状态,关闭上一个打开的面板
// 判断当前面板是否正在打开,如果正在打开则将上一个打开的面板关闭
private void closePre() {
//记录旧状态
Status preStatus=status;
if (mContent.getLeft()==-mRang){
//记录当前面板已经打开
status=status.OPENED;
}else if (mContent.getLeft()==0){
//当前面板已经关闭
status=status.CLOSED;
}else {
status=status.DRAGING;
}
// 如果当前面板旧状态为关闭,并且新状态为拖拽,那么此时可以关闭之前打开的面板
if (preStatus==status.CLOSED&&status==status.DRAGING){
if (preSwipeLayout!=null&&preSwipeLayout!=this){
// 关闭上一个面板
preSwipeLayout.close();
}
// 将当前面板标记为 打开的面板
preSwipeLayout=this;
}
}
总结
以上所述是小编给大家介绍的Android条目拖拽删除功能实例代码网站的支持!
来源:http://blog.csdn.net/wangxiaohuhu1314/article/details/76973904


猜你喜欢
- Mybatis-plus全局id生成策略在配置文件中加入以下代码后就不需要在实体类种的id上添加@TableId(value = “id”,
- 产品在测试过程中发现一个bug,就是测试人员不停的疯狂的点击某个按钮,触发了toast以后,toast内容会一直排着队的显示出来,不能很快的
- WPF的InkCanvas就是一个画板,可以在上面随意涂鸦,每写上一笔,InkCanvas的Strokes集合里就新增一个涂鸦对象,下面的代
- 朋友让我帮忙写个程序从文本文档中导入数据到oracle数据库中,技术上没有什么难度,文档的格式都是固定的只要对应数据库中的字段解析就行了,关
- 前言之前写过 Mybatis Plus 的基本配置和使用。Mybatis-Plus 看这一篇就够了当初在进行查询时,虽然没有写硬SQL进行查
- 我们都知道mybatis在进行参数判断的时候,直接可以用<if test=""></if> 就可
- 1.先下载微信分享的jar包放在lib目录下,并且添加依赖,清单文件添加<activity
- Condition是在Spring 4.0 增加的条件判断功能,通过这个可以功能可以实现选择性的创建 Bean操作。思考:SpringBoo
- 背景在使用Spring Boot Mvc的项目中,使用Long类型作为id的类型,但是当前端使用Number类型接收Long类型数据时,由于
- 知识准备需要了解POI工具,以及POI对Excel中的对象的封装对应关系。什么是POIApache POI 是用Java编写的免费开源的跨平
- 一、容器初始化1、源码分析在jdk8的ConcurrentHashMap中一共有5个构造方法,这四个构造方法中都没有对内部的数组
- 本文根据java开发人员在编码过程中容易忽视或经常出错的地方进行了整理,总结了十个比较常见的低级错误点,方便大家学习。1、不能用“==”比较
- 众所周知在android7.0,修改了对私有存储的限制,导致在获取资源的时候,不能通过Uri.fromFile来获取uri了我们需要适配7.
- 我们在实际开发中,有的时候需要储存或者备份比较复杂的数据。这些数据的特点是,内容多、结构大,比如短信备份等。我们知道SharedPrefer
- 一、什么是桥接模式桥接模式(Bridge Pattern):将抽象部分与它的实现部分分离,使它们都可以独立地变化。它是一种对象结构型模式,又
- 1、注解(Annotation)1.1 什么是注解(Annotation)注解不是程序本身,可以在程序编译、类加载和运行时被读取,并执行相应
- 本文实例为大家分享了Android SeekBar实现平滑滚动的具体代码,供大家参考,具体内容如下由于项目需要,SeekBar只需要三个档,
- 1.背景由于公司的日志系统使用的是plumelog,最近生产环境老是报 jedis连接池不够,导致丢失日志,而且服务老是重启,怀疑跟日志系统
- 本文实例为大家分享了OpenCV+Qt实现图像处理操作的具体代码,供大家参考,具体内容如下一、目标Qt界面实现 雪花屏 高斯模糊 中值滤波
- 测试例:PageElement pe = new PageElement();pe.LoadDataFromJsonString("