ScrollView与ListView嵌套使用,导致ListView下拉失效

在一次项目开发中,在Scrollv中嵌套进ListView,当触摸ListView范围下拉时,整个展示页面滑动,而不是ListView内容滑动,

也就是说ListView滑动事件被ScrollView截掉(消费掉),没有向下子级View下传,而导致ListView无法滑动的效果,

        listview_list.setOnTouchListener(new View.OnTouchListener(){
            @Override
            public boolean onTouch(View view, MotionEvent even){
                if(even.getAction()==MotionEvent.ACTION_UP){
                    scollview_account.requestDisallowInterceptTouchEvent(false);
                }else{
                    scollview_account.requestDisallowInterceptTouchEvent(true);//屏蔽父控件的拦截事件
                }
                return false;
            }
        });

关于事件分发机制的部分:

listView..setOnItemClickListener()与listView.setOnItemLongClickListener()冲突问题(好像在Android 5.1之前没有这个问题),长按item时同样会触发item的点击事件,解决方法是将长按事件方法中,默认的return false改为return true即可;原因见:http://blog.csdn.net/u012527802/article/details/47338263

一、简介  :

  Activity或View类的onTouchEvent()回调函数会接收到touch事件。

  一个完整的手势是从ACTION_DOWN开始,到ACTION_UP结束。

  简单的情况下,我们只需要在onTouchEvent()中写个switch case语句,处理各种事件(Touch Down、 Touch Move、 Touch Up等),但是比较复杂的动作就需要更多的处理了。

  ViewGroup作为一个parent是可以截获传向它的child的touch事件的。

  如果一个ViewGroup的onInterceptTouchEvent()方法返回true,说明Touch事件被截获,子View不再接收到Touch事件,而是转向本ViewGroup的 onTouchEvent()方法处理。从Down开始,之后的Move,Up都会直接在onTouchEvent()方法中处理。

  先前还在处理touch event的child view将会接收到一个 ACTION_CANCEL。

  如果onInterceptTouchEvent()返回false,则事件会交给child view处理。

  Android中提供了ViewGroup、View、Activity三个层次的Touch事件处理。

  处理过程是按照Touch事件从上到下传递,再按照是否消费的返回值,从下到上返回,即如果View的onTouchEvent返回false,将会向上传给它的parent的ViewGroup,如果ViewGroup不处理,将会一直向上返回到Activity。

  即隧道式向下分发,然后冒泡式向上处理。

Android 中与 Touch 事件相关的方法包括:dispatchTouchEvent(MotionEvent ev)、onInterceptTouchEvent(MotionEvent ev)、onTouchEvent(MotionEvent ev);能够响应这些方法的控件包括:ViewGroup、View、Activity。方法与控件的对应关系如下表所示:

Touch 事件相关方法   方法功能     ViewGroup           View         Activity
  public boolean dispatchTouchEvent(MotionEvent ev) 事件分发   Yes  Yes  Yes
  public boolean onInterceptTouchEvent(MotionEvent ev)   事件拦截   Yes  Yes / No  No
  public boolean onTouchEvent(MotionEvent ev) 事件响应   Yes  Yes  Yes

从这张表中我们可以看到 ViewGroup 和 View 对与 Touch 事件相关的三个方法均能响应,而 Activity 对 onInterceptTouchEvent(MotionEvent ev) 也就是事件拦截不进行响应。另外需要注意的是 View 对 onInterceptTouchEvent(MotionEvent ev) 的响应的前提是可以向该 View 中添加子 View,如果当前的 View 已经是一个最小的单元 View(比如 TextView),那么就无法向这个最小 View 中添加子 View,也就无法向子 View 进行事件的拦截,所以它没有 onInterceptTouchEvent(MotionEvent ev)。

三个方法的用法:

dispatchTouchEvent() 用来分派事件。
其中调用了onInterceptTouchEvent()和onTouchEvent(),一般不重写该方法
onInterceptTouchEvent() 用来拦截事件。
ViewGroup类中的源码实现就是{return false;}表示不拦截该事件,
事件将向下传递(传递给其子View);
若手动重写该方法,使其返回true则表示拦截,事件将终止向下传递,
事件由当前ViewGroup类来处理,就是调用该类的onTouchEvent()方法
onTouchEvent() 用来处理事件。
返回true则表示该View能处理该事件,事件将终止向上传递(传递给其父View);
返回false表示不能处理,则把事件传递给其父View的onTouchEvent()方法来处理

【注】:ViewGroup的某些子类(GridView、ScrollView...)重写了onInterceptTouchEvent()方法,当发生ACTION_MOVE事件时,返回true进行拦截。

一、Touch 事件分析

(一)、事件分发:public boolean dispatchTouchEvent(MotionEvent ev)

Touch 事件发生时 Activity 的 dispatchTouchEvent(MotionEvent ev) 方法会以隧道方式(从根元素依次往下传递直到最内层子元素或在中间某一元素中由于某一条件停止传递)将事件传递给最外层 View 的 dispatchTouchEvent(MotionEvent ev) 方法,并由该 View 的 dispatchTouchEvent(MotionEvent ev) 方法对事件进行分发。

(二)、事件拦截:public boolean onInterceptTouchEvent(MotionEvent ev)

在外层 View 的 dispatchTouchEvent(MotionEvent ev) 方法返回系统默认的 super.dispatchTouchEvent(ev) 情况下,事件会自动的分发给当前 View 的 onInterceptTouchEvent 方法。onInterceptTouchEvent 的事件拦截逻辑如下:

  1. ?如果 onInterceptTouchEvent 返回 true,则表示将事件进行拦截,并将拦截到的事件交由当前 View 的 onTouchEvent 进行处理;
  2. ?如果 onInterceptTouchEvent 返回 false,则表示将事件放行,当前 View 上的事件会被传递到子 View 上,再由子 View 的 dispatchTouchEvent 来开始这个事件的分发;
  3. ?如果 onInterceptTouchEvent 返回 super.onInterceptTouchEvent(ev),事件默认不会被拦截,并将拦截到的事件交由当前 View 的 onTouchEvent 进行处理。

(三)、事件响应:public boolean onTouchEvent(MotionEvent ev)

在 dispatchTouchEvent 返回 super.dispatchTouchEvent(ev) 并且 onInterceptTouchEvent 返回 true 或返回 super.onInterceptTouchEvent(ev) 的情况下 onTouchEvent 会被调用。onTouchEvent 的事件响应逻辑如下:

  1. ?如果事件传递到当前 View 的 onTouchEvent 方法,而该方法返回了 false,那么这个事件会从当前 View 向上传递,并且都是由上层 View 的 onTouchEvent 来接收,如果传递到上面的 onTouchEvent 也返回 false,这个事件就会“消失”,而且接收不到下一次事件。
  2. ?如果返回了 true 则会接收并消费该事件。
  3. ?如果返回 super.onTouchEvent(ev) 默认处理事件的逻辑和返回 false 时相同。

onInterceptTouchEvent用于改变事件的传递方向。决定传递方向的是返回值,返回为false时事件会传递给子控件,返回值为true时事件会传递给当前控件的onTouchEvent(),这就是所谓的Intercept(拦截)。

正确的使用方法是,在此方法内仅判断事件是否需要拦截,然后返回。即便需要拦截也应该直接返回true,然后由onTouchEvent方法进行处理。

onTouchEvent用于处理事件,返回值决定当前控件是否消费(consume)了这个事件。尤其对于ACTION_DOWN事件,返回true,表示我想要处理后续事件;返回false,表示不关心此事件,并返回由父类进行处理。

可能你要问是否消费了又区别吗,反正我已经针对事件编写了处理代码?答案是有区别!比如ACTION_MOVE或者ACTION_UP发生的前提是一定曾经发生了ACTION_DOWN,如果你没有消费ACTION_DOWN,那么系统会认为ACTION_DOWN没有发生过,所以ACTION_MOVE或者ACTION_UP就不能被捕获。

在没有重写onInterceptTouchEvent()和onTouchEvent()的情况下(他们的返回值都是false)

Android系统中的每个View的子类都具有下面三个和TouchEvent处理密切相关的方法:

1)public boolean dispatchTouchEvent(MotionEvent ev) 这个方法用来分发TouchEvent

2)public boolean onInterceptTouchEvent(MotionEvent ev) 这个方法用来拦截TouchEvent

3)public boolean onTouchEvent(MotionEvent ev) 这个方法用来处理TouchEvent

1、如果dispatchTouchEvent返回true ,则交给这个view的onTouchEvent处理, 如果最终需要处理事件的view的onTouchEvent()返回了false,那么该事件将被传递至其上一层次的view的onTouchEvent()处理。如果最终需要处理事件的view 的onTouchEvent()返回了true,那么后续事件将可以继续传递给该view的onTouchEvent()处理。

2、如果dispatchTouchEvent返回 false ,则交给这个 view的interceptTouchEvent方法来决定是否

要拦截这个事件,如果 interceptTouchEvent 返回 true ,表示拦截掉了,则交给它的 onTouchEvent 来处理,如果 interceptTouchEvent 返回 false ,那么就传递给子view ,由子 view 的 dispatchTouchEvent 再来开始这个事件的分发。

3、如果事件传递到某一层的子 view 的onTouchEvent 上了,这个方法返回了 false ,那么这个事件

会从这个view 往上传递,都是 onTouchEvent 来接收。如果传递到最上面的 onTouchEvent 也返回 false 的话,这个事件就会“消失”,而且接收不到下一次事件。

【备注:】

onLongClick按下到一定的时间就调用了,在ACTION_UP之前调用。如果长按返回false,则长按结束的ACTION_UP调用onClick(onClick是ACTION_UP之后调用的);如果长按返回true,onLongClick后不再调用onClick。

Click事件处理

  Click事件:View的短按和长按都是注册监听器的(setListener):

  onClick是在ACTION_UP之后执行的。

  onLongClick则是按下到一定时间之后执行的,这个时间是ViewConfiguration中的:

  private static final int TAP_TIMEOUT = 180; //180毫秒

  这里需要注意onLongClick的返回值,如果是false,则onLongClick之后,手指抬起,ACTION_UP之后还是会执行到onClick;但是如果onLongClick返回true,则不会再调用onClick。

【备注:】

如果一个View是Clickable或者longClickable, onTouchEvent()就直接返回true, 表示该View就一直消费Touch事件。也就是说,一个clickable或者longclickable的View是一直消费Touch事件的,而一般的View既不是clickable也不是longclickable的(即不会消费Touch事件,只会执行ACTION_DOWN而不会执行ACTION_MOVE和ACTION_UP) 。

Button是clickable的,可以消费Touch事件,但是我们可以通过setClickable()和setLongClickable()来设置View是否为clickable和longClickable。当然还可以通过重写View的onTouchEvent()方法来控制Touch事件的消费与否。

参考链接:https://blog.csdn.net/androidforwell/article/details/52621866

原文地址:https://www.cnblogs.com/zty-Love/p/8658235.html

时间: 2024-10-10 17:43:28

ScrollView与ListView嵌套使用,导致ListView下拉失效的相关文章

安卓PopupWindow+ListView实现登录账号选择下拉框

这段时间在做android开发,发现自定义下拉框有很多种方法实现,我介绍一种PopupWindow+ListView的方式,实现起来比较灵活.效果: 直接看核心代码: Java代码   //获取文本框 etLoginName = (EditText)findViewById(R.id.login_edit_account); //自定义ListView的Adapter adapter=new myAdapter(); listView=new ListView(TestPopupWindowAc

android滑动组件嵌套一般思路,多任务手势思路,触摸传递思路,【例】listview嵌套viewpager

在android UI开发中,我们经常会遇到这种需求: 两个支持滑动的组件,比如listview嵌套多个listview,listview的item是一个viewpager或gallary?亦或是scrollview嵌套scrollview等等. 一般情况下,你还可能需要支持如下几种功能: ¤ 两层组件都可以滑动 ¤ 不让两个组件同时滑动,或者让两个组件同时滑动并可以自己调节 ¤ 不影响底层view的子view和嵌套view的子view的点击事件 实现上述功能时,我们也经常遇到一些问题: ¤ 点

ListView实现下拉刷新-1-实现ListView

即使你不是需要这个项目,但通过这个项目,你会知道android的一些基础知识,对初学者的话帮助会比较大! ListView做下拉刷新的源码为例,代码是有慕课网的老师提供的,真心感谢慕课网! 源码下载   (注意源码中,有两个类He,MyAdapter是为了测试而创建的,没有实际作用) 不是打广告(注意在边看解释的时候最好是边看代码) 综述:(分多篇的原因是:一起讲完的话,不一定能接受,而不是故意为了积分) 第一篇:实现LIstView:重点在MyAdapter的实现上和convertView回收

自定义下拉刷新ListView

PullToRefreshListView 原理:下拉刷新ListView无非就是对普通的List View添加一个HeaderView,然后通过对ListView onTouchEvent来获取当前下拉刷新的状态.然后去改变HeaderView的状态. 自定义ListView,在构造方法中去添加HeaderView 通过ListView.addHeaderView()去添加HeaderView的时候,HeaderView会显示在屏幕的最初位置,我们需要它默认的时候是在屏幕的上方,这样默认时是不

Android ListView下拉/上拉刷新:设计原理与实现

 <Android ListView下拉/上拉刷新:设计原理与实现> Android上ListView的第三方开源的下拉刷新框架很多,应用场景很多很普遍,几乎成为现在APP的通用设计典范,甚至谷歌官方都索性在Android SDK层面支持下拉刷新,我之前写了一篇文章<Android SwipeRefreshLayout:谷歌官方SDK包中的下拉刷新>专门介绍过(链接地址:http://blog.csdn.net/zhangphil/article/details/4696537

ListView下拉加载一(分页)

首先创建在主xml里放置一个listview列表,代码如下: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="fill_parent" android:layout_height="fill_par

Android学习之——ListView下拉刷新

背景知识 ListView使用非常广泛,对于使用ListView的应用来说,下拉刷新是必不可少要实现的功能. 我们常用的微博.网易新闻,搜狐新闻都使用了这一功能,如下图所示.     微博 搜狐新闻 具体学习: 首先分析下拉刷新的具体操作过程: 用户手指在ListView上按下并往下拉----->出现一个提示的View在ListView顶部----->ListView内容更新,顶部的提示View消失    具体实现步骤:    1.创建继承自ListView的RefreshListView,并

layui与jquery冲突导致下拉框无法显示的解决方法

1.背景: 在使用 layui 框架写 jsp 的时候,使用 ajax 传递数据来刷新表单,发现使用 ajax 引用外部的jquery 和 layui 自带的jquery中,可能是 $ 导致select 下拉框中的option 没法在layui中正常使用(即数据传过去了,但是点击下拉框没有任何数据) 2.解决 查了一下网上的解决方法.有个解决方法是 在layui.js之前引用其他jquery .但是发现 并没有什么卵用. 后来发现,ajax传递数据在加载页面之后,导致了导入的option没有在第

Android下拉刷新完全解析,教你如何一分钟实现下拉刷新功能

转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/9255575 最近项目中需要用到ListView下拉刷新的功能,一开始想图省事,在网上直接找一个现成的,可是尝试了网上多个版本的下拉刷新之后发现效果都不怎么理想.有些是因为功能不完整或有Bug,有些是因为使用起来太复杂,十全十美的还真没找到.因此我也是放弃了在网上找现成代码的想法,自己花功夫编写了一种非常简单的下拉刷新实现方案,现在拿出来和大家分享一下.相信在阅读完本篇文章之后,大