android 桌面点击位置不变,android listView中实现长按某个item出现的图片点击屏幕任意位置后自动消失的实现...

本文围绕Android聊天工具中长按历史消息出现删除图标,点击屏幕其他处图标消失的UI效果展开。介绍了UI界面结构,分析了Android的touch事件分发逻辑,通过实际操作验证相关说法,解决了点击位置与图标显示的问题,最终通过添加标志位解决实际难题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我们在使用诸如QQ、微信等聊天工具时,总会发现在长按历史消息会出现待办和删除的一个小图标。(其主要功能还是删除)点击删除,则该条记录就会消失。但是如果点击屏幕其他的地方,则待办和删除的小图标应该消失。这个小小的UI效果却花了我好几天来做出来。现在总结一下。

首先介绍一下UI界面的大致结构:我做的这个demo中,有一个mainactivity,在这个activity中包含有两个fragment。但需要注意的是,我们一般的做法是一个fragment替换另一个fragment,即被替换掉的fragment的生命周期会结束(至少走到了onDestroyView()这一步)。但实际上这两个fragment是可以具有相同的生命周期的。我的这个demo就是这种情况(具体步骤见我的其他文章,在此不赘述)。下面是这个显示历史记录的fragment的布局文件。

android:layout_width="match_parent"

android:layout_height="match_parent"

android:background="@color/common_white"

android:orientation="vertical"

android:clickable="true">

android:id="@+id/list"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:background="#fff4f7f9"

android:cacheColorHint="#00000000"

android:divider="#dddbdb"

android:dividerHeight="1.0px"

android:listSelector="@android:color/transparent"

android:scrollbars="none" />

android:id="@+id/deleteTalk"

android:layout_width="10dp"

android:layout_height="10dp"

android:src="@drawable/emoticon_big_tips3"

android:visibility="gone"/>

大家可以看到,这个布局文件是十分简单的。最外面是一个相对布局,因为我们后面需要在listView的相应item上面添加删除的图标,所以不能使用线性布局(否则图标显示不出来)。帧布局也是可以的,但由于我对于帧布局较陌生,故采用了相对布局。相对布局里面就定义了一个listView和一个ImageView。这个ImageView就是我们需要显示的删除的小图标。这个地方当时也想使用popWindow来做,因为那样就省去了添加点击任意地方图标消失的逻辑。但是在图片显示上面感觉效果不理想,故还是选用ImageView来做,自己添加相应的逻辑。而这也是问题的难点。

介绍完这些,我们就可以谈谈我们的难点问题。android的touch事件是一个绕不开的话题。网上的资料都比较一致。但是我在实际的操作中,发现在我这个demo里面貌似和网上谈到的不太一样,因此,我不敢盲信网上的说法。但还是先归纳一下网上靠谱一点的说法:

说法1:View和ViewGroup主要有三种方法:

public boolean dispatchTouchEvent(MotionEvent event),用于事件的分发,android所有的事件都要经过这个方法的分发。返回true表示不分发,false继续分发,若是ViewGroup,则分发给onInterceptTouchEvent判断是否拦截该事件。

public boolean onTouchEvent(MotionEvent event),用于事件的处理。

public boolean onInterceptTouchEvent(MotionEvent event),ViewGroup中特有的方法,负责事件的拦截,返回true时表示拦截当前事件,不继续向下分发,而是交给自身的onTouchEvent进行处理。返回false则不拦截,继续往下传。

说法2:当keydown的事件发生后,首先被传递到dispatchTouchEvent中,会先调用onUserInteraction方法(空方法,可被重写),再判断getWindow().superDispatchTouchEvent(ev)的结果(用于自定义的Window,若dispatchTouchEvent方法返回值为true,该函数也为true,不会执行onTouchEvent,若返回false,最终会执行onTouchEvent。红色部分结论和我的不一致,我的在这种情况下,是没有执行onTouchEvent,不知道为什么)。

说法3:从activity的dispatchTouchEvent方法进行事件分发开始的消息传递图:

12928831_201406181555570688.png

说法4:事件传递的两种方式:隧道方式:从根元素依次往下传递直到最内层子元素或在中间某一元素中由于某一条件停止传递。冒泡方式:从最内层子元素依次往外传递直到根元素或在中间某一元素中由于某一条件停止传递。 android对Touch Event的分发逻辑是View从上层分发到下层(dispatchTouchEvent函数)类似于隧道方式,然后下层优先开始处理Event(先mOnTouchListener,再onTouchEvent)并向上返回处理情况(boolean值),若返回true,则上层不再处理,类似于冒泡方式。

上面谈了很多,但说实话,足以把你转晕。但我觉得上面这些理论知识还是得稍微了解一下,才能继续进行下面的工作。不管对与错,至少你得知道你要注意些什么。

首先我们得弄清楚touch事件到底是个什么顺序在执行。(注意:在我的demo中mainactivity中的onTouchEvent一直没有执行,故对上面的相关说法持怀疑态度)

步骤1

在Mainactivity里面添加以下两个函数:

12928831_201406181621070542.png

还有fragment里面的代码(这里面的代码是一直没有改变的):

12928831_201406181622130883.png

上面代码中的ss就是我们要显示的删除的那个图标,它被定义为静态变量,因为它的实例化是在历史记录所在的fragment中,而在mainactivity中我们需要设置其可见性,故使用静态变量。此时在屏幕上随便点击一个地方,结果如下:

12928831_201406181631070234.png

验证了说法2 的部分结论。

步骤2

修改dispatchTouchEvent的最后一句为return super.dispatchTouchEvent(ev);

12928831_201406181637370544.png

其结果如下:

12928831_201406181638050059.png

会发现多出来了一句,这说明super.dispatchTouchEvent(ev)也调用了onUserInteraction()函数。

步骤3

下面我们需要看看当点击删除的图标时又会是个什么情况(长按item弹出图标的逻辑此处省略)。结果如下:

12928831_201406181645390367.png

这说明这次touch事件首先是在mainactivity中的dispatchTouchEvent函数分发,然后由ImageView来执行。

此时对于解决我们的实际问题实际上,已经够了。因为当我们点击屏幕任意一点时一定会调用dispatchTouchEvent,可以通过在dispatchTouchEvent添加让ImageView消失的逻辑。但在实际操作中遇到了问题:如果把这段逻辑添加到touchdown中,则会出现点击任何位置,图片都成功消失,包括点击图片的时候,因为dispatchTouchEvent在ImageView响应之前已经删掉了ImageView;而如果把这段逻辑放在touchup中,则会出现在长按item之后图片出现,松手后图片立马消失的现象。这个也是不行的。问题到了这里,有2条路走:1,想办法改变执行顺序。2.添加一些标志位,把上述不正常的状态剔除掉。我本来想选择第一种方式,进行了一些如下尝试

在各种搜索无果的情况下,我决定看看有哪些函数可以调用。结果找到了每一个View实例都可以直接调用dispatchTouchEvent函数,这个函数有什么作用呢?

步骤1  对mainactivity里面的函数做如下修改:

12928831_201406181722110081.png

步骤2:点击任意位置,结果如下:

12928831_201406181725520540.png

即ss.dispatchTouchEvent(ev)这个函数相当于把点击屏幕任意一点这个事件完整的搬过来了,对于点击屏幕任意一点,都让button有效的应用场景是十分重要的,但对于我们这里来说是没有意义的。

既然如此,那就走第二条路吧,添加两个标志位ImageClicked和LongClicked,问题最终得到解决。具体代码如下:

12928831_201406181742200042.png

这里return true是为了防止这个事件会传递给后面的Item的点击响应事件。还有就是ImageClicked和longclicked初始值均为0,longclicked在Item长按事件发生时被置为1。

12928831_201406181742200230.png

通过ImageClicked变量来标记图片被点击事件,通过longClicked变量来区分长按Item后松手与其他一般情况的点击。 其内在的逻辑就是检查图片是否被点击,是则让图片响应事件响应,activity中的dispatchTouchEvent不处理,否则让图片消失。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值