A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

最近总结了一下Android事件分发机制。由于场景比较多,现先从最简单的场景开始讲解。一个FrameLayout嵌套一个LinearLayout,LinearLayout中嵌套一个View。我们接下来就来分析一下这个最经典,也是最简单的事件传递场景中,事件是如何传递的。

首先为了方便观察,先自定义一个MyFrameLayout,重写三个方法并添加日志:
[AppleScript] 纯文本查看 复制代码
package com.itheima.touchdemo;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;

public class MyFrameLayout extends FrameLayout {

        public MyFrameLayout(Context context, AttributeSet attrs, int defStyle) {
                super(context, attrs, defStyle);
                // TODO Auto-generated constructor stub
        }

        public MyFrameLayout(Context context, AttributeSet attrs) {
                super(context, attrs);
                // TODO Auto-generated constructor stub
        }

        public MyFrameLayout(Context context) {
                super(context);
        }

        // 事件处理
        @Override
        public boolean onTouchEvent(MotionEvent event) {
                System.out.println("FrameLayout---->onTouchEvent---start");
                boolean b = super.onTouchEvent(event);
                System.out.println("FrameLayout---->onTouchEvent---end---" + b);
                return b;
        }

        // 事件拦截
        @Override
        public boolean onInterceptTouchEvent(MotionEvent ev) {
                System.out.println("FrameLayout---->onInterceptTouchEvent---start");
                boolean b = super.onInterceptTouchEvent(ev);
                System.out.println("FrameLayout---->onInterceptTouchEvent---end---" +b);
                return b;
        }

        // 事件分发
        @Override
        public boolean dispatchTouchEvent(MotionEvent ev) {
                
                System.out.println(ev.getX() + "----- " + ev.getY());
                
                System.out.println("FrameLayout---->dispatchTouchEvent---start");
                boolean b = super.dispatchTouchEvent(ev);
                System.out.println("FrameLayout---->dispatchTouchEvent---end--->" + b);
                return b;
        }

}


同理自定义MyLinearLayout,并重写三个方法便于观察你:
[AppleScript] 纯文本查看 复制代码
package com.itheima.touchdemo;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.LinearLayout;

public class MyLinearLayout extends LinearLayout {


        public MyLinearLayout(Context context, AttributeSet attrs) {
                super(context, attrs);
                // TODO Auto-generated constructor stub
        }

        public MyLinearLayout(Context context) {
                super(context);
                // TODO Auto-generated constructor stub
        }

        // 事件处理
        @Override
        public boolean onTouchEvent(MotionEvent event) {
                System.out.println("LinearLayout---->onTouchEvent---start");
                boolean b = super.onTouchEvent(event);
                System.out.println("LinearLayout---->onTouchEvent---end---" + b);
                return b;
        }

                // 事件拦截
                @Override
                public boolean onInterceptTouchEvent(MotionEvent ev) {
                        System.out.println("LinearLayout---->onInterceptTouchEvent---start");
                        boolean b = super.onInterceptTouchEvent(ev);
                        System.out.println("LinearLayout---->onInterceptTouchEvent---end---" +b);
                        return b;
                }
        @Override
        public boolean dispatchTouchEvent(MotionEvent ev) {
                System.out.println("LinearLayout---->dispatchTouchEvent---start");
                boolean b = super.dispatchTouchEvent(ev);
                System.out.println("LinearLayout---->dispatchTouchEvent---end--->" + b);
                return b;
        }
}


自定义MyView,重写dispatchTouchEvent,onTouchEvent两个方法,并添加日志便于观察:
[AppleScript] 纯文本查看 复制代码
package com.itheima.touchdemo;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

public class MyView extends View {

        public MyView(Context context, AttributeSet attrs, int defStyle) {
                super(context, attrs, defStyle);
                // TODO Auto-generated constructor stub
        }

        public MyView(Context context, AttributeSet attrs) {
                super(context, attrs);
                // TODO Auto-generated constructor stub
        }

        public MyView(Context context) {
                super(context);
                // TODO Auto-generated constructor stub
        }
        // 事件处理
        @Override
        public boolean onTouchEvent(MotionEvent event) {
                System.out.println("View---->onTouchEvent---start");
                boolean b = super.onTouchEvent(event);
                System.out.println("View---->onTouchEvent---end---" + b);
                return b;
        }
        @Override
        public boolean dispatchTouchEvent(MotionEvent ev) {
                System.out.println("View---->dispatchTouchEvent---start");
                boolean b = super.dispatchTouchEvent(ev);
                System.out.println("View---->dispatchTouchEvent---end--->" + b);
                return b;
        }
}


Activity中初始化view时,动态将三个View依次嵌套起来:
[AppleScript] 纯文本查看 复制代码
package com.itheima.touchdemo;

import android.graphics.Color;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.Gravity;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.LinearLayout;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        View view = init_view();
        setContentView(view);
    }

    private View init_view() {

        MyFrameLayout myFrameLayout = new MyFrameLayout(this);

        myFrameLayout.setBackgroundColor(Color.RED);

        MyLinearLayout myLinearLayout = new MyLinearLayout(this);

        myLinearLayout.setBackgroundColor(Color.GREEN);

        FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(200, 200);

        params.gravity = Gravity.CENTER;

        myFrameLayout.addView(myLinearLayout, params);

        MyView myView = new MyView(this);

        myView.setBackgroundColor(Color.GRAY);
        LinearLayout.LayoutParams params1 = new LinearLayout.LayoutParams(100, 100);
        params1.gravity = Gravity.CENTER_VERTICAL;
        myLinearLayout.setGravity(Gravity.CENTER);
        myLinearLayout.addView(myView,params1);
//        FrameLayout.LayoutParams params2 = new FrameLayout.LayoutParams(100,
//                100);

//        params2.gravity = Gravity.CENTER;
//        myFrameLayout.setGravity(Gravity.CENTER);
//        myFrameLayout.addView(myView, params2);

        return myFrameLayout;
    }
}



红色的是MyFrameLayout,绿色的是MyLInearLayout,灰色的是MyView。现在我将手指按在灰色的区域按下时,事件的传递过程是这样的:
[AppleScript] 纯文本查看 复制代码
03-31 14:40:41.581 2465-2465/com.itheima.touchdemo I/System.out: FrameLayout---->dispatchTouchEvent---start
03-31 14:40:41.581 2465-2465/com.itheima.touchdemo I/System.out: FrameLayout---->onInterceptTouchEvent---start
03-31 14:40:41.581 2465-2465/com.itheima.touchdemo I/System.out: FrameLayout---->onInterceptTouchEvent---end---false
03-31 14:40:41.581 2465-2465/com.itheima.touchdemo I/System.out: LinearLayout---->dispatchTouchEvent---start
03-31 14:40:41.581 2465-2465/com.itheima.touchdemo I/System.out: LinearLayout---->onInterceptTouchEvent---start
03-31 14:40:41.581 2465-2465/com.itheima.touchdemo I/System.out: LinearLayout---->onInterceptTouchEvent---end---false
03-31 14:40:41.581 2465-2465/com.itheima.touchdemo I/System.out: View---->dispatchTouchEvent---start
03-31 14:40:41.582 2465-2465/com.itheima.touchdemo I/System.out: View---->onTouchEvent---start
03-31 14:40:41.582 2465-2465/com.itheima.touchdemo I/System.out: View---->onTouchEvent---end---false
03-31 14:40:41.582 2465-2465/com.itheima.touchdemo I/System.out: View---->dispatchTouchEvent---end--->false
03-31 14:40:41.582 2465-2465/com.itheima.touchdemo I/System.out: LinearLayout---->onTouchEvent---start
03-31 14:40:41.582 2465-2465/com.itheima.touchdemo I/System.out: LinearLayout---->onTouchEvent---end---false
03-31 14:40:41.582 2465-2465/com.itheima.touchdemo I/System.out: LinearLayout---->dispatchTouchEvent---end--->false
03-31 14:40:41.582 2465-2465/com.itheima.touchdemo I/System.out: FrameLayout---->onTouchEvent---start
03-31 14:40:41.582 2465-2465/com.itheima.touchdemo I/System.out: FrameLayout---->onTouchEvent---end---false
03-31 14:40:41.582 2465-2465/com.itheima.touchdemo I/System.out: FrameLayout---->dispatchTouchEvent---end--->false

从这个日志中不难看出,事件的传递流程是这样的。先从最外层的MyFrameLayout的dispatchTouchEvent开始,然后问自己的onInterceptTouchEvent是否拦截,不拦截然后将事件传递给MyLinearLayout的dispatchTouchEvent,然后调用MyLinearLayout的onInterceptTouchEvent是否拦截,不拦截,将事件传递给MyView的dispatchTouchEvent,因为Myview是最后一层,所以要调用onTouchEvent,看是否处理,如果不处理,再讲事件向上传递到MyLinearLayout的onTouchEvent,如果MyLinearLayout也不处理,事件接着向上传递到MyFrameLayout的onTouchEvent。如果MyFrameLayout也不处理,那么这个事件就会丢失,接下来的move事件up事件都不会再往下传递。

我们已经分析完了最简单,也是最经典的事件传递过程。这一篇就到这里。接下来我们下一篇再来一块分析一下如果MyFrameLayout,MyLinearLayout,MyView中有人处理这个事件。或者有人拦截这个事件,事件的传递过程又会怎样呢?敬请关注Android事件分发机制(二)。

1 个回复

正序浏览
多谢分享
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马