View的Touch事件分發(fā)

1. 說(shuō)明


這篇文章分析下View的Touch事件分發(fā)的順序蒸甜,這里記錄一下:

2. 分析

public class MainActivity extends AppCompatActivity {

    private TouchView touch_view;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        touch_view = (TouchView) findViewById(R.id.touch_view);

        touch_view.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                Log.e("TAG" , "觸摸onTouch() -> " + event.getAction()) ;
                return true;
            }
        });


        touch_view.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.e("TAG" , "點(diǎn)擊onClick -> ") ;
            }
        });
    }
}
public class TouchView extends View {

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

    public TouchView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public TouchView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }


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

現(xiàn)象一:onTouchListener、onTouch睛竣、onClick三個(gè)都有的情況下晰房,并且onTouchListener返回false,表示自己不處理事件酵颁,直接把事件分發(fā)下去給子控件嫉你,所以3個(gè)方法都會(huì)執(zhí)行;

03-25 08:18:36.589 3344-3344/com.jackchen.view_day010_2 E/TAG: 觸摸onTouch() -> 0
03-25 08:18:36.589 3344-3344/com.jackchen.view_day010_2 E/TAG: onTouchEvent -> 0
03-25 08:18:36.672 3344-3344/com.jackchen.view_day010_2 E/TAG: 觸摸onTouch() -> 2
03-25 08:18:36.672 3344-3344/com.jackchen.view_day010_2 E/TAG: onTouchEvent -> 2
03-25 08:18:36.851 3344-3344/com.jackchen.view_day010_2 E/TAG: 觸摸onTouch() -> 1
03-25 08:18:36.851 3344-3344/com.jackchen.view_day010_2 E/TAG: onTouchEvent -> 1
03-25 08:18:36.852 3344-3344/com.jackchen.view_day010_2 E/TAG: 點(diǎn)擊onClick -> 

由以上可知:0代表DOWN躏惋、2代表MOVE幽污、1代表UP,執(zhí)行順序如下:
onTouchListener的DOMN -> onTouch的DOWN ->
onTouchListener的MOVE -> onTouch的MOVE ->
onTouchListener的UP -> onTouch的UP ->
onClick

現(xiàn)象二:onTouchListener簿姨、onTouch距误、onClick三個(gè)都有的情況下,并且onTouchListener返回true扁位,表示自己處理事件准潭,就不會(huì)把事件分發(fā)給子控件,所以就只會(huì)執(zhí)行自己而方法域仇;

03-25 08:25:30.493 23991-23991/? E/TAG: 觸摸onTouch() -> 0
03-25 08:25:30.625 23991-23991/? E/TAG: 觸摸onTouch() -> 2
03-25 08:25:30.625 23991-23991/? E/TAG: 觸摸onTouch() -> 1

執(zhí)行順序如下:
onTouchListener的DOWN -> onTouchListener的MOVE -> onTouchListener的UP

現(xiàn)象三:只有 onTouchEvent()刑然、onClickListener(),前提是onTouchEvent返回true暇务,表示自己處理事件泼掠,就不會(huì)把事件分發(fā)下去,所以就只執(zhí)行自己的方法垦细,不會(huì)執(zhí)行下邊的方法择镇;

03-25 09:19:11.648 3005-3005/? E/TAG: onTouchEvent -> 0
03-25 09:19:11.752 3005-3005/? E/TAG: onTouchEvent -> 2
03-25 09:19:11.752 3005-3005/? E/TAG: onTouchEvent -> 1

執(zhí)行順序如下:
onTouchEvent的DOWN -> onTouchEvent的MOVE -> onTouchEvent的UP,不會(huì)執(zhí)行onClick事件

onClick不執(zhí)行的原因:
因?yàn)閛nClick事件是在 View中的 onTouchEvent中的 case MotionEvent.ACTION_UP:里邊調(diào)用了performClick()括改,而這里onTouchEvent返回的是true腻豌,而不是super.onTouchEvent(event),所以就不會(huì)執(zhí)行View中的方法,所以就不會(huì)執(zhí)行 View中的 onTouchEvent中的 case MotionEvent.ACTION_UP吝梅,所以onClick不會(huì)調(diào)用

現(xiàn)象四: onTouchListener onTouchEvent onClick dispatchTouchEvent 都有虱疏,前提是dispatchTouchEvent返回true,那么一個(gè)方法都不會(huì)執(zhí)行憔涉;如果dispatchTouchEvent返回true订框,并且添加super.dispatchTouchEvent(event) ;那么現(xiàn)象和現(xiàn)象一是一樣的析苫。

public class MainActivity extends AppCompatActivity {

    private TouchView touchView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        touchView = (TouchView) findViewById(R.id.touch_view);
        touchView.setEnabled(false);  //touchView不可用


        touchView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                Log.e("TAG" , "onTouch -> "+event.getAction()) ;
                return false;
            }
        });
        touchView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.e("TAG" , "onClick") ;
            }
        });

    }
}
public class TouchView extends View {
    public TouchView(Context context) {
        this(context, null);
    }

    public TouchView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public TouchView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }


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


    /**
     *  復(fù)寫 dispatchTouchEvent作用就是兜叨,在onTouchEvent()方法中可以返回任何值,return false衩侥、return true国旷、return super.onTouchEvent(event)都是可以的
     *  但是在 dispatchTouchEvent必須返回true,并且添加super.dispatchTouchEvent(event) ,這樣的話現(xiàn)象就是現(xiàn)象一
     * @param event
     * @return
     */
    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        super.dispatchTouchEvent(event) ;
        Log.e("TAG" , "dispatchTouchEvent -> "+event.getAction()) ;
        return true;
    }
}


3. View和Touch相關(guān)的有2個(gè)非常重要的方法

3.1>:dispatchTouchEvent()事件分發(fā):

源碼分析:
在View源碼中的 dispatchTouchEvent()方法中:

    public boolean dispatchTouchEvent(MotionEvent event) {        

        // result:默認(rèn)是false
        boolean result = false茫死;

            // ListenerInfo:里邊存放了 View的所有的 Listener信息
            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;
    }

以上中:
boolean result = false;
ListenerInfo 很重要跪但,它里邊存放了View的所有的Listener信息,比如:onTouchListener峦萎、onClickListener

ListenerInfo li = mListenerInfo;
if (li != null && li.mOnTouchListener != null               
   && (mViewFlags & ENABLED_MASK) == ENABLED
   && li.mOnTouchListener.onTouch(this, event)) {
       result = true;
}
分析以上代碼可知:
li為true屡久,li.mOnTouchListener != null 為true
(mViewFlags & ENABLED_MASK) == ENABLED 是否是ENABLE可用的
li.mOnTouchListener.onTouch(this, event):

如果返回false,說(shuō)明進(jìn)不去if語(yǔ)句爱榔,那么就直接用初始化的result = false的值被环;
如果返回true,那么 result = true 详幽;

if (!result && onTouchEvent(event)) {
      result = true;
}
分析以上代碼可知:

對(duì)于if (!result && onTouchEvent(event)) :
如果上邊的result為false筛欢,那么 !result為true,那么就會(huì)執(zhí)行后邊的 onTouchEvent()方法了唇聘;
如果 result為true版姑,那么 !result為false,那么就不會(huì)執(zhí)行后邊的 onTouchEvent()方法了迟郎;

到目前來(lái)講剥险,我們都還沒(méi)有看到點(diǎn)擊事件?
在View的onTouchEvent中的 case MotionEvent.ACTION_UP里邊調(diào)用了 performClick()方法宪肖,點(diǎn)擊 performClick()進(jìn)入里邊方法后表制,具體代碼是:

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

        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
        return result;
    }

分析:因?yàn)閛nTouchEvent返回true,即return true 匈庭,而沒(méi)有return super.onTouchEvent(event)夫凸,所以就不會(huì)執(zhí)行View,更不會(huì)執(zhí)行View中的onTouchEvent中的case MotionEvent.ACTION_UP阱持,所以就只會(huì)執(zhí)行 onTouchEvent()的Down夭拌、Move、Up事件,不會(huì)執(zhí)行onClick()方法了鸽扁;

3.2>:onTouchEvent()蒜绽,這個(gè)方法一般都被我們復(fù)寫,并且直接return true即可桶现;

注意:

注意:自定義View是沒(méi)有 onInterceptTouchEvent() 攔截方法的

4. 總結(jié)如下:


  • 如果onTouchListener返回false躲雅,表示不處理事件,把事件分發(fā)給子控件骡和,讓下級(jí)處理相赁,執(zhí)行順序就是:
    onTouchListener、onTouchEvent慰于、onClickListener
  • 如果onTouchListener返回true钮科,表示自己處理事件,就不會(huì)把事件分發(fā)給子控件婆赠,所以就只會(huì)執(zhí)行onTouchListener
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末绵脯,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子休里,更是在濱河造成了極大的恐慌蛆挫,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,681評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件妙黍,死亡現(xiàn)場(chǎng)離奇詭異悴侵,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)废境,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,205評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門畜挨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人噩凹,你說(shuō)我怎么就攤上這事巴元。” “怎么了驮宴?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,421評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵逮刨,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我堵泽,道長(zhǎng)修己,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,114評(píng)論 1 300
  • 正文 為了忘掉前任迎罗,我火速辦了婚禮睬愤,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘纹安。我一直安慰自己尤辱,他們只是感情好砂豌,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,116評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著光督,像睡著了一般阳距。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上结借,一...
    開(kāi)封第一講書(shū)人閱讀 52,713評(píng)論 1 312
  • 那天筐摘,我揣著相機(jī)與錄音,去河邊找鬼船老。 笑死咖熟,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的努隙。 我是一名探鬼主播球恤,決...
    沈念sama閱讀 41,170評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼荸镊!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起堪置,我...
    開(kāi)封第一講書(shū)人閱讀 40,116評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤躬存,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后舀锨,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體岭洲,經(jīng)...
    沈念sama閱讀 46,651評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,714評(píng)論 3 342
  • 正文 我和宋清朗相戀三年坎匿,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了盾剩。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,865評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡替蔬,死狀恐怖告私,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情承桥,我是刑警寧澤驻粟,帶...
    沈念sama閱讀 36,527評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站凶异,受9級(jí)特大地震影響蜀撑,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜剩彬,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,211評(píng)論 3 336
  • 文/蒙蒙 一酷麦、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧喉恋,春花似錦沃饶、人聲如沸粪摘。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,699評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)徘意。三九已至,卻和暖如春轩褐,著一層夾襖步出監(jiān)牢的瞬間椎咧,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,814評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工把介, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留勤讽,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,299評(píng)論 3 379
  • 正文 我出身青樓拗踢,卻偏偏與公主長(zhǎng)得像脚牍,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子巢墅,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,870評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容