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