第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號安全,請及時綁定郵箱和手機立即綁定

View的點擊事件流程

標簽:
Android

一、点击事件流程组成

Activity + Window + DecorView + View事件分发机制 + View的点击事件处理过程

  1. 一个点击事件产生之后,先传递给Activity ——> Window(PhoneWindow具体实现) ——> DecorView
  2. View的点击事件分发机制
  3. View的点击事件处理过程

二、举例:一个button的点击事件

  1. 一个点击事件产生之后,先传递给Activity ——> Window(PhoneWindow具体实现) ——> DecorView,继承自FrameLayout,是一个ViewGroup,ViewGroup默认不拦截事件
  2. ——>顶级View,即在setContentView()我们自己所设置的View,一般最外层布局是LinearLayout、ConstraintLayout和RelativeLayout,也都是ViewGroup (这里已经进入View的分发机制)
  3. ——>此时遍历子View,向下分发,因为布局是我们自己写的,所以有几层布局,几个Button都是确定的,如果遇到嵌套布局,那ViewGroup继续遍历子View分发,开启下一轮分发流程
  4. ——>如果子View是能够接受事件,满足在播放动画 OR 点击事件落到子View区域内(在布局中所占的宽高位置)的条件,事件交由子View处理,走它的dispatchOnTouchEvent(),而Button等是继承自View,是一个单独的子View
  5. ——>如果Button等子View没有重写dispatchTouchEvent()等方法,那最终会使用View的对应方法,View没有拦截事件方法onInterceptTouchEvent(),所以会调用onTouchEvent()。(点击事件分发流程结束)
  6. ——>View的dispatchTouchEvent()如果设置有mOnTouchListener.onTouch(),走到这里onTouch()消耗事件就返回了,这里的OnTouchListener是一个接口,项目中很少见到,注意区别于OnClickListener,不是一个东西。(有View消耗事件,开始View的点击事件处理流程。)
  7. ——>如果用户没有设置OnTouchListener,则走到onTouchEvent(),在onTouchEvent()里才会使用到OnClickListener。
  8. ——>onTouchEvent() ——> performClickInternal() ——>mOnClickListener.onClick(this),此处是会回调button设置监听的代码

三、源码

    //Activity.java
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            onUserInteraction();
        }
        if (getWindow().superDispatchTouchEvent(ev)) {
            return true;
        }
        return onTouchEvent(ev);
    }

    //PhoneWindow.java
    @Override
    public boolean superDispatchTouchEvent(MotionEvent event) {
        return mDecor.superDispatchTouchEvent(event);
    }
    
    //DecorView.java
    //是setContentView()中设置view的父View
    public boolean superDispatchTouchEvent(MotionEvent event) {
        //DecorView继承自FrameLayout,FrameLayout继承自ViewGroup
        return super.dispatchTouchEvent(event);
    }
    
    //ViewGroup.java
    /**
     * 此时到View事件的分发机制,下面是伪代码
     * 父View收到点击事件后,开始分发事件,如果拦截事件,则调用onTouchEvent()方法处理事件,否则交由子View进行下一轮事件的分发。
     * ViewGroup默认不拦截View(书籍)?返回false,现在version的版本有一定条件为true,怎么解释这个case
     * 子View可能是ViewGroup吗?可能,比如xml里的嵌套LinearLayout,它是否拦截消耗事件由具体的代码实现,如果没有重写dispatchTouchEvent(),则用父类ViewGroup的对应方法。
     */
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        boolean consume = false;
        if (onInterceptTouchEvent(ev)) {
            consume = onTouchEvent(ev);
        } else {
            consume = child.dispatchTouchEvent(ev);
        }
        return consume;
    }
    
    //View.java
    /**
     * 这里的View不包含ViewGroup,传递到具体的单独View,如Button
     * mOnTouchListener.onTouch(): 这里的OnTouchListener是一个接口,项目中很少见到,注意区别于OnClickListener,不是一个东西。优先级比onTouchEvent()高。
     * 如果用户没有设置OnTouchListener或者 mOnTouchListener.onTouch()返回false,则走到onTouchEvent(),在onTouchEvent()里才会使用到OnClickListener,见下面方法实现。
     */
    public boolean dispatchTouchEvent(MotionEvent event) {
        //...
        boolean result = false;

        if (onFilterTouchEventForSecurity(event)) {
            if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) {
                result = true;
            }
            //noinspection SimplifiableIfStatement
            ListenerInfo li = mListenerInfo;
            if (li != null && li.mOnTouchListener != null
                    && (mViewFlags & ENABLED_MASK) == ENABLED
                    && **li.mOnTouchListener.onTouch(this, event)**) {
                result = true;
            }

            if (!result && onTouchEvent(event)) {
                result = true;
            }
        }
        //...

        return result;
    }
    
    //View.java
    //最终会走onTouchEvent() ——> performClickInternal() ——>mOnClickListener.onClick(this)
    public boolean onTouchEvent(MotionEvent event) {
        //...
        if (mTouchDelegate != null) {
            if (mTouchDelegate.onTouchEvent(event)) {
                return true;
            }
        }

        if (clickable || (viewFlags & TOOLTIP) == TOOLTIP) {
            switch (action) {
                case MotionEvent.ACTION_UP:
                    //...
                    if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) {
                        // take focus if we don't have it already and we should in
                        // touch mode.
                        boolean focusTaken = false;
                        if (isFocusable() && isFocusableInTouchMode() && !isFocused()) {
                            focusTaken = requestFocus();
                        }
                        if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) {
                            // This is a tap, so remove the longpress check
                            removeLongPressCallback();

                            // Only perform take click actions if we were in the pressed state
                            if (!focusTaken) {
                                // Use a Runnable and post this rather than calling
                                // performClick directly. This lets other visual state
                                // of the view update before click actions start.
                                if (mPerformClick == null) {
                                    mPerformClick = new PerformClick();
                                }
                                if (!post(mPerformClick)) {
                                    **performClickInternal();**
                                }
                            }
                        }
                        //...
                    }
                    //...
                    break;
            }

            return true;
        }

        return false;
    }

    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() {
        // We still need to call this method to handle the cases where performClick() was called
        // externally, instead of through performClickInternal()
        notifyAutofillManagerOnClick();

        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;
        }
        //...

        return result;
    }

點擊查看更多內(nèi)容
TA 點贊

若覺得本文不錯,就分享一下吧!

評論

作者其他優(yōu)質(zhì)文章

正在加載中
  • 推薦
  • 評論
  • 收藏
  • 共同學習,寫下你的評論
感謝您的支持,我會繼續(xù)努力的~
掃碼打賞,你說多少就多少
贊賞金額會直接到老師賬戶
支付方式
打開微信掃一掃,即可進行掃碼打賞哦
今天注冊有機會得

100積分直接送

付費專欄免費學

大額優(yōu)惠券免費領

立即參與 放棄機會
微信客服

購課補貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網(wǎng)微信公眾號

舉報

0/150
提交
取消