Android View事件傳遞機制
view事件傳遞機制,在很多面試中會問道,我曾經也被問道,卻沒有回答上來。
今天我在這裡寫了一個demo去理解這個view的事件傳遞機制。
首先這個view包括兩種,viewGroup和普通view。viewGroup就是裡面還可以包含子控制元件的那種,如LinearLayout,ViewPager;view是指不能包含子view的那種,如Button,TextView,ImageView 等。
viewGroup的view傳遞事件按順序是:
dispatchTouchEvent(分發)
onInterceptTouchEvent(攔截)
onTouchEvent(觸控)
view的事件傳遞順序是
dispatchTouchEvent(分發)
onTouchEvent(觸控)
如果onInterceptTouchEvent 返回true,則父控制元件消費觸控事件
如果onInterceptTouchEvent 返回false,則子控制元件消費觸控事件
我們來寫demo看看,這個機制到底是怎麼實現的。我使用viewPage和image做的測試。
我自己測試發現一個有趣的事情,
1、onInterceptTouchEvent 不做任何修改,
return super.onInterceptTouchEvent(ev)
a 子view的onTouchEvent 不做任何修改
return super.onTouchEvent(event);
如果子view不消費onTouchEvent 事件,則一次滑動中,父控制元件不會多次呼叫onInterceptTouchEvent
09-13 16:55:21.427 6089-6089/ylj.com.vieweventapplication E/view_event_viewPager: dispatchTouchEvent 09-13 16:55:21.428 6089-6089/ylj.com.vieweventapplication E/view_event_viewPager: onInterceptTouchEvent 09-13 16:55:21.429 6089-6089/ylj.com.vieweventapplication E/view_event_myImageView: dispatchTouchEvent 09-13 16:55:21.429 6089-6089/ylj.com.vieweventapplication E/view_event_myImageView: onTouchEvent 09-13 16:55:21.429 6089-6089/ylj.com.vieweventapplication E/view_event_viewPager: onTouchEvent 09-13 16:55:21.438 6089-6089/ylj.com.vieweventapplication E/view_event_viewPager: dispatchTouchEvent 09-13 16:55:21.438 6089-6089/ylj.com.vieweventapplication E/view_event_viewPager: onTouchEvent 09-13 16:55:21.452 6089-6089/ylj.com.vieweventapplication E/view_event_viewPager: dispatchTouchEvent 09-13 16:55:21.452 6089-6089/ylj.com.vieweventapplication E/view_event_viewPager: onTouchEvent 09-13 16:55:21.460 6089-6089/ylj.com.vieweventapplication E/view_event_viewPager: dispatchTouchEvent 09-13 16:55:21.460 6089-6089/ylj.com.vieweventapplication E/view_event_viewPager: onTouchEvent 09-13 16:55:21.468 6089-6089/ylj.com.vieweventapplication E/view_event_viewPager: dispatchTouchEvent 09-13 16:55:21.468 6089-6089/ylj.com.vieweventapplication E/view_event_viewPager: onTouchEvent 09-13 16:55:21.476 6089-6089/ylj.com.vieweventapplication E/view_event_viewPager: dispatchTouchEvent 09-13 16:55:21.477 6089-6089/ylj.com.vieweventapplication E/view_event_viewPager: onTouchEvent
b 如果子控制元件onTouchEvent 返回true,view group 則會多次呼叫onInterceptTouchEvent。
09-13 17:12:47.652 7371-7371/ylj.com.vieweventapplication E/view_event_viewPager: dispatchTouchEvent
09-13 17:12:47.652 7371-7371/ylj.com.vieweventapplication E/view_event_viewPager: onInterceptTouchEvent
09-13 17:12:47.652 7371-7371/ylj.com.vieweventapplication E/view_event_myImageView: dispatchTouchEvent
09-13 17:12:47.652 7371-7371/ylj.com.vieweventapplication E/view_event_myImageView: onTouchEvent
09-13 17:12:47.727 7371-7371/ylj.com.vieweventapplication E/view_event_viewPager: dispatchTouchEvent
09-13 17:12:47.727 7371-7371/ylj.com.vieweventapplication E/view_event_viewPager: onInterceptTouchEvent
09-13 17:12:47.727 7371-7371/ylj.com.vieweventapplication E/view_event_myImageView: dispatchTouchEvent
09-13 17:12:47.727 7371-7371/ylj.com.vieweventapplication E/view_event_myImageView: onTouchEvent
09-13 17:12:47.738 7371-7371/ylj.com.vieweventapplication E/view_event_viewPager: dispatchTouchEvent
09-13 17:12:47.738 7371-7371/ylj.com.vieweventapplication E/view_event_viewPager: onInterceptTouchEvent
09-13 17:12:47.738 7371-7371/ylj.com.vieweventapplication E/view_event_myImageView: dispatchTouchEvent
09-13 17:12:47.738 7371-7371/ylj.com.vieweventapplication E/view_event_myImageView: onTouchEvent
09-13 17:12:47.760 7371-7371/ylj.com.vieweventapplication E/view_event_viewPager: dispatchTouchEvent
09-13 17:12:47.760 7371-7371/ylj.com.vieweventapplication E/view_event_viewPager: onTouchEvent
09-13 17:12:47.776 7371-7371/ylj.com.vieweventapplication E/view_event_viewPager: dispatchTouchEvent
09-13 17:12:47.776 7371-7371/ylj.com.vieweventapplication E/view_event_viewPager: onTouchEvent
09-13 17:12:47.777 7371-7371/ylj.com.vieweventapplication E/view_event_viewPager: dispatchTouchEvent
09-13 17:12:47.777 7371-7371/ylj.com.vieweventapplication E/view_event_viewPager: onTouchEvent
2、onInterceptTouchEvent 返回true
輸出如下,不會呼叫子view的方法
09-13 16:52:34.841 4478-4478/ylj.com.vieweventapplication E/view_event_viewPager: dispatchTouchEvent
09-13 16:52:34.841 4478-4478/ylj.com.vieweventapplication E/view_event_viewPager: onInterceptTouchEvent
09-13 16:52:34.842 4478-4478/ylj.com.vieweventapplication E/view_event_viewPager: onTouchEvent
09-13 16:52:34.848 4478-4478/ylj.com.vieweventapplication E/view_event_viewPager: dispatchTouchEvent
09-13 16:52:34.848 4478-4478/ylj.com.vieweventapplication E/view_event_viewPager: onTouchEvent
09-13 16:52:34.864 4478-4478/ylj.com.vieweventapplication E/view_event_viewPager: dispatchTouchEvent
09-13 16:52:34.864 4478-4478/ylj.com.vieweventapplication E/view_event_viewPager: onTouchEvent
09-13 16:52:34.871 4478-4478/ylj.com.vieweventapplication E/view_event_viewPager: dispatchTouchEvent
09-13 16:52:34.871 4478-4478/ylj.com.vieweventapplication E/view_event_viewPager: onTouchEvent
3、onInterceptTouchEvent 返回false,子view的onTouchevent
return super.onTouchEvent(event);
這個時候,viewPager 可以滑動
3、onInterceptTouchEvent 返回false,子view的onTouchevent
return true;
這個時候,viewPager 就不能滑動了
測試原始碼如下,複寫的viewPager
package ylj.com.vieweventapplication;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.MotionEvent;
/**
* Created by dfgx_yinlijuan on 2018/9/13.10:06
*/
public class MyViewPager extends ViewPager {
String tag="viewPager";
public MyViewPager(@NonNull Context context) {
super(context);
}
public MyViewPager(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Tools.log(tag,"dispatchTouchEvent");
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
Tools.log(tag,"onTouchEvent");
return super.onTouchEvent(ev);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
Tools.log(tag,"onInterceptTouchEvent");
return super.onInterceptTouchEvent(ev);
// return false;
}
}
複寫的ImageView
package ylj.com.vieweventapplication;
import android.content.Context;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.ImageView;
/**
* Created by dfgx_yinlijuan on 2018/9/13.14:49
*/
public class MyImageView extends android.support.v7.widget.AppCompatImageView {
String tag="myImageView";
public MyImageView(Context context) {
super(context);
}
public MyImageView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public MyImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
Tools.log(tag,"dispatchTouchEvent");
return super.dispatchTouchEvent(event);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
Tools.log(tag,"onTouchEvent");
return super.onTouchEvent(event);
// return true;
}
}
activity 呼叫
package ylj.com.vieweventapplication;
import android.graphics.Color;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.ViewGroup;
import java.util.ArrayList;
import java.util.List;
/**
* view 事件傳遞機制demo
*/
public class ViewEventActivty extends AppCompatActivity {
final String tag = "button";
ViewPager viewPager;
List<View> views=new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.actvity_view_event);
MyViewPager viewPager = (MyViewPager) findViewById(R.id.viewPager);
// viewPager.setAdapter(new GuidePageAdapter());
for (int i = 0; i < 3; i++) {
MyImageView imageView = new MyImageView(this);
if (i == 0) {
imageView.setBackgroundColor(Color.RED);
} else if (i == 1) {
imageView.setBackgroundColor(Color.GREEN);
} else if (i == 2) {
imageView.setBackgroundColor(Color.BLUE);
}
imageView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
views.add(imageView);
}
GuideAdapter adapter = new GuideAdapter(views);
viewPager.setAdapter(adapter);
}
class GuideAdapter extends PagerAdapter {
List<View> mViews;
GuideAdapter(List<View> views) {
this.mViews = views;
}
@Override
public int getCount() {
return mViews.size();
}
@Override
public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
return view==object;
}
@Override
public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
((ViewPager) container).removeView(mViews.get(position));
}
@Override
public Object instantiateItem(@NonNull ViewGroup container, int position) {
((ViewPager)container).addView(mViews.get(position));
return mViews.get(position);
}
}
}