2023年6月27日发(作者:)
实践-同⽅向和不同⽅向Android滑动冲突解决⽅案Android 说明:为了⽂章简洁,下⾯将⽤简写代替控件或⽅法全称。总控件:VG 代替 ViewGroup纵向控件:SRL 代替 SwipeRefreshLayoutTL 代替 TabLayoutSV 代替 ScrollViewRV 代替 RecyclerViewLV 代替 ListView横向控件:VP 代替 ViewPagerSM 代替 SlideMenu事件传递:disTE 代替 dispatchTouchEvent(事件分发)onITE 代替 onInterceptTouchEvent(事件拦截)onTE 代替 onTouchEvent(事件消费)reDITE 代替 requestDisallowInterceptTouchEvent(⼦View要求⽗View不要拦截事件)setOTL 代替 setOnTouchListenerView事件分发机制如果⼤家不了解View的事件分发机制,可以参看⽂章:事件冲突实际上就是对事件分发机制的应⽤。解决事件冲突总结来看有下列⼏种⽅法:⽗View # onITE ⽅法:决定事件是否向⼦View传递。⼦View # disTE ⽅法:通过 reDITE 来⼲预⽗View事件的分发。⼦View # setOTL ⽅法:通过 reDITE 来⼲预⽗View事件的分发。注意:标志位在MOVE事件和DOWN事件中都会起作⽤。滑动冲突分为三种情况:同⽅向;不同⽅向;同⽅向和不同⽅向混合。同⽅向:核⼼要点:保证外部滑动的时候只滑动外部,内部滑动的时候只滑动内部。点击事件交给合适的View处理。冲突场景:只有⼀层能滑动;内外层同时滑动很卡顿。+SV/RV:没有冲突。分析:SRL:重写了onITE⽅法。向下滑动,Y轴距离⼤于最⼩滑动距离,拦截事件,效果正常。SV/RV:没有重写disTE⽅法。向上滚动,效果正常。+SV:有滑动冲突。问题:内部不能滑动。分析:外部Y轴距离⼤于最⼩滑动距离,拦截事件,导致内部不能滑动。解决:内部拦截:内部滑动时,执⾏getparent().reDITE(true);public class SV_SV_inner extends ScrollView { public SV_SV_inner(Context context) { super(context); } public SV_SV_inner(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { getParent().requestDisallowInterceptTouchEvent(true); return chTouchEvent(ev); }}外部拦截:public class SV_SV_outer extends ScrollView { public SV_SV_outer(Context context) { super(context); } public SV_SV_outer(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { rceptTouchEvent(ev); return false; }}+RV:有滑动冲突。问题:内层在滑动时,外层也在滑动,滑动很卡顿。分析:SV:重写了onInterceptTouchEvent⽅法。当Y轴移动距离⼤于最⼩滑动距离时,就会拦截事件,否则向⼦View传递。RV:没有重写dispatchTouchEvent⽅法。解决:内部拦截:内部滑动时,通过reDITE设置为true使事件向⼦View分发。通过打印⽇志会发现:当内部滑动的时候,外部没有在滑动。效果实现。public class SV_RV_inner extends RecyclerView { public SV_RV_inner(Context context) { super(context); } public SV_RV_inner(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { getParent().requestDisallowInterceptTouchEvent(true); if (ion() == _MOVE) { Log.d("SV_RV", "dispatchTouchEvent: 内层在滑动++"); } return chTouchEvent(ev); }}+VP:没有滑动冲突。分析:打印⽇志发现:外部滑动的时候内部没有滑动,内部滑动的时候外部没有滑动。综上,同⼀⽅向有滑动冲突的有两个例⼦:只有⼀层能滑动的例⼦:SV+SV内外层同时滑动很卡顿的例⼦:SV+RV不同⽅向:核⼼点:判断谁来拦截:根据滑动是⽔平滑动还是竖直滑动来判断到底由谁来拦截事件。判断滑动⽅向:根据滑动过程中两点之间的坐标滑动路径和⽔平⽅向所形成的夹⾓(滑动⾓度)⽔平和竖直⽅向距离差(距离差)(常⽤)⽔平和竖直⽅向速度差(速度差)滑动冲突出现的根本原因:上层View拦截了下层View导致下层View⽆法滑动。+VP:问题:VP左下右下滑动时,SRL也在上下滑动。SRL拦截掉了VP的滑动事件。分析:SRL源码:Y轴⼤于最⼩滑动距离时,⽗View拦截事件,否则不拦截。解决:内部拦截:SRL_VP_outer:public class SRL_VP_outer extends SwipeRefreshLayout { public SRL_VP_outer(Context context) { super(context); } public SRL_VP_outer(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { if (ion() == _DOWN) { rceptTouchEvent(ev); return false; } return rceptTouchEvent(ev); }}SRL_VP_inner:public class SRL_VP_inner extends ViewPager { private float startX; private float startY; private float x; private float y; private float deltaX; private float deltaY; public SRL_VP_inner(Context context) { super(context); } public SRL_VP_inner(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { switch (ion()) { case _DOWN: startX = (); startY = (); //注释1 tedScrollingEnabled(this, true); getParent().requestDisallowInterceptTouchEvent(true); break; case _MOVE: x = (); y = (); deltaX = (x - startX); deltaY = (y - startY); if (deltaX < deltaY) { getParent().requestDisallowInterceptTouchEvent(false); } break; case _UP: case _CANCEL: break; } return chTouchEvent(ev); }}注释1:因为SRL重写了requestDisallowInterceptTouchEvent这个⽅法,edScrollingEnabled(mTarget)默认为false,导致tDisallowInterceptTouchEvent(b)不执⾏,所以要设置edScrollingEnabled为true。外部拦截:SRL_VP_out_SRL:public class SRL_VP_out_SRL extends SwipeRefreshLayout { private boolean mIsBeingDragged; private float initialX; private float initialY; private float x; private float y; private float deltaX; private float deltaY; private int mTouchSlop; boolean isVpDragged = false; public SRL_VP_out_SRL(Context context) { super(context); } public SRL_VP_out_SRL(Context context, AttributeSet attrs) { super(context, attrs); mTouchSlop = (context).getScaledTouchSlop(); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { switch (ion()) { case _DOWN: initialX = (); initialY = (); isVpDragged = false; break; case _MOVE: //只要⼿指不离开就⼀直返回false if (isVpDragged) return false; x = (); y = (); deltaX = (x - initialX); deltaY = (y - initialY); if (deltaX > deltaY) { isVpDragged = true; return false; } break; case _UP: case _CANCEL: isVpDragged = false; break; } return rceptTouchEvent(ev); }}+VP:没有冲突。+SV:没有冲突。+LV:没有冲突。
发布者:admin,转转请注明出处:http://www.yc00.com/news/1687841649a49960.html
评论列表(0条)