Android事件分发常见冲突案例
⼀:安卓事件分发的常⽤总结语句:
ViewGroup,先要⾛分发流程,如果没有孩⼦处理事件,⾃⼰就再⾛处理流程(⾃⼰处理事件)
View,只能⾛处理事件流程.
⼆:事件分发流程(简洁):
(1) down--⾸先确定down事件属于谁的?: 属于⽗容器的?属于⼦view的?
1.先看是否拦截后⾃⼰处理(即不分发下去)
2.如果不拦截,分发下去:
排序
遍历分发
领取事件的⼦View 处理该事件
3.没孩⼦领取处理该事件,再看下⾃⼰是否处理事件。
①如果⽗容器拿到了down事件,那么后续事件(move up)怎么处理?有⽗容器说了算,或者拦截,⾃⼰处理事件,或者事件分发给⼦view处
理。
②如果⼦Veiw拿到了down事件 那么后续的事件(move up)有谁处理,由⼦View 说了算 ,或者⼦view请求⽗容器要拦截事件,让⽗容器
处理事件(Parent().requestDisallowInterceptTouchEvent(fal)(请求系统不要禁⽤⽗容器的拦截事件);或者⼦View⾃⼰处理事件.
(2) move--处理事件
1.先看是否拦截后⾃⼰处理(即不分发下去) (⼦view可以请求不拦截)
2.分发下去:
直接由down事件确定的view处理
三:控件滑动冲突的解决⽅案:
1.外部拦截法
外部滑动⽅向与内部滑动⽅向不⼀致
解决⽅案:外部拦截法,当事件传递到⽗View时,⽗View需要处理此事件,就拦截,不处理此事件就不拦截
2.内部拦截法
外部滑动⽅向与内部滑动⽅向⼀致;
爱让生活更美好作文
解决⽅案:内部拦截法,当事件传递到⽗View时,⽗View都传递给⼦View,如果⼦View需要处理此事件就消耗掉,否则就交给⽗View处理。但是这种⽅法和Android事件分发不⼀致,需要配合 requestDisallowInterceptTouchEvent ⽅法才能正常⼯作
事件冲突案例1: ⽗容器 BadViewPager 与⼦view MylistView的冲突
public class MainActivity extends AppCompatActivity {
private int[] iv = new int[]{R.mipmap.iv_0, R.mipmap.iv_1, R.mipmap.iv_2,
R.mipmap.iv_3, R.mipmap.iv_4, R.mipmap.iv_5,
R.mipmap.iv_6, R.mipmap.iv_7, R.mipmap.iv_8};
@Override
protected void onCreate(Bundle savedInstanceState) {
tContentView(R.layout.activity_viewpager);
BadViewPager pager = findViewById(R.id.viewpager);
List<Map<String, Integer>> strings = new ArrayList<>();
Map<String, Integer> map;
for (int i = 0; i < 20; i++) {
map = new HashMap<>();
map.put("key", iv[i % 9]);
strings.add(map);
}
MyPagerAdapter adapter = new MyPagerAdapter(this, strings);
pager.tAdapter(adapter);
}
}
public class MyPagerAdapter extends PagerAdapter {
private Context mContext;
private List<Map<String, Integer>> mData;
public MyPagerAdapter(Context context, List<Map<String, Integer>> list) {
mContext = context;
mData = list;
}
@Override
public int getCount() {
return 5;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
View view = View.inflate(mContext, R.layout.item_list, null);
ListView list = view.findViewById(R.id.list);
list.tAdapter(new Context(), mData, R.layout.item_ba, new String[]{"key"}, new int[]{R.id.iv})); container.addView(view);
return view;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
}
使⽤内部拦截法:让⼦view(MyListView)处理事件冲突
当你上下滑动⼦view myListView的同时可以左右滑动ViewPager ⼦Veiw不可以抢⽗容器的事件
/**
内部拦截法:⼦view(MyListView)处理事件冲突
* */
public class MyListView extends ListView {
public MyListView(Context context) {
super(context);
}
public MyListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
private int mLastX, mLastY;
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
int x = (int) X();
int y = (int) Y();
switch (Action()) {
ca MotionEvent.ACTION_DOWN: {
//todo 当down时,⽗容器(BadViewPager)会把事件往下分发给⼦view(⽗容器拿不到该事件了) 让⼦view(MyListVIew)来处理事件(⼦view 拿到down事件 )
getParent().requestDisallowInterceptTouchEvent(true);
break;
}
ca MotionEvent.ACTION_MOVE: {
int deltaX = x - mLastX;
int deltaY = y - mLastY;
// todo 如果Math.abs(deltaX) > Math.abs(deltaY) 判断出是左右滑动,
// todo 那么⼦view 把该事件让给⽗容器(BadViewPager)去处理让⽗容器会拦截事件,⽗容器处理该事件那么你就可以左右滑动⽗容器(BadViewPager) if (Math.abs(deltaX) > Math.abs(deltaY)) {
getParent().requestDisallowInterceptTouchEvent(fal);
}
break;
}
绿野仙踪故事ca MotionEvent.ACTION_UP: {
break;
}
default:
break;
}
mLastX = x;
mLastY = y;
return super.dispatchTouchEvent(event);
}
}
外部拦截法:⽗容器BadViewPager处理冲突事件
当你左右滑动⽗容器 BadViewPager的同时不可以上下滑动myListView ⽗容器可以抢⼦Veiw的事件
/**
外部拦截法:⽗容器处理冲突事件
* ⽗容器想要把事件分发给谁就分发给谁
* */
public class BadViewPager extends ViewPager {
private int mLastX, mLastY;
public BadViewPager(@NonNull Context context) {
super(context);
}
public BadViewPager(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
吴越文化}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
// if (Action() == MotionEvent.ACTION_DOWN){
// InterceptTouchEvent(event);
// return fal;
// }
/
/ return true;
int x = (int) X();
int y = (int) Y();
switch (Action()) {
ca MotionEvent.ACTION_DOWN: {
mLastX = (int) X();
入盆是什么意思mLastY = (int) Y();
怪石嶙峋break;
}
ca MotionEvent.ACTION_MOVE: {
int deltaX = x - mLastX;
int deltaY = y - mLastY;
if (Math.abs(deltaX) > Math.abs(deltaY)) {
//todo 如果 onInterceptTouchEvent =fal ⽗容器(BadViewPager)不拦截事件 , 分发给⼦view (MyListView ) ⽗容器(BadViewPager) 不处理事件(那么⽗容器就 // return fal;
//todo 如果 onInterceptTouchEvent =true ⽗容器(BadViewPager)拦截事件,不分发给⼦view (MyListView ) ⽗容器(BadViewPager) ⾃⼰处理事件(那么⽗容器就可 return true;
}
break;
}
我想日你ca MotionEvent.ACTION_UP: {
break;
}
default:
浅字组词break;
}
InterceptTouchEvent(event);
}
}
事件冲突案例2: ⽗容器 SwipeRefreshLayout 与⼦view Viewpager的冲突
/**
* ⽗容器CustomSRL2来处理这个冲突事件
10月22日是什么星座
* */
* */
public class CustomSRL2 extends SwipeRefreshLayout {
public CustomSRL2(Context context) {
super(context);
}
public CustomSRL2(Context context, AttributeSet attrs) {
super(context, attrs);
}
private int mLastX, mLastY;
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
int x = (int) ev.getX();
int y = (int) ev.getY();
switch (ev.getAction()){
//todo down ⽗容器拿到事件下⾯⽗容器如何处理这个事件呢?
ca MotionEvent.ACTION_DOWN: {
mLastX = (int) ev.getX();
mLastY = (int) ev.getY();
break;
}
ca MotionEvent.ACTION_MOVE: {
int deltaX = x - mLastX;
int deltaY = y - mLastY;
/
/todo 如果 Math.abs(deltaY) > Math.abs(deltaX) 上下垂直滑动, onInterceptTouchEvent=true ⽗容器SwipeRefreshLayout(上拉刷新) 拦截事件⾃⼰处理 if (Math.abs(deltaY) > Math.abs(deltaX)) {
return true ;
}
break;
}
ca MotionEvent.ACTION_UP: {
break;
}
default:
break;
}
InterceptTouchEvent(ev);
}
}
/**
* ⼦view ViewPager
*
* */
public class CustomVPInner extends ViewPager {
private float startX;
private float startY;
private float x;
private float y;
private float deltaX;
private float deltaY;
public CustomVPInner(Context context) {
super(context);
}
public CustomVPInner(Context context, AttributeSet attrs) {
super(context, attrs);
}