QQListview左滑删除,经典案例,高仿QQ左滑,动画效果,自定义!!

本文主要是介绍QQListview左滑删除,经典案例,高仿QQ左滑,动画效果,自定义!!,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

     虽然有很多开放写得已经很完美的listview开源框架, 用起来也很方便, 只需修改下布局,   大致套路都一样, 几乎没什么bug。 今天我们来看看自己定义的QQListview;


在这篇文章你能学到什么?

    

   1.事件冲突---listview 上下滑动和里面Item左右滑动 冲突(解决方法: 用外部拦截法, 判断滑动角度,是否大一定角度,然后进行拦截)

  2.VelocityTracker 使用, 计算;

3. handler结合targetview处理view动画(这里有多种方式比如Scroller , )



开始吧

    先看下Listview 的Item布局吧 


<span style="color:#3333ff;"><?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="horizontal" ><TextViewandroid:layout_gravity="right"android:id="@+id/dele"android:layout_width="100dp"android:layout_height="wrap_content"android:background="#ff0000"android:gravity="center"android:padding="20dp"android:text="删除"android:enabled="false"android:textColor="#fff" /><TextViewandroid:id="@+id/alp"android:layout_width="match_parent"android:layout_height="wrap_content"android:padding="20dp"android:background="#ffffff"android:text="A" /></FrameLayout></span>
      这里比较简单就一个FrameLayout,嵌套两个TextView,需要注意的是id为alp的TextView为前景TextView,id为deleTextView正常情况下是不可见, 我们要做的事情, 当user手势向左滑动的时候, 把deleTextView显示出来。


再来看看QQListView核心代码

 

public class QQListView extends ListView {/*** 屏幕宽度*/private int width;/*** 屏幕高度*/private int height;/*** 系统默认最小的滑动距离,*/private int slop;/*** 速度追踪者*/private VelocityTracker mVelocityTracker;/*** 当用户按下Item的时候记录的 前景TextView*/private View target;/*** 上一次X坐标*/private int lastX;/*** 上一次Y坐标*/private int lastY;/*** 滑动的模式*/private int scrollModel;/*** 判断是否需要改变滑动模式*/boolean isNeed=true;/*** 背景TextView宽度*/private int backgroudViewWidht;/*** 表示背景TextView是否已经显示*/boolean isShow=false;/*** 前景TextView*/private View showView;/*** 背景TextView*/private View backgroudView;public QQListView(Context context) {this(context,null);}public QQListView(Context context, AttributeSet attrs) {this(context, attrs,0);// 获取屏幕的宽高}public QQListView(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();height = displayMetrics.heightPixels;width = displayMetrics.widthPixels;slop = ViewConfiguration.get(getContext()).getScaledTouchSlop();}
这里贴了一些变量,和构造方法,  构造方法第一个构造方法调用第二个构造方法,第二个构造方法调用三个参数构造方法,一般来说, 第一个构造参数的构造方法在java文件new的时候调用,第二个构造方法在xml文件不指定style时候调用,指定调用第三个,我们这里初始化了,屏幕宽高;

onTouchEvent 的事件

 先看下down事件

     

<span style="font-size:24px;">case MotionEvent.ACTION_DOWN:if(isShow==true)  // 表示背景View(删除TextView)可见的时候,在触发down就把背景View 隐秘掉{Log.i("Info ", "is show");closeViewByAnimation(showView); }lastX=(int) ev.getX();  //获取当前X坐标(这里LastX是相对父控件)lastY=(int) ev.getY();getTargetView(ev,lastX,lastY);  //获取点击按下那个Item里面的前景TextViewbreak;</span>
    

这里说明一下,在onTouchEvent方法里面的Down 事件 必须返回super.onTouchEvent(ev) ,不然后续ItemOnItemClickListener等事件不会响应,具体要深入listview的源码,有兴趣的可以去了解下, listview本身为我们做了很多事件处理了。 我们这里主要获取下点击的Item(

<span style="font-size:24px;">getTargetView(ev,lastX,lastY);</span>
)获取对应的TextView,  也就是(前景TextView) 具体怎么获取 看下面

	private View getTargetView(MotionEvent ev,int x,int y) {mVelocityTracker=VelocityTracker.obtain();mVelocityTracker.addMovement(ev);ViewGroup viewGroup=(ViewGroup) this.getChildAt(pointToPosition(x, y)-this.getFirstVisiblePosition()); //获取外层的FrameLayoutif(viewGroup!=null)  //这里需要盘空,有各种意外情况  (比如点了分割线 没有获取到){View view=viewGroup.getChildAt(1);  //前景TextViewtarget=view; //赋值给target 我们要对target进行一系列动画处理backgroudView = viewGroup.getChildAt(0);   //获取backgroudview,然后其宽度backgroudView.setEnabled(true);backgroudViewWidht = backgroudView.getWidth();}return null;}


前面两行把速度追踪者初始化了  VelocityTracker    用来计算单位时间内用户滑动的像素。 看看Move事件吧


case MotionEvent.ACTION_MOVE:int moveX=(int) ev.getX();   //获取触摸当前move事件下得X Y坐标int moveY=(int) ev.getY();if(mVelocityTracker==null){mVelocityTracker=VelocityTracker.obtain();}mVelocityTracker.clear();  //清空一些数据mVelocityTracker.addMovement(ev); mVelocityTracker.computeCurrentVelocity(500);  //计算500ms 用户滑动速度,注意这里是有方向区别的if(scrollModel!=ITEMSCROLLMODE&&isNeed==true) //判断是不是item滑动模式{if(Math.abs(mVelocityTracker.getXVelocity())<=50){  Log.i("Info", "速度太慢无法触发 X:"+mVelocityTracker.getXVelocity());lastX=(int) ev.getX();lastY=(int) ev.getY();  //把当前X Y赋值给lastX lastYreturn super.onTouchEvent(ev);   // 这里触发listview上下滑动}Log.i("Info", "tag4");if(Math.abs(moveX-lastX)>Math.abs(moveY-lastY)){   //判断是左滑还是上下滑动, 这里默认X>Y则为Item滑动,也就是左滑删除scrollModel=ITEMSCROLLMODE;isNeed=false;}else{isNeed=false;}}if(moveX-lastX>0){//大于零 说明已经往右滑moveX=lastX;}if(scrollModel==LISTVIEWSCROLLMODEL||target==null){
//				 Log.i("Info", "scrollModel: "+ scrollModel);return super.onTouchEvent(ev);  //不处理, 交个listview 做上下滑动处理}else{int deltaX=moveX-lastX;ViewHelper.setTranslationX(target, deltaX); //移动target(前景TextView)显示背景TextView(删除TextView)return true;}

       Move事件处理可以说整个QQListView核心了,注释已经写的很详细了。这里做了很多逻辑代码判断, 继续看Up事件

   

case MotionEvent.ACTION_UP:try {mVelocityTracker.clear();  //清除下数据mVelocityTracker.recycle(); //回收下if(isShow){Log.i("Info", "消费事件");isShow=false;stateRestore();  //恢复先原来状态return true;    // 如果当前是显示状态, 把事件消费掉  结束整个事件分发}if(scrollModel==ITEMSCROLLMODE) {
//					Log.i("Info", "up return "+"true");restoreOrSmoonth(ev,target);  //关闭前景TextViewstateRestore();return true;} stateRestore();} catch (Exception e) {   //这里捕捉下异常Log.e("Info", "up  事件 异常");}break;}return super.onTouchEvent(ev);

      在UP事件把一些东西释放掉, 然后就是把显示的View关闭。 

     然后我们来看看动画吧  ,   这里来分析下, 在下图可以看出, 我们滑动大于一般的时候松开手, 会自动移动到把整个删除按钮都显示出来, 这里需要是实现 是用ViewHelper+Handler实现, 先简单讲下思路 ,删除按钮显示一半, 需要把另一把的长度计算出来, 这一段长度就是我们动画自动移动的长度, 把这一段长度, 分成若干帧

用算出来的长度/帧数=每帧移动的长度, 我这里默认30帧,默认 时长 1000ms 然后用handler  postMessageDelay()这里可以控制时间   总之核心思想 类似 微积分,把一个大的东西小分化了, 无数小东西,  这里也一样, 一秒播放了三十张图片  , 看代码吧


     

private void closeViewByAnimation(View showView_) {Message message=new Message();message.what=0x22;message.obj=showView_;from=-backgroudViewWidht;  distance=backgroudViewWidht;handler.sendMessage(message);}boolean isRuning=false;private Scroller mScroller;private void restoreOrSmoonth(MotionEvent ev ,View v) {Log.i("Info", "v:"+v+"   isRuning:"+isRuning);if(v==null||isRuning==true){return;}isRuning=true;int endX=(int) ev.getX();int deltaX=endX-lastX;Log.i("Info", "触发动画");if(deltaX<0){//左滑if(Math.abs(deltaX)>backgroudViewWidht/2){int oppsiteDeltaX=backgroudViewWidht-Math.abs(deltaX);Log.i("Info", "x oppsi:"+oppsiteDeltaX+"  deltaX:"+deltaX);from=deltaX;distance=-oppsiteDeltaX;Message message=handler.obtainMessage();Log.i("Info", "target:"+v);message.what=0x22;message.obj=v;handler.sendMessage(message);showView=v;isShow=true;//显示ViewLog.i("Info", "isShow:"+isShow);isRuning=false;}else{//如果滑动大于bacgroud的一半int oppsiteDeltaX=backgroudViewWidht-Math.abs(deltaX);Log.i("Info", "s oppsi:"+oppsiteDeltaX+"  deltaX:"+deltaX);from=deltaX;distance=-deltaX;Message message=handler.obtainMessage();message.what=0x22;message.obj=v;handler.sendMessage(message);Log.i("Info", "isShow_:"+isShow);isShow=false;isRuning=false;}}isRuning=false;}float from;  //从哪里开始float distance;  //滑动到哪里float frame=30;   //帧数float duration=100;  //时长float count=0;   //用于计数Handler handler=new Handler(){public void handleMessage(android.os.Message msg) {if(msg.what==0x22){if(count<=frame)   //小于帧数继续走{++count;View view=(View) msg.obj;Message message=handler.obtainMessage();message.what=0x22;message.obj=view;ViewHelper.setTranslationX(view, from+distance/frame*count);  //view移动的距离handler.sendMessageDelayed(message,(int)duration/100); //继续发送消息直到移动结束}else{count=0;}}};};
           这里的handler 主要用来控制时间和帧数    。。 好了 分析就到这里了 .





 

     


   

   

    


冲 突处理;

这篇关于QQListview左滑删除,经典案例,高仿QQ左滑,动画效果,自定义!!的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/343569

相关文章

Hadoop企业开发案例调优场景

需求 (1)需求:从1G数据中,统计每个单词出现次数。服务器3台,每台配置4G内存,4核CPU,4线程。 (2)需求分析: 1G / 128m = 8个MapTask;1个ReduceTask;1个mrAppMaster 平均每个节点运行10个 / 3台 ≈ 3个任务(4    3    3) HDFS参数调优 (1)修改:hadoop-env.sh export HDFS_NAMENOD

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

深入探索协同过滤:从原理到推荐模块案例

文章目录 前言一、协同过滤1. 基于用户的协同过滤(UserCF)2. 基于物品的协同过滤(ItemCF)3. 相似度计算方法 二、相似度计算方法1. 欧氏距离2. 皮尔逊相关系数3. 杰卡德相似系数4. 余弦相似度 三、推荐模块案例1.基于文章的协同过滤推荐功能2.基于用户的协同过滤推荐功能 前言     在信息过载的时代,推荐系统成为连接用户与内容的桥梁。本文聚焦于

电脑桌面文件删除了怎么找回来?别急,快速恢复攻略在此

在日常使用电脑的过程中,我们经常会遇到这样的情况:一不小心,桌面上的某个重要文件被删除了。这时,大多数人可能会感到惊慌失措,不知所措。 其实,不必过于担心,因为有很多方法可以帮助我们找回被删除的桌面文件。下面,就让我们一起来了解一下这些恢复桌面文件的方法吧。 一、使用撤销操作 如果我们刚刚删除了桌面上的文件,并且还没有进行其他操作,那么可以尝试使用撤销操作来恢复文件。在键盘上同时按下“C

【区块链 + 人才服务】可信教育区块链治理系统 | FISCO BCOS应用案例

伴随着区块链技术的不断完善,其在教育信息化中的应用也在持续发展。利用区块链数据共识、不可篡改的特性, 将与教育相关的数据要素在区块链上进行存证确权,在确保数据可信的前提下,促进教育的公平、透明、开放,为教育教学质量提升赋能,实现教育数据的安全共享、高等教育体系的智慧治理。 可信教育区块链治理系统的顶层治理架构由教育部、高校、企业、学生等多方角色共同参与建设、维护,支撑教育资源共享、教学质量评估、

客户案例:安全海外中继助力知名家电企业化解海外通邮困境

1、客户背景 广东格兰仕集团有限公司(以下简称“格兰仕”),成立于1978年,是中国家电行业的领军企业之一。作为全球最大的微波炉生产基地,格兰仕拥有多项国际领先的家电制造技术,连续多年位列中国家电出口前列。格兰仕不仅注重业务的全球拓展,更重视业务流程的高效与顺畅,以确保在国际舞台上的竞争力。 2、需求痛点 随着格兰仕全球化战略的深入实施,其海外业务快速增长,电子邮件成为了关键的沟通工具。

防近视护眼台灯什么牌子好?五款防近视效果好的护眼台灯推荐

在家里,灯具是属于离不开的家具,每个大大小小的地方都需要的照亮,所以一盏好灯是必不可少的,每个发挥着作用。而护眼台灯就起了一个保护眼睛,预防近视的作用。可以保护我们在学习,阅读的时候提供一个合适的光线环境,保护我们的眼睛。防近视护眼台灯什么牌子好?那我们怎么选择一个优秀的护眼台灯也是很重要,才能起到最大的护眼效果。下面五款防近视效果好的护眼台灯推荐: 一:六个推荐防近视效果好的护眼台灯的

【区块链 + 人才服务】区块链集成开发平台 | FISCO BCOS应用案例

随着区块链技术的快速发展,越来越多的企业开始将其应用于实际业务中。然而,区块链技术的专业性使得其集成开发成为一项挑战。针对此,广东中创智慧科技有限公司基于国产开源联盟链 FISCO BCOS 推出了区块链集成开发平台。该平台基于区块链技术,提供一套全面的区块链开发工具和开发环境,支持开发者快速开发和部署区块链应用。此外,该平台还可以提供一套全面的区块链开发教程和文档,帮助开发者快速上手区块链开发。

Flutter 进阶:绘制加载动画

绘制加载动画:由小圆组成的大圆 1. 定义 LoadingScreen 类2. 实现 _LoadingScreenState 类3. 定义 LoadingPainter 类4. 总结 实现加载动画 我们需要定义两个类:LoadingScreen 和 LoadingPainter。LoadingScreen 负责控制动画的状态,而 LoadingPainter 则负责绘制动画。