在一次项目开发中,在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

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

  1. Android 它们的定义ListView实现底部和页下拉刷新刷新的顶

    在项目开发.由于数据量过大,寻呼需要加载或下拉刷新.为了缓解长期等待-time负载.这个博客的评论中被自己的定义实例ListView实现底部的下拉刷新页面正在加载结果和顶部. 其效果图: 一.List ...

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

    这段时间在做android开发,发现自定义下拉框有很多种方法实现,我介绍一种PopupWindow+ListView的方式,实现起来比较灵活.效果: 直接看核心代码: //获取文本框 etLoginN ...

  3. css中overflow:hidden的属性 可能会导致js下拉菜单无法显示

    css中overflow:hidden属性导致ExtJS中无法显示下拉滚动条 overflow属性: visible 默认.内容不会被修剪,会呈现在元素之外. hidden 内容会被修剪,但是浏览器不 ...

  4. Qt qml listview 列表视图控件(下拉刷新、上拉分页、滚动轴)

    Qt qml listview下拉刷新和上拉分页主要根据contentY来判断.但要加上顶部下拉指示器.滚动条,并封装成可简单调用的组件,着实花了我不少精力:) [先看效果]    [功能] 下拉刷新 ...

  5. ListView下拉加载一(分页)

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

  6. 1、ListView自定义控件下拉刷新(一)

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layo ...

  7. Android学习之——ListView下拉刷新

    背景知识 ListView使用非常广泛,对于使用ListView的应用来说,下拉刷新是必不可少要实现的功能. 我们常用的微博.网易新闻,搜狐新闻都使用了这一功能,如下图所示.     微博 搜狐新闻 ...

  8. ListView嵌套GridView使用详解及注意事项

    ListView嵌套GridView即ListView的每个Item中都包含一个GridView:需要注意的是由于ListView和GridView都是可滑动的控件. 所以需要自定义GridView, ...

  9. 【Android - 自定义View】之自定义可下拉刷新或上拉加载的ListView

    首先来介绍一下这个自定义View: (1)这个自定义View的名称叫做 RefreshableListView ,继承自ListView类: (2)在这个自定义View中,用户可以设置是否支持下拉刷新 ...

随机推荐

  1. 【安卓中的缓存策略系列】安卓缓存策略之磁盘缓存DiskLruCache

    安卓中的缓存包括两种情况即内存缓存与磁盘缓存,其中内存缓存主要是使用LruCache这个类,其中内存缓存我在[安卓中的缓存策略系列]安卓缓存策略之内存缓存LruCache中已经进行过详细讲解,如看官还 ...

  2. Unity插件 - MeshEditor(三) 面片破碎&网格破碎

    网上的unity破碎插件很多,不过想着可以以自己的方式实现也不失为一种乐趣,虽然整体的表现性上显得有些差,但也并不会影响最终的效果,接下来我大致讲解一下破碎一个物体的流程,因为用到了协程计算碎片的原因 ...

  3. Caffe框架,训练model并测试数据

    1. 训练model #!/usr/bin/env sh ./build/tools/caffe train --solver=examples/focal_length/focal_solver.p ...

  4. 多进程log4cxx区分日志

    多进程log4cxx区分日志 (金庆的专栏) 网游客户端一般会多开,多个进程会写同一个日志文件.log4cxx看来会对文件加锁,防止多进程写同一文件写乱,截止目前还没发现错乱的日志. log4cxx有 ...

  5. java判断字符串是否回文

    java判断字符串是否回文 /** * java判断字符串是否回文<br><br> * 基本思想是利用字符串首尾对应位置相比较 * * @author InJavaWeTrus ...

  6. shell的case语句

    case语句格式 # vi test.sh : echo "input : " read num echo "the input data is $num" c ...

  7. javascript语法之number对象和Math对象

    这两个对象很简单,一个例子就能掌握用法. 一:number对象. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional// ...

  8. ZooKeeper实现分布式锁

    使用场景          一般的锁是指单进程多线程的锁,在多线程并发编程中,用于线程之间的数据同步,保证共享资源的访问.而分布式锁,指的是在分布式环境下,保证跨进程.跨主机.跨网络的共享资源,实现互 ...

  9. linux知识汇总

    1.     利用Ctrl+Alt+F1到Ctrl+Alt+F6在6个虚拟控制台之间切换,利用Ctrl+Alt+F7切换回图形界面. 2.     使用who命令来判断谁在系统上及其登录方式.id命令 ...

  10. Linux Platform Device and Driver

    从 Linux 2.6 起引入了一套新的驱动管理和注册机制 :Platform_device 和 Platform_driver . Linux 中大部分的设备驱动,都可以使用这套机制 , 设备用 P ...