ListView使用案例一之滑动冲突
程序员文章站
2024-03-24 17:50:16
...
ListView的使用
在我们学会使用recyclerview之前,我们一定是在ListView的世界中在挣扎,彷徨,忧郁,困惑,然而,当我们真正的封装好了的话也可以趟过这趟混水,迈入新的天地。
下面就给大家带来我项目中曾经遇到过的ListView的坑,当然你可能也会遇到,并且有了不一样的处理方法,此处仅供已懂的人参考,不懂的人借鉴。
首先给大家发一波我遇到的各类滑动冲突的‘撞车事故’:
1)ScrollView内部套用ListView,GridView的滚动冲突事件
处理方法:重写ListView的onMeasure()方法即可,代码如下
import android.content.Context;
import android.util.AttributeSet;
import android.widget.ListView;
//解决ListView外部套用ScrollView的滚动冲突事件
public class MyListView extends ListView{
public MyListView(Context context) {
super(context);
}
public MyListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//设置当前ListVIew的高度为ListView所有内容加起来的整体高度,此高度最多不能超过Integer.MAX_VALUE>>2
int heightSpec;
if (getLayoutParams().height==LayoutParams.WRAP_CONTENT){
heightSpec= MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE>>2,MeasureSpec.AT_MOST);
}else {
heightSpec=heightMeasureSpec;
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
2)解决ScrolView内嵌套ViewPager的滚动问题
处理方法:重写ScrolView的onMeasure()方法即可,代码如下
注:这里可能设计到SimpleOnGestureListener的使用,此为用户触屏时对各类不同手势处理的类,下一篇文章中将做出对它的详细使用说明,当然,如果你是个老司机,也可以直接百度它,也是有一堆合理的解释和使用说明的 -_-)
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
import android.view.View;
import android.webkit.WebView;
import android.widget.ScrollView;
import android.widget.Scroller;
/**
* 自定义ScrollView,解决:ScrollView嵌套ViewPager,导致ViewPager不能滑动的问题
*/
public class CustomScrollView extends ScrollView {
private GestureDetector mGestureDetector;
private int Scroll_height = 0;
private int view_height = 0;
protected Field scrollView_mScroller;
private static final String TAG = "CustomScrollView";
public CustomScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
mGestureDetector = new GestureDetector(context, new YScrollDetector());
setFadingEdgeLength(0);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
stopAnim();
}
boolean ret = super.onInterceptTouchEvent(ev);
boolean ret2 = mGestureDetector.onTouchEvent(ev);
return ret && ret2;
}
// Return false if we're scrolling in the x direction
class YScrollDetector extends SimpleOnGestureListener {
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
if (Math.abs(distanceY) > Math.abs(distanceX)) {
return true;
}
return false;
}
}
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
boolean stop = false;
if (Scroll_height - view_height == t) {
stop = true;
}
if (t == 0 || stop == true) {
try {
if (scrollView_mScroller == null) {
scrollView_mScroller = getDeclaredField(this, "mScroller");
}
Object ob = scrollView_mScroller.get(this);
if (ob == null || !(ob instanceof Scroller)) {
return;
}
Scroller sc = (Scroller) ob;
sc.abortAnimation();
} catch (Exception e) {
Log.e(TAG, e.getMessage());
}
}
super.onScrollChanged(l, t, oldl, oldt);
}
private void stopAnim() {
try {
if (scrollView_mScroller == null) {
scrollView_mScroller = getDeclaredField(this, "mScroller");
}
Object ob = scrollView_mScroller.get(this);
if (ob == null) {
return;
}
Method method = ob.getClass().getMethod("abortAnimation");
method.invoke(ob);
} catch (Exception ex) {
Log.e(TAG, e.getMessage());
}
}
@Override
protected int computeVerticalScrollRange() {
Scroll_height = super.computeVerticalScrollRange();
return Scroll_height;
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
if (changed == true) {
view_height = b - t;
}
}
@Override
public void requestChildFocus(View child, View focused) {
if (focused != null && focused instanceof WebView) {
return;
}
super.requestChildFocus(child, focused);
}
/**
* 获取一个对象隐藏的属性,并设置属性为public属性允许直接访问
*
* @return {@link Field} 如果无法读取,返回null;返回的Field需要使用者自己缓存,本方法不做缓存
*/
public static Field getDeclaredField(Object object, String field_name) {
Class<?> cla = object.getClass();
Field field = null;
for (; cla != Object.class; cla = cla.getSuperclass()) {
try {
field = cla.getDeclaredField(field_name);
field.setAccessible(true);
return field;
} catch (Exception e) {
}
}
return null;
}
}
3)ViewPager内部套用ViewPager时发生的横向滑动冲突
处理方法:重写内部横向滑动的ViewPager中的onTouchEvent()方法即可,代码如下
import android.content.Context;
import android.graphics.PointF;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.MotionEvent;
/**
* 自定义ViewPager,解决ViewPagger嵌套使用时不滑动问题。
*/
public class HorizontalInnerViewPager extends ViewPager {
/** 触摸时按下的点 **/
PointF downP = new PointF();
/** 触摸时当前的点 **/
PointF curP = new PointF();
public HorizontalInnerViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
mGestureDetector = new GestureDetector(context, new XScrollDetector());
}
public HorizontalInnerViewPager(Context context) {
super(context);
mGestureDetector = new GestureDetector(context, new XScrollDetector());
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return super.onInterceptTouchEvent(ev);//default
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
//每次进行onTouch事件都记录当前的按下的坐标
curP.x = ev.getX();
curP.y = ev.getY();
if(ev.getAction() == MotionEvent.ACTION_DOWN){
//记录按下时候的坐标
//切记不可用 downP = curP ,这样在改变curP的时候,downP也会改变
downP.x = ev.getX();
downP.y = ev.getY();
//此句代码是为了通知他的父ViewPager现在进行的是本控件的操作,不要对我的操作进行干扰
getParent().requestDisallowInterceptTouchEvent(true);
}
if(ev.getAction() == MotionEvent.ACTION_MOVE){
//此句代码是为了通知他的父ViewPager现在进行的是本控件的操作,不要对我的操作进行干扰
getParent().requestDisallowInterceptTouchEvent(true);
}
return super.onTouchEvent(ev);
}
}
4)ViewPager中嵌套ScrollView,ScrollView中又嵌套另一个ViewPager的滑动冲突事件
**处理方法:
1)确定嵌套模型:我的嵌套是ViewPager–>ScrollView–>ViewPager;
2)最里面的ViewPager水平滚动时总是会触发最外层的ViewPager滚动,我们用自定义内部的ViewPager即可处理(使用3中相同的处理方法);
3)但此时最里面的ViewPager垂直滚动时外层的ScrollView并不会滚动(增加2中的SimpleOnGestureListener手势滑动监听处理方法)。**
import android.content.Context;
import android.graphics.PointF;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
/**
* 自定义ViewPager,解决ViewPagger嵌套使用时不滑动问题。
*/
public class HorizontalInnerViewPager extends ViewPager {
/** 触摸时按下的点 **/
PointF downP = new PointF();
/** 触摸时当前的点 **/
PointF curP = new PointF();
/** 自定义手势**/
private GestureDetector mGestureDetector;
public HorizontalInnerViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
mGestureDetector = new GestureDetector(context, new XScrollDetector());
}
public HorizontalInnerViewPager(Context context) {
super(context);
mGestureDetector = new GestureDetector(context, new XScrollDetector());
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return super.onInterceptTouchEvent(ev);//default
//当拦截触摸事件到达此位置的时候,返回true,
//说明将onTouch拦截在此控件,进而执行此控件的onTouchEvent
// return true;
//接近水平滑动时子控件处理该事件,否则交给父控件处理
// return mGestureDetector.onTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
//每次进行onTouch事件都记录当前的按下的坐标
curP.x = ev.getX();
curP.y = ev.getY();
if(ev.getAction() == MotionEvent.ACTION_DOWN){
//记录按下时候的坐标
//切记不可用 downP = curP ,这样在改变curP的时候,downP也会改变
downP.x = ev.getX();
downP.y = ev.getY();
//此句代码是为了通知他的父ViewPager现在进行的是本控件的操作,不要对我的操作进行干扰
getParent().requestDisallowInterceptTouchEvent(true);
}
if(ev.getAction() == MotionEvent.ACTION_MOVE){
float distanceX = curP.x - downP.x;
float distanceY = curP.y - downP.y;
//接近水平滑动,ViewPager控件捕获手势,水平滚动
if(Math.abs(distanceX) > Math.abs(distanceY)){
//此句代码是为了通知他的父ViewPager现在进行的是本控件的操作,不要对我的操作进行干扰
getParent().requestDisallowInterceptTouchEvent(true);
}else{
//接近垂直滑动,交给父控件处理
getParent().requestDisallowInterceptTouchEvent(false);
}
}
return super.onTouchEvent(ev);
}
private class XScrollDetector extends GestureDetector.SimpleOnGestureListener{
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
// return super.onScroll(e1, e2, distanceX, distanceY);
//接近水平滑动时子控件处理该事件,否则交给父控件处理
return (Math.abs(distanceX) > Math.abs(distanceY));
}
}
}
未完待续… …
上一篇: ThinkPHP使用方法小记
下一篇: Gulp 使用