这几天一直在纠结这个问题。现在终于算是完满了。
先说说我都实现了什么:
1.欢迎页。
就是第一次启动才会出现的页面。用的是viewpager+SharedPreferences的方法。
2.侧滑出菜单栏。
本来是用的HorizontalScrollView来实现。可是不知怎么昨天是好的,睡了一觉出了个我解决不了的问题。后来直接用别人提供的方法。自定义类用自定义滑动。
E/HorizontalScrollView(8996): Invalid pointerId=-1 in onTouchEvent
有谁知道的求指点啊。
3.tabhost滑动切换。
4.两个tabhost的tab里面分别放入了listview和viewpager。
解决了这几个滑动操作的冲突问题。
概括起来主要就是两点:
A.怎么在父groupview的onintercepttouchevent()方法中拦截;
B.怎么在子groupview的onintercepttouchevent()方法中用getParent().requestDisallowInterceptTouchEvent(true);不允许拦截。
还有一种是重写dispatchtouchevent方法,我还不会,囧。
如果你不清楚touch事件的拦截机制,可以看看我上一篇,主要是我引用的那三篇文章。
关于android的touch事件分发,点开阅读
下面这些都是我的总结。
如果用A,请注意。第一、你当前要用来拦截的groupview能够点击的地方应该有子view,否则,down的时候找不到target,onintercepttouchevent()方法处理不到后续的动作。第二、如果拦截下来了,你还要考虑你本身是否时刻点击的,否则在ontouchEvent方法中会跳过直接返回!当然在ontouch中也是可以处理的。但是view的dispatchtouchevent方法中,ontouch方法前面还有两个判断,这是需要注意的,否则,ontouch中的代码可能会得不到执行!第三,可以发
现ontouch很像onintercepttouchevent(),都是在前面拦截,你还没执行我先看看。
如果用B,你需要把你所要保证出效果的view放在一个viewgroup中,这样,才能在onintercepttouchevent()重写中用getParent().requestDisallowInterceptTouchEvent(true);不允许拦截。这正是我用的方法。如果你要在view中直接用getParent().requestDisallowInterceptTouchEvent(true);你需要重写view的dispatchtouchevent()方法。一般来说,都是在down的时候不允许,在move的时候区分情况。
说了这么多都是空话。
下面我贴出主要的代码。
a、listview和tab的滑动切换的冲突,在只要是充满tab界面的一个viewgroup并且包含这个listview,最好直接自定义tabhost,重写onintercepttouchevent()。在move的时候判断拦截,只要拦截了代码就再也不会走到这里。只会走拦截的这个viewgroup的父类即view的dispatchtouchevent方法,如果这个viewgroup重写了view的这些方法你就必须小心,不要随意返回return super.onInterceptTouchEvent(ev);。(a标记)
case MotionEvent.ACTION_MOVE:
x_move = ev.getRawX();
y_move = ev.getRawY();
moveDistanceX = (int) (x_move - x_down);
moveDistanceY = (int) (y_move - y_down);
// 思考,如果要区分tab1和tab2呢?
if (tabHost.getCurrentTab() == 0) {
//判断横向还是纵向滑动,横向不交给listview,拦截
if (Math.abs(moveDistanceX) >= 2 * touchSlop
&& (istabSliding || Math.abs(moveDistanceY) <= 2 * touchSlop)) {
istabSliding = true;
}
if (istabSliding) {
//判断为滑动,拦截
return true;
}
}
上面的一个小知识
mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
这个值来自于ViewConfiguration.java,默认是8dp
它的意义是在触摸屏上操作时,当发生多大的移动时,触摸屏相应滑动或滚动的事件,
例如此值越小,相应越灵敏;此值越大,滑动时需要动作大一点,并且这个值对应的物理意义也收到触摸屏及其固件的微小影响
默认是8dp,可以在frameworks/base/core/res/res/values/config.xml里面配置
b、下面是怎么在边上划出菜单栏,自定义HorizontalScrollView
后来用其他方法写了,但此处拦截是几乎一样的
case MotionEvent.ACTION_MOVE:
x_move = ev.getRawX();
y_move = ev.getRawY();
moveDistanceX = (int) (x_move - x_down);
moveDistanceY = (int) (y_move - y_down);
// put the calculation out of this
//此判断是菜单显示时全部拦截,主要是菜单出来后,主界面还有一
//部分是漏出的,但这样不好,当菜单中有内容就不行
/*if (menu_visible) {
Log.i(TAG, "visibale"+"intercept");
return true;
}*/
// 把必须###拦截和必须不拦截###的情况写出,其余都return super.onInterceptTouchEvent(ev);
// 即按照这个控件继承的那个控件去完成操作,这正是我们要的。
if (!menu_visible) {
if ((x_down < 50 || x_move < 50) && wantToScroll()) {
Log.i(TAG, "invisible,it is slide:" + "intercept");
return true;
} else {
Log.i(TAG, "invisible,it is not slide:" +"no intercept");
// 这里必须不拦截
//而不能省略,因为HorizontalScrollView重写了onInterceptTouchEvent(ev)方法,
//返回的不是默认的false!正是爱标记出所说
return false;
}
} else {
// 这里拦截没能右边还露出来的那一部分,
// 当然可以直接在down拦截,但在down拦截虽然可以是吸纳
//不滑动listview,但同时也失去了点击隐藏的效果
if (x_down >= mMenuWidth) {
shouldScroll = true;
return true;
}
Log.i(TAG, "visible,it is slide:" + "intercept");
}
break;
c、接下来是tabhost里面的viewpager,自定义了一个Fragment把viewpager包起来了。仍然是重写onInterceptTouchEvent(ev)方法。
switch (action) {
case MotionEvent.ACTION_DOWN:// 按下
startX = event.getX();
getParent().requestDisallowInterceptTouchEvent(true);
break;
// 滑动,在此对里层viewpager的第一页和最后一页滑动做处理
case MotionEvent.ACTION_MOVE:
if (startX == event.getX()) {
if (0 == child_viewpager.getCurrentItem()
|| child_viewpager.getCurrentItem() == child_viewpager
.getAdapter().getCount() - 1) {
getParent().requestDisallowInterceptTouchEvent(false);
}
}
// 里层viewpager已经是最后一页,此时继续向右滑(手指从右往左滑)
else if (startX > event.getX()) {
if (child_viewpager.getCurrentItem() == child_viewpager
.getAdapter().getCount() - 1) {
getParent().requestDisallowInterceptTouchEvent(false);
}
}
// 里层viewpager已经是第一页,此时继续向左滑(手指从左往右滑)
else if (startX < event.getX()) {
if (child_viewpager.getCurrentItem() == 0) {
getParent().requestDisallowInterceptTouchEvent(false);
}
} else {
getParent().requestDisallowInterceptTouchEvent(true);
}
break;
case MotionEvent.ACTION_UP:// 抬起
case MotionEvent.ACTION_CANCEL:
getParent().requestDisallowInterceptTouchEvent(false);
break;
}
return false;
好了,就这么多了。我要继续学习其他方法了。祝大家愉快。
我上传了,可以去下载
设置为1分,主要我没下载分了(一分没有。。。),请不要吝啬。。。仅一分