android View——事件分发

项目地址:项目地址包含之前的内容

  • 介绍
  • 示例
  • 源码浅析

对于Android中的事件,最常见到的就是点击事件。那么点击在屏幕上,最终怎么响应在设置的控件上的呢?

三个重要的方法

了解这些需要先知道三个方法

  1. dispatchTouchEvent
    此方法View和ViewGroup中都有。
public boolean dispatchTouchEvent (MotionEvent event)

将触摸屏运动事件传递给目标视图,如果目标是该视图,则传递给该视图。如果事件是由视图处理的,则返回true。

  1. onInterceptTouchEvent
    此方法只在ViewGroup中
public boolean onInterceptTouchEvent (MotionEvent ev)

实现此方法来拦截所有触摸屏运动事件。这允许您在事件被发送给孩子时监视它们,并在任何时候拥有当前手势的所有权。
使用这个函数需要注意,因为它与视图#onTouchEvent(MotionEvent)的交互相当复杂,使用它需要以正确的方式实现这个方法和这个方法。活动将按以下顺序接收:

  1. 您将在这里接收到down事件
  2. down事件将由这个视图组的一个子视图组处理,或者指定给您自己的onTouchEvent()方法来处理;这意味着您应该实现onTouchEvent()来返回true,这样您将继续看到手势的其余部分(而不是寻找父视图来处理它)。此外,通过从onTouchEvent()返回true,您将不会在onInterceptTouchEvent()中接收任何以下事件,所有触摸处理都必须像正常情况一样在onTouchEvent()中发生。
  3. 只要从这个函数返回false,接下来的每个事件(直到并包括最终的up)都将首先在这里交付,然后交付给目标的onTouchEvent()。
  4. 如果您从这里返回true,您将不会接收到任何以下事件:目标视图将接收到相同的事件,但是带有action MotionEvent.ACTION_CANCEL,并且所有进一步的事件都将交付给onTouchEvent()方法,并且不再出现在这里。

总结一点:onInterceptTouchEvent 将接受一个Down事件,如果想拦截下来就返回true,这样不会再分发到子view中,否则交给子view处理。所以如果返回true的时候,需要ViewGroup自己的onTouchEvent处理,这个时候原来的处理事件的view将收到一个MotionEvent.ACTION_CANCEL的action。

  1. onTouchEvent
public boolean onTouchEvent (MotionEvent event)

实现此方法来处理触摸屏运动事件。如果处理事件为True,则为false。

示例

onTouchEvent

文档中很多提到返回true,表示要处理事件。该如何理解呢。

public class CustomView extends View {
	private static final String TAG = "CustomView";
 	@Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Log.e(TAG, "dispatchTouchEvent"+"  action: "+event.getAction());
        return super.dispatchTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.e(TAG, "onTouchEvent");
        return super.onTouchEvent(event);
    }
}

自定义一个view,重写两个方法并打印。

07-08 14:50:54.459 17907-17907/com.example.study E/ViewTouchActivity: dispatchTouchEvent
07-08 14:50:54.459 17907-17907/com.example.study E/CustomFrameLayout: dispatchTouchEvent  action:0
07-08 14:50:54.459 17907-17907/com.example.study E/CustomFrameLayout: onInterceptTouchEvent  action:0
07-08 14:50:54.459 17907-17907/com.example.study E/CustomView: dispatchTouchEvent  action: 0
07-08 14:50:54.459 17907-17907/com.example.study E/CustomView: onTouchEvent
07-08 14:50:54.459 17907-17907/com.example.study E/CustomFrameLayout: onTouchEvent  action:0
07-08 14:50:54.459 17907-17907/com.example.study E/ViewTouchActivity: onTouchEvent
07-08 14:50:54.549 17907-17907/com.example.study E/ViewTouchActivity: dispatchTouchEvent
07-08 14:50:54.549 17907-17907/com.example.study E/ViewTouchActivity: onTouchEvent
07-08 14:50:54.549 17907-17907/com.example.study E/ViewTouchActivity: dispatchTouchEvent
07-08 14:50:54.549 17907-17907/com.example.study E/ViewTouchActivity: onTouchEvent

运行后点击一下,查看log,只打印了down的部分,之后的move和up都交给了Activity。

 @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.e(TAG, "onTouchEvent");

        if (event.getAction()==MotionEvent.ACTION_UP){
            return true;
        }
        return super.onTouchEvent(event);
    }

上面代码中up的时候返回了true

07-08 14:50:54.459 17907-17907/com.example.study E/ViewTouchActivity: dispatchTouchEvent
07-08 14:50:54.459 17907-17907/com.example.study E/CustomFrameLayout: dispatchTouchEvent  action:0
07-08 14:50:54.459 17907-17907/com.example.study E/CustomFrameLayout: onInterceptTouchEvent  action:0
07-08 14:50:54.459 17907-17907/com.example.study E/CustomView: dispatchTouchEvent  action: 0
07-08 14:50:54.459 17907-17907/com.example.study E/CustomView: onTouchEvent
07-08 14:50:54.459 17907-17907/com.example.study E/CustomFrameLayout: onTouchEvent  action:0
07-08 14:50:54.459 17907-17907/com.example.study E/ViewTouchActivity: onTouchEvent
07-08 14:50:54.549 17907-17907/com.example.study E/ViewTouchActivity: dispatchTouchEvent
07-08 14:50:54.549 17907-17907/com.example.study E/ViewTouchActivity: onTouchEvent
07-08 14:50:54.549 17907-17907/com.example.study E/ViewTouchActivity: dispatchTouchEvent
07-08 14:50:54.549 17907-17907/com.example.study E/ViewTouchActivity: onTouchEvent

发现和没加之前的一样。不是说好的返回true表示处理吗,为啥up没有传递进来。
这是因为之前down的时候我们返回了false,这样事件就丢出去不再重新传递回来了。
下面看下,down和move返回true,up返回false。

  @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.e(TAG, "onTouchEvent");
        if (event.getAction()==MotionEvent.ACTION_DOWN){
            return true;
        }
        if (event.getAction()==MotionEvent.ACTION_MOVE){
            return true;
        }
        if (event.getAction()==MotionEvent.ACTION_UP){
            return false;
        }
        return super.onTouchEvent(event);
    }

运行后打印

07-08 14:56:58.399 18182-18182/com.example.study E/ViewTouchActivity: dispatchTouchEvent
07-08 14:56:58.399 18182-18182/com.example.study E/CustomFrameLayout: dispatchTouchEvent  action:0
07-08 14:56:58.399 18182-18182/com.example.study E/CustomFrameLayout: onInterceptTouchEvent  action:0
07-08 14:56:58.399 18182-18182/com.example.study E/CustomView: dispatchTouchEvent  action: 0
07-08 14:56:58.409 18182-18182/com.example.study E/CustomView: onTouchEvent
07-08 14:56:58.469 18182-18182/com.example.study E/ViewTouchActivity: dispatchTouchEvent
07-08 14:56:58.469 18182-18182/com.example.study E/CustomFrameLayout: dispatchTouchEvent  action:2
07-08 14:56:58.469 18182-18182/com.example.study E/CustomFrameLayout: onInterceptTouchEvent  action:2
07-08 14:56:58.469 18182-18182/com.example.study E/CustomView: dispatchTouchEvent  action: 2
07-08 14:56:58.469 18182-18182/com.example.study E/CustomView: onTouchEvent
07-08 14:56:58.489 18182-18182/com.example.study E/ViewTouchActivity: dispatchTouchEvent
07-08 14:56:58.489 18182-18182/com.example.study E/CustomFrameLayout: dispatchTouchEvent  action:2
07-08 14:56:58.489 18182-18182/com.example.study E/CustomFrameLayout: onInterceptTouchEvent  action:2
07-08 14:56:58.489 18182-18182/com.example.study E/CustomView: dispatchTouchEvent  action: 2
07-08 14:56:58.489 18182-18182/com.example.study E/CustomView: onTouchEvent
07-08 14:56:58.499 18182-18182/com.example.study E/ViewTouchActivity: dispatchTouchEvent
07-08 14:56:58.499 18182-18182/com.example.study E/CustomFrameLayout: dispatchTouchEvent  action:1
07-08 14:56:58.499 18182-18182/com.example.study E/CustomFrameLayout: onInterceptTouchEvent  action:1
07-08 14:56:58.499 18182-18182/com.example.study E/CustomView: dispatchTouchEvent  action: 1
07-08 14:56:58.499 18182-18182/com.example.study E/CustomView: onTouchEvent
07-08 14:56:58.499 18182-18182/com.example.study E/ViewTouchActivity: onTouchEvent

可以看到从down到up都事件都分配到了CustomView的onTouchEvent中。因为up返回的是false,所以up结束之后,立马有丢给了Activity。
所以这个返回true一定要在能传递进来的前提下返回。向之前down的时候已经返回出去了,那么以后再也不会分发进来了只要有一次是返回的false,之后就不会再分发进来。

onInterceptTouchEvent
public class CustomFrameLayout extends FrameLayout {
     @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.e(TAG,"dispatchTouchEvent"+"  action:"+ev.getAction());
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        Log.e(TAG,"onInterceptTouchEvent"+"  action:"+ev.getAction());
        if (ev.getAction()==MotionEvent.ACTION_MOVE){
            return true;
        }
        return super.onInterceptTouchEvent(ev);
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.e(TAG,"onTouchEvent"+"  action:"+event.getAction());
        return super.onTouchEvent(event);
    }
}

CustomFrameLayout 继承自FrameLayout ,在onInterceptTouchEvent方法move的时候返回true,CustomView代码不变,看下log

07-08 15:07:39.079 18566-18566/com.example.study E/ViewTouchActivity: dispatchTouchEvent
07-08 15:07:39.079 18566-18566/com.example.study E/CustomFrameLayout: dispatchTouchEvent  action:0
07-08 15:07:39.079 18566-18566/com.example.study E/CustomFrameLayout: onInterceptTouchEvent  action:0
07-08 15:07:39.079 18566-18566/com.example.study E/CustomView: dispatchTouchEvent  action: 0
07-08 15:07:39.079 18566-18566/com.example.study E/CustomView: onTouchEvent
07-08 15:07:39.159 18566-18566/com.example.study E/ViewTouchActivity: dispatchTouchEvent
07-08 15:07:39.159 18566-18566/com.example.study E/CustomFrameLayout: dispatchTouchEvent  action:2
07-08 15:07:39.159 18566-18566/com.example.study E/CustomFrameLayout: onInterceptTouchEvent  action:2
07-08 15:07:39.159 18566-18566/com.example.study E/CustomView: dispatchTouchEvent  action: 3
07-08 15:07:39.159 18566-18566/com.example.study E/CustomView: onTouchEvent
07-08 15:07:39.159 18566-18566/com.example.study E/ViewTouchActivity: onTouchEvent
07-08 15:07:39.179 18566-18566/com.example.study E/ViewTouchActivity: dispatchTouchEvent
07-08 15:07:39.179 18566-18566/com.example.study E/CustomFrameLayout: dispatchTouchEvent  action:2
07-08 15:07:39.179 18566-18566/com.example.study E/CustomFrameLayout: onTouchEvent  action:2
07-08 15:07:39.179 18566-18566/com.example.study E/ViewTouchActivity: onTouchEvent
07-08 15:07:39.199 18566-18566/com.example.study E/ViewTouchActivity: dispatchTouchEvent
07-08 15:07:39.199 18566-18566/com.example.study E/CustomFrameLayout: dispatchTouchEvent  action:2
07-08 15:07:39.199 18566-18566/com.example.study E/CustomFrameLayout: onTouchEvent  action:2

log中发现,本来CustomView应该一直回调到up的,但是现在只到down,move的时候就没有回调了,这是因为父布局CustomFrameLayout的onInterceptTouchEvent方法在move的时候进行了拦截,并且向之前的CustomView返回了一次cancel的回调。之后CustomFrameLayout会直接回调onTouchEvent 方法,不在回调onInterceptTouchEvent 方法。

dispatchTouchEvent

通过上面的log可以看到,无论是Activity还是view,事件都是从dispatchTouchEvent开始的。
如果返回true呢,会如何?

   @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.e(TAG,"dispatchTouchEvent"+"  action:"+ev.getAction());

        return true;
    }

CustomFrameLayout返回true,查看log

07-08 15:29:07.369 20839-20839/com.example.study E/ViewTouchActivity: dispatchTouchEvent
07-08 15:29:07.369 20839-20839/com.example.study E/CustomFrameLayout: dispatchTouchEvent  action:0
07-08 15:29:07.399 20839-20839/com.example.study E/ViewTouchActivity: dispatchTouchEvent
07-08 15:29:07.399 20839-20839/com.example.study E/CustomFrameLayout: dispatchTouchEvent  action:2
07-08 15:29:07.419 20839-20839/com.example.study E/ViewTouchActivity: dispatchTouchEvent
07-08 15:29:07.429 20839-20839/com.example.study E/CustomFrameLayout: dispatchTouchEvent  action:2
07-08 15:29:07.449 20839-20839/com.example.study E/ViewTouchActivity: dispatchTouchEvent
07-08 15:29:07.449 20839-20839/com.example.study E/CustomFrameLayout: dispatchTouchEvent  action:2
07-08 15:29:07.449 20839-20839/com.example.study E/ViewTouchActivity: dispatchTouchEvent
07-08 15:29:07.449 20839-20839/com.example.study E/CustomFrameLayout: dispatchTouchEvent  action:1

发现从down、move、up都回调到了CustomFrameLayout中,但是只调用了dispatchTouchEvent 方法。

看来我们把onInterceptTouchEvent 、onTouchEvent 方法的调用地方给搞没了。
dispatchTouchEvent 那就看看源码是怎么调用的吧。

源码浅析

dispatchTouchEvent

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
    	//验证操作的唯一性
        if (mInputEventConsistencyVerifier != null) {
            mInputEventConsistencyVerifier.onTouchEvent(ev, 1);
        }

        //查看是否获得焦点
        if (ev.isTargetAccessibilityFocus() && isAccessibilityFocusedViewOrHost()) {
            ev.setTargetAccessibilityFocus(false);
        }
        ...
         // Check for interception.检查拦截
            final boolean intercepted;
            if (actionMasked == MotionEvent.ACTION_DOWN
                    || mFirstTouchTarget != null) {
                    //是否允许拦截
                final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
                if (!disallowIntercept) {
                	//允许拦截这里调用onInterceptTouchEvent
                    intercepted = onInterceptTouchEvent(ev);
                    ev.setAction(action); // restore action in case it was changed
                } else {
                	//不允许拦截,状态直接为false
                    intercepted = false;
                }
            } else {
                // There are no touch targets and this action is not an initial down
                // so this view group continues to intercept touches.
                intercepted = true;
            }
        ...
        //多处会判断分发给子view还是分发给自己
         dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)
        ...
            private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
            View child, int desiredPointerIdBits) {
        final boolean handled;

        // Canceling motions is a special case.  We don't need to perform any transformations
        // or filtering.  The important part is the action, not the contents.
        final int oldAction = event.getAction();
        if (cancel || oldAction == MotionEvent.ACTION_CANCEL) {
            event.setAction(MotionEvent.ACTION_CANCEL);
            if (child == null) {
            	//如果没有子view就调用自己的dispatchTouchEvent,对于ViewGroup而已调用的是View的
                handled = super.dispatchTouchEvent(event);
            } else {
                handled = child.dispatchTouchEvent(event);
            }
            event.setAction(oldAction);
            return handled;
        }
        ...

上面的代码中,先对事件做一个检查,然后判断是否需要拦截,最后遍历子view,判断继续分发给子view还是分发给自己。最后返回结果。
ViewGroup中 的dispatchTouchEvent方法还没有调用onTouchEvent方法。

onInterceptTouchEvent
 public boolean onInterceptTouchEvent(MotionEvent ev) {
        if (ev.isFromSource(InputDevice.SOURCE_MOUSE)
                && ev.getAction() == MotionEvent.ACTION_DOWN
                && ev.isButtonPressed(MotionEvent.BUTTON_PRIMARY)
                && isOnScrollbarThumb(ev.getX(), ev.getY())) {
            return true;
        }
        return false;
    }

而onInterceptTouchEvent方法中只是对按下时的进行了一个判断。

View中的dispatchTouchEvent
 public boolean dispatchTouchEvent(MotionEvent event) {
 ...

         if (onFilterTouchEventForSecurity(event)) {
            if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) {
            	//如果view处于ENABLED ,并且处于滑动状态直接返回true。
                result = true;
            }
            //noinspection SimplifiableIfStatement
            ListenerInfo li = mListenerInfo;
            if (li != null && li.mOnTouchListener != null
                    && (mViewFlags & ENABLED_MASK) == ENABLED
                    && li.mOnTouchListener.onTouch(this, event)) {
                     //这里如果OnTouchListener不为空的时候调用onTouch方法。
                result = true;
            }
            //为false如果返回结果,但是onTouchEvent返回的是true
            if (!result && onTouchEvent(event)) {
            	//返回结果true
                result = true;
            }
        }
           ...
        }
 ...

如果我们设置了setOnTouchListener的话,会调用onTouch方法。接下来再调用onTouchEvent。
其中onTouch方法需要我们自己去实现。

onTouchEvent
public boolean onTouchEvent(MotionEvent event) {
...
	 switch (action) {
                case MotionEvent.ACTION_UP:
					...
					if (!post(mPerformClick)) {
						//执行点击操作
                         performClickInternal();
                    }
                    ...
                 
                case MotionEvent.ACTION_DOWN:
                // Walk up the hierarchy to determine if we're inside a scrolling container.
                //遍历层次结构以确定是否在滚动容器中。
                    boolean isInScrollingContainer = isInScrollingContainer();

                    // For views inside a scrolling container, delay the pressed feedback for
                    // a short period in case this is a scroll.
                    //对于滚动容器中的视图,将按下的反馈延迟一段时间,以防这是滚动。
                    if (isInScrollingContainer) {
                        mPrivateFlags |= PFLAG_PREPRESSED;
                        if (mPendingCheckForTap == null) {
                            mPendingCheckForTap = new CheckForTap();
                        }
                        mPendingCheckForTap.x = event.getX();
                        mPendingCheckForTap.y = event.getY();
                        //发送一个执行长按的消息,延迟了100毫秒
                        postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());
                    } else {
                        // Not inside a scrolling container, so show the feedback right away
                        setPressed(true, x, y);
                        //不在滚动容器内直接长按,不需要延迟
                        checkForLongClick(0, x, y);
                    }        
                    ...
	...
	}
...
}
-----------------点击事件   ---------------------------------
 private boolean performClickInternal() {
        // Must notify autofill manager before performing the click actions to avoid scenarios where
        // the app has a click listener that changes the state of views the autofill service might
        // be interested on.
        notifyAutofillManagerOnClick();

        return performClick();
    }
 public boolean performClick() {
       	...
       	final boolean result;
        final ListenerInfo li = mListenerInfo;
        if (li != null && li.mOnClickListener != null) {
            playSoundEffect(SoundEffectConstants.CLICK);
            //调用点击事件
            li.mOnClickListener.onClick(this);
            result = true;
        } else {
            result = false;
        }
        ..
    }

--------------------长按--------------------------
  private void checkForLongClick(int delayOffset, float x, float y) {
        if ((mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE || (mViewFlags & TOOLTIP) == TOOLTIP) {
            mHasPerformedLongPress = false;

            if (mPendingCheckForLongPress == null) {
                mPendingCheckForLongPress = new CheckForLongPress();
            }
            mPendingCheckForLongPress.setAnchor(x, y);
            mPendingCheckForLongPress.rememberWindowAttachCount();
            mPendingCheckForLongPress.rememberPressedState();
            //如果按下的时间在默认的500毫秒,然后执行长按
            postDelayed(mPendingCheckForLongPress,
                    ViewConfiguration.getLongPressTimeout() - delayOffset);
        }
    }

所以:在View的dispatchTouchEvent中如果设置了OnTouchListener的话会调用onTouch方法,会调用onTouchEvent方法。onTouchEvent方法中在up的时候执行了判断是否执行onClickListener,在down的时候会判断是否执行onLongClickListener。

总结

无论是View还是ViewGroup,事件都是由dispatchTouchEvent方法开始,ViewGroup中会进行onInterceptTouchEvent方法的判断,之后会遍历调用子View或者自己父类的dispatchTouchEvent,最终都是View的dispatchTouchEvent方法。在View的dispatchTouchEvent方法中,进行了OnTouchListener的判断,是否调用onTouch,之后调用onTouchEvent方法。在onTouchEvent方法中,信息了onClickListener和onLongClickListener调用的判断。

上面的代码中出现了Activity也会调用dispatchTouchEvent方法。

public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
        	//开始交互
            onUserInteraction();
        }
        //调用Window的DispatchTouchEvent
        if (getWindow().superDispatchTouchEvent(ev)) {
            return true;
        }
        //返回的是onTouchEvent,是否处理事件
        return onTouchEvent(ev);
    }

那么这个window是什么呢?

 public Window getWindow() {
        return mWindow;
    }
...
 final void attach(Context context, ActivityThread aThread,
            Instrumentation instr, IBinder token, int ident,
            Application application, Intent intent, ActivityInfo info,
            CharSequence title, Activity parent, String id,
            NonConfigurationInstances lastNonConfigurationInstances,
            Configuration config, String referrer, IVoiceInteractor voiceInteractor,
            Window window, ActivityConfigCallback activityConfigCallback) {
        attachBaseContext(context);

        mFragments.attachHost(null /*parent*/);
		//Activity的attach方法中实例化了window对象
        mWindow = new PhoneWindow(this, window, activityConfigCallback);
        mWindow.setWindowControllerCallback(this);
        mWindow.setCallback(this);
        mWindow.setOnWindowDismissedCallback(this);
        mWindow.getLayoutInflater().setPrivateFactory(this);
        if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
            mWindow.setSoftInputMode(info.softInputMode);
        }
...

可以看到这里的window对象是PhoneWindow。

	//PhoneWindow
 	@Override
    public boolean superDispatchTouchEvent(MotionEvent event) {
        return mDecor.superDispatchTouchEvent(event);
    }
    ....
    private DecorView mDecor;
--------------------------------------------------------
...
	//DecorView 
  public boolean superDispatchTouchEvent(MotionEvent event) {
        return super.dispatchTouchEvent(event);
    }
...

最终调用到了DecorView 的superDispatchTouchEvent,而DecorView 继承制FrameLayout。这样就回到了之前的三大方法上了。那么DecorView什么时候实例化的呢
Activity的setContentView

//Activity
 public void setContentView(@LayoutRes int layoutResID) {
        getWindow().setContentView(layoutResID);
        initWindowDecorActionBar();
    }
----------------
//PhoneWindow
 @Override
    public void setContentView(int layoutResID) {
        // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
        // decor, when theme attributes and the like are crystalized. Do not check the feature
        // before this happens.
        if (mContentParent == null) {
        //实例化DecorView,实例化mContentParent
            installDecor();
        } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            mContentParent.removeAllViews();
        }
		//是否需要改变窗口内容
        if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
        //布局加入到通过DecorView得到的mContentParent(ViewGroup)中
            final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
                    getContext());
            transitionTo(newScene);
        } else {
        	//布局加入到通过DecorView得到的mContentParent(ViewGroup)中
            mLayoutInflater.inflate(layoutResID, mContentParent);
        }
        mContentParent.requestApplyInsets();
        final Callback cb = getCallback();
        if (cb != null && !isDestroyed()) {
            cb.onContentChanged();
        }
        mContentParentExplicitlySet = true;
    }

总结:这里Activity在attch的时候实例化出PhoneWindow对象,然后在PhoneWindow中通过setContentView方法实例化DecorView,并将布局加入其中。接下来的事件分发有都交给了View了。三大方法dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值