View的Touch事件分發(fā)

  1. 說明
    上節(jié)課我們總結(jié)了下我們的自定義View的套路和自定義ViewGroup的套路宇攻,那么這節(jié)課我們就用示例代碼的方式來演示下View的Touch事件分發(fā)丈挟,并且從源碼的角度來分析它為什么會是這樣,那么我們接下來先通過示例代碼分析現(xiàn)象各谚,然后我們再通過源碼來分析為什么會是這樣的

  2. 示例代碼分析現(xiàn)象

現(xiàn)象1:onTouchListener onTouchEvent onClick都有 前提是onTouchListener返回false onTouchEvent返回super.onTouchEvent(event)

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

         //onTouchListener返回false
        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);
    }


}

執(zhí)行順序如下:

onTouchListener.Down -> onTouch.Down -> onTouchListener.Move -> onTouch.Move ->onTouchListener.UP -> onTouch.UP -> onClick

現(xiàn)象2:onTouchListener onTouchEvent onClick都有 前提是onTouchListener返回true onTouchEvent返回super.onTouchEvent(event)

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

         //onTouchListener返回true
        touchView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                Log.e("TAG" , "onTouch -> "+event.getAction()) ;
                return true;  
            }
        });
        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);
    }


}

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

現(xiàn)象三:只有onClickListener onTouchEvent 省核,前提是onTouchEvent返回true

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 true;
//            }
//        });
        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 true;
    }


}

執(zhí)行順序如下:
onTouchEvent.DOWN -> onTouchEvent.MOVE -> onTouchEvent.UP 墩虹,不執(zhí)行onClick

onClick不執(zhí)行的原因:
因為onClick事件是在 View中的 onTouchEvent中的 case MotionEvent.ACTION_UP:里邊調(diào)用了performClick()豌熄,而這里onTouchEvent返回的是true授嘀,而不是super.onTouchEvent(event),所以就不會執(zhí)行View中的方法锣险,所以就不會執(zhí)行 View中的 onTouchEvent中的 case MotionEvent.ACTION_UP蹄皱,所以onClick不會調(diào)用

現(xiàn)象四: onTouchListener onTouchEvent onClick dispatchTouchEvent 都有,前提是dispatchTouchEvent返回true囱持,那么一個方法都不會執(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;
    }
}


  1. View與Touch相關(guān)的有2個非常重要的方法

2.1:dispatchTouchEvent()方法:用于事件分發(fā)
源碼分析:
boolean result = false;
ListenerInfo li = mListenerInfo;
ListenerInfo :存放了關(guān)于View的所有的Listener信息际邻,比如 onClickListener、onTouchListener等等的有關(guān)于Listener信息

下邊這2個if語句是順序關(guān)系芍阎,先執(zhí)行第一個if語句世曾,再執(zhí)行第二個if語句
if (li != null && li.mOnTouchListener != null //這2個都返回true true
&& (mViewFlags & ENABLED_MASK) == ENABLED //是否是可用的
&& li.mOnTouchListener.onTouch(this, event)) { //這個如果返回false ,則result = false 谴咸; 如果這個返回true轮听,則result=true
result = true;
}

而我們的現(xiàn)象一就是OnTouchListener.onTouch返回false骗露,這個時候上邊的if語句就是false,那么result=true就不會執(zhí)行

if (!result && onTouchEvent(event)) { //表示如果result=false血巍,萧锉!result=true,就會執(zhí)行onTouchEvent(event)述寡;如果result=true柿隙,就不會執(zhí)行onTouchEvent(event),
result = true;
}
而我們的現(xiàn)象二就是OnTouchListener.onTouch返回true鲫凶,那么禀崖!result=false,就不會執(zhí)行onTouchEvent(event)事件

//返回result
return result掀序;

onClick事件在哪里帆焕?
在View中的onTouchEvent()方法中的 -> case MotionEvent.ACTION_UP:里邊調(diào)用了performClick()方法 -> 在這個方法中調(diào)用的li.mOnClickListener.onClick(this);

分析:因為onTouchEvent返回true,即return true 不恭,而沒有return super.onTouchEvent(event)叶雹,所以就不會執(zhí)行View,更不會執(zhí)行View中的onTouchEvent中的case MotionEvent.ACTION_UP

2.2:onTouchEvent()方法换吧,一般都會被我們復(fù)寫折晦,就是我們自定義TouchView中的onTouchEvent()方法

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

代碼已上傳至github:
https://github.com/shuai999/View_day10.git
如果覺得對你有用,歡迎star

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末沾瓦,一起剝皮案震驚了整個濱河市满着,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌贯莺,老刑警劉巖风喇,帶你破解...
    沈念sama閱讀 211,639評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異缕探,居然都是意外死亡魂莫,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評論 3 385
  • 文/潘曉璐 我一進(jìn)店門爹耗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來耙考,“玉大人,你說我怎么就攤上這事潭兽【胧迹” “怎么了?”我有些...
    開封第一講書人閱讀 157,221評論 0 348
  • 文/不壞的土叔 我叫張陵山卦,是天一觀的道長鞋邑。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么枚碗? 我笑而不...
    開封第一講書人閱讀 56,474評論 1 283
  • 正文 為了忘掉前任藻懒,我火速辦了婚禮,結(jié)果婚禮上视译,老公的妹妹穿的比我還像新娘嬉荆。我一直安慰自己,他們只是感情好酷含,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,570評論 6 386
  • 文/花漫 我一把揭開白布鄙早。 她就那樣靜靜地躺著,像睡著了一般椅亚。 火紅的嫁衣襯著肌膚如雪限番。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,816評論 1 290
  • 那天呀舔,我揣著相機(jī)與錄音弥虐,去河邊找鬼。 笑死媚赖,一個胖子當(dāng)著我的面吹牛霜瘪,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播惧磺,決...
    沈念sama閱讀 38,957評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼颖对,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了磨隘?” 一聲冷哼從身側(cè)響起缤底,我...
    開封第一講書人閱讀 37,718評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎番捂,沒想到半個月后个唧,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,176評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡设预,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,511評論 2 327
  • 正文 我和宋清朗相戀三年徙歼,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片絮缅。...
    茶點(diǎn)故事閱讀 38,646評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡鲁沥,死狀恐怖呼股,靈堂內(nèi)的尸體忽然破棺而出耕魄,到底是詐尸還是另有隱情,我是刑警寧澤彭谁,帶...
    沈念sama閱讀 34,322評論 4 330
  • 正文 年R本政府宣布吸奴,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏则奥。R本人自食惡果不足惜考润,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,934評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望读处。 院中可真熱鬧糊治,春花似錦、人聲如沸罚舱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽管闷。三九已至粥脚,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間包个,已是汗流浹背刷允。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留碧囊,地道東北人树灶。 一個月前我還...
    沈念sama閱讀 46,358評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像糯而,于是被迫代替她去往敵國和親破托。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,514評論 2 348

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