在android事件传递一般包括三个对象: Activity,ViewGroup,View,事件分发顺序为:Activity->ViewGroup->View,事件分发过程由
onTouchEvent()
onInterceptTouchEvent()
dispatchTouchEvent()
这三个方法协助完成, 其中View没有onInterceptTouchEvent()方法
下面用一个简单的例子进行说明:
testButton, testLayout为自定义控件
class MainActivity : AppCompatActivity(), View.OnTouchListener {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//view没有onInterceptTouchEvent
//onTouch事件优于onClick
btnTest.setOnTouchListener(this)
btnTest.setOnClickListener {
Toast.makeText(this@MainActivity,"te", Toast.LENGTH_LONG).show()
}
}
override fun onTouch(v: View?, event: MotionEvent?): Boolean {
when (v){
mainLayout->{
when (event?.action){
MotionEvent.ACTION_DOWN->{
Log.d("touch event","mainLayout ACTION_DOWN")
}
MotionEvent.ACTION_UP->{
Log.d("touch event","mainLayout ACTION_UP")
}
}
}
btnTest->{
when (event?.action){
MotionEvent.ACTION_DOWN->{
Log.d("touch event","btnTest ACTION_DOWN")
}
MotionEvent.ACTION_UP->{
Log.d("touch event","btnTest ACTION_UP")
}
}
}
}
return true
}
//activity的dispatchTouchEvent
override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
//事件分派
when (ev?.action){
MotionEvent.ACTION_DOWN->{
Log.d("touch event","activity dispatchTouchEvent ACTION_DOWN")
//在ACTION_DOWN return true,子view收不到后面的事件
//return true
}
MotionEvent.ACTION_UP->{
Log.d("touch event","activity dispatchTouchEvent ACTION_UP")
//ACTION_UP return true,子view收不到ACTION_UP
//return true
}
}
return super.dispatchTouchEvent(ev)
}
override fun onTouchEvent(event: MotionEvent?): Boolean {
return super.onTouchEvent(event)
}
}
class TestButton:Button {
constructor(mContext: Context) : super(mContext) {
val context = mContext
}
constructor(mContext: Context, mAttributeSet: AttributeSet) : super(mContext, mAttributeSet) {
val context = mContext
}
override fun onTouchEvent(event: MotionEvent?): Boolean {
//return super.onTouchEvent(event)
when (event?.action){
MotionEvent.ACTION_DOWN->{
Log.d("touch event","btnTest ACTION_DOWN")
return true
}
MotionEvent.ACTION_UP->{
Log.d("touch event","btnTest ACTION_UP")
}
}
//如果返回true,不会把onTouch事件传递回activity,就是说activity的onTouchEvent不会被调用
return true
}
override fun dispatchTouchEvent(event: MotionEvent?): Boolean {
return super.dispatchTouchEvent(event)
}
}
class TestLayout : ConstraintLayout{
constructor(mContext: Context) : super(mContext) {
val context = mContext
}
constructor(mContext: Context, mAttributeSet: AttributeSet) : super(mContext, mAttributeSet) {
val context = mContext
}
override fun onTouchEvent(event: MotionEvent?): Boolean {
//return super.onTouchEvent(event)
Log.d("touch event","view group")
return true
}
override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {
//return super.onInterceptTouchEvent(ev)
//true:中断事件
//中断后, TestLayout的子view btnTest的onTouch,onClick都不会执行
return true
}
override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
//事件分派
when (ev?.action){
MotionEvent.ACTION_DOWN->{
Log.d("touch event","view group dispatchTouchEvent ACTION_DOWN")
//在ACTION_DOWN return true,子view收不到后面的事件
//return true
}
MotionEvent.ACTION_UP->{
Log.d("touch event","view group dispatchTouchEvent ACTION_UP")
//ACTION_UP return true,子view收不到ACTION_UP
//return true
}
}
return super.dispatchTouchEvent(ev)
}
}
我们通过log查看到,每次touch btnTest或mainLayout,都会先打印Activity里的dispatchTouchEvent里的ACTION_DOWN,是传递的起点
a. 如果Activity的dispatchTouchEvent里的ACTION_DOWN return true,子view就收不到事件传递了;
b. TestLayout的onInterceptTouchEvent,如果return true,表示中断传递给子view的事件,TestButton的onTouch,onClick都不会执行,会走TestLayout的onTouchEvent;就是说如果ViewGroup的onInterceptTouchEvent return true,就会走自已的onTouchEvent();
c. 如果TestLayout的onTouchEvent return true,就是消费掉事件,不会把onTouch事件传递回activity,就是说activity的onTouchEvent不会被调用
d. 同理TestButton的onTouchEvent return true,也不会把onTouch事件传递回activity,就是说activity的onTouchEvent不会被调用
如果view,viewgroup都没有对事件进行消费,会以activity的onTouchEvent作为终点;
如果viewgroup中断事件并对事件进行消费,会以viewgroup onTouchEvent作为终点;
如果viewgroup没有中断事件,但view(如button)对事件进行消费,会以button ACTION_UP作为终点;
如果viewgroup没有中断事件,view也没有对事件进行消费,会以activity的onTouchEvent作为终点;