高级UI--事件处理(六)

本节内容包括

  • 事件分发机制
  • ListView和ScrollView的冲突处理
  • viewPager简易实现

事件分发机制

一、View的事件分发传递
测试结果:
1.控件的Listener事件触发的顺序是先onTouch,再onClick。】
2.控件的onTouch返回true,将会onClick事件没有了---阻止了事件的传递。返回false,才会传递onClick事件(才会传递up事件)

源码分析:
    1.dispatchTouchEvent();
    2.onTouchListener-->onTouch方法
    3.onTouchEvent
    4.onClickListener-->onClick方法

源码设计(View的dispatchTouchEvent源码):
    1.如果onTouchListener的onTouch方法返回了true,那么view里面的onTouchEvent就不会调用了。
    调用顺序:
    dispatchTouchEvent-->onTouchListener-->onTouch方法(return false)-->onTouchEvent
    2.如果view为disenable,则:onTouchListener里面不会执行,但会执行onTouchEvent
    3.onTouchEvent方法中的ACTION_UP分支中触发onClick事件监听

二、ViewGroup+View的事件分发传递
ViewGroup-->View
    1.dispatchTouchEvent();
    2.onTouchEvent();
    3.onInterceptTouchEvent();拦截触摸事件
  先接触到事件的是父容器。
  顺序:
    dispatchTouchEvent-->onInterceptTouchEvent-->onTouchListener-->onTouch(return false)-->onTouchEvent

ViewGroup源码分析

//源码2520行
dispatchTransformedTouchEvent(){
     if(child == null){//如果viewGroup里面没有子控件就交给自己处理
            handled = super.dispatchTouchEvent(event);
      }else{
            handled = child.dispatchTouchEvent(event);
      }
}

测试DemoEventDeliver事件分发顺序

dispatchTouchEvent====0====MyRelativeLayout
onInterceptTouchEvent====0====MyRelativeLayout
dispatchTouchEvent====0====MyButton
onTouchListener====0====2131427423
onTouchEvent====0====MyButton
dispatchTouchEvent====1====MyRelativeLayout
onInterceptTouchEvent====1====MyRelativeLayout
dispatchTouchEvent====1====MyButton
onTouchListener====1====2131427423
onTouchEvent====1====MyButton
onClickListener====2131427423

参考文献
1.图解 Android 事件分发机制

ListView和ScrollView的冲突处理

(1). 在ScrollView控件中设置固定高度ListView控件,并用其他控件(如TextView)占据超过屏幕剩余空间。这样滑动界面的时候,只会触发ScrollView的滚动,而不能触发ListView的滑动。
解决方法:

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        //不要拦截
        requestDisallowInterceptTouchEvent(true);
        return super.dispatchTouchEvent(ev);
    }

调用requestDisallowInterceptTouchEvent(true)不拦截子控件的事件
(2). ScrollView嵌套ListView,ListView完全展开
布局如下:

<?xml version="1.0" encoding="utf-8"?>
<com.andryyu.eventdeliver.test2.MyScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.andryyu.eventdeliver.test2.Test2Activity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <com.andryyu.eventdeliver.test2.MyListView
            android:id="@+id/lv_test2"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="200dp"
            android:text="周末愉快,各位大宝贝!" />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="200dp"
            android:text="周末愉快,各位大宝贝!" />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="200dp"
            android:text="周末愉快,各位大宝贝!" />
        ....

无论ListView的高度怎么设置,都会只显示一行的高度,那是由于ListView的父容器测量模式为UNSPECIFIED的时候,ListView的高度默认为一个item的高度。ListView中源码如下:

if (heightMode == MeasureSpec.UNSPECIFIED) {
    heightSize = mListPadding.top + mListPadding.bottom + childHeight +
                   getVerticalFadingEdgeLength() * 2;
}

解决方法:重写ListView的onMeasure方法

 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //int size = MeasureSpec.getSize(heightMeasureSpec);
        //int mode = MeasureSpec.getMode(heightMeasureSpec);
        //>>右移运算符
        int expandedHeight  = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE>>2, MeasureSpec.AT_MOST);

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  }

原理分析:
我们把高度写成了一个固定值expandSpec ,这个值是这样计算出来的

int expandedHeight  = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE>>2, MeasureSpec.AT_MOST);

这和android的实体测量机制有关了,android中规定,测量的值(高度或宽度)为一个int类型,但不是普通的int,而是一个进过处理的int,在view视图中我们制定一个高度需要2个参数,1个是具体的值,一个是测量模式,测量模式就是我们在布局中经常用到的MATCH_PARENT 、WRAP_CONTENT。他们是一个int型的常量,对应的值分别是:

LayoutParams.MATCH_PARENT  对应 MeasureSpec.EXACTLY
LayoutParams.WRAP_CONTENT  对应 MeasureSpec.AT_MOST

而EXACTLY和AT_MOST的值是:

private static final int MODE_SHIFT = 30;      

public static final int EXACTLY     = 1 << MODE_SHIFT;    //填满父控件高度
public static final int AT_MOST     = 2 << MODE_SHIFT;    //自适应当前控件高度

android中把测量出的int做了处理,int的长度时32位,把前2位作为标志位标示了测量模式,如EXACTLY、AT_MOST ,把后30位作为测量的具体高度或宽度。 也就是说,把一个int分成了2部分,使一个int值同时拥有了模式和具体数值的2部分信息!

EXACTLY的值是1向左进位30,就是01 00000000000…(01后跟30个0) 
AT_MOST的值是2向左进位30,就是10 00000000000…(10后跟30个0)

所以我们在调用MeasureSpec.makeMeasureSpec(size,mode)方法时,传入的size参数要把Integer.MAX_VALUE右移2位,因为前两位会被认为是标志,而不是值。这样我们传入的参数才会被认为是最大的int类型的值,同时传入AT_MOST作为模式,那么前两位就会被赋值为10。

参考文献
1.android开发游记:ScrollView嵌套ListView,ListView完全展开及makeMeasureSpec测量机制原理分析

ViewPager简易实现

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容