@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int expandSpec = MeasureSpec.makeMeasureSpec(500,
MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
}
3 .解决滑动冲突问题
按照我上面的代码解决了显示不完全的问题,这时当你滑动recycleview时,无论如何会先响应recycleview的滑动事件,然后才响应scrollview的滑动事件,这样就达不到图片上的先将scrollview滑动指定位置,然后才让recycleview滑动的效果.原因就是recycleview抢走了scrollview的滑动事件,让recycleview消费了,scrollview就无法滑动了.
通过调用recyclerView.setNestedScrollingEnabled(false);就可以让recycleview不抢走scrollview的事件,这时在recycleview上滑动,也只会响应scrollview的滑动事件,recycleview是无法滑动的.这样还是达不到要求.于是就只能重写scrollview的onTouchevent方法和recycleview的dispatchtouchevent方法来解决冲突问题.
@Override
public boolean onTouchEvent(MotionEvent ev) {
boolean isup = false;
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
downY = (int) ev.getY();
isup = super.onTouchEvent(ev);
break;
case MotionEvent.ACTION_MOVE:
//防止从intercept直接跳过来
if (downY == 0) {
downY = (int) ev.getY();
}
//获取偏移量
int diffy = (int) (ev.getY() - downY);
if (diffy < 0) {//上拉
if (getScrollY() >= measuredHeight) {//当scrollview滑动的距离大于指定的距离时就让recycleview滑动
//修改父类的上一次事件的位置,防止跳动
mLastMotionY = (int) ev.getY();
//置顶了实际上是要让recycleview滑动了
isup = recyclerView.dispatchTouchEvent(ev);
} else {
//scrollview滑动
isup = super.onTouchEvent(ev);
}
} else if (diffy > 0) { //下拉
//如果recycleview没置顶就应该先让recycleview滑动
if (!isTop) {
//修改父类的上一次事件的位置
mLastMotionY = (int) ev.getY();
//recycleview滑动
isup = recyclerView.dispatchTouchEvent(ev);
} else {
//scrollview滑动
isup = super.onTouchEvent(ev);
}
}
//记录上一次的位置
downY = (int) ev.getY();
break;
case MotionEvent.ACTION_UP:
downY = 0;
isup = super.onTouchEvent(ev);
break;
}
return isup;
}
上面的代码就是我重写的scrollview的onTouchevent方法,注释的很详细了,我这里只重点说明一个问题,mLastMotionY 是父类Scrollview的私有变量,如果你是继承系统的Scrollview是修改不了的,我这里是将系统的Scrollview拷贝一份出来,然后将mLastMotionY的权限修改为公有的就可以修改了.这里为什么要修改这个属性呢,因为我调用recyclerView.dispatchTouchEvent(ev);让recycleview滑动,并没有调用super.onTouchevent方法这样父类Scrollview的mLastMotionY属性就不会被修改,需要我们主动修改.如果不修改这个属性,当我们先往上滑动在下拉,滑动完recycleview,让scrollview滑动时会突然跳很大一段距离.
下面是重写recycleview的dispatchtouchevent方法
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
downY = (int) ev.getY();
//在down的时候拦截,否则后面都拦截不到
getParent().requestDisallowInterceptTouchEvent(true);
break;
case MotionEvent.ACTION_MOVE:
LinearLayoutManager layoutManager = (LinearLayoutManager) this.getLayoutManager();
int firstCompletelyVisibleItemPosition = layoutManager.findFirstCompletelyVisibleItemPosition();
if (scrollYScrollView != null) {
if (firstCompletelyVisibleItemPosition == 0) {//recycleview置顶,通知scrollview
scrollYScrollView.setTop(true);
} else {
scrollYScrollView.setTop(false);
}
}
int diffy = (int) (ev.getY() - downY);
if (diffy > 0) {//下拉
if (firstCompletelyVisibleItemPosition == 0) {//当recycleview滑倒顶部时就不拦截,让scrollview滑动
getParent().requestDisallowInterceptTouchEvent(false);
} else {
//recycleview没滑到顶部,就先让recycleview滑动
getParent().requestDisallowInterceptTouchEvent(true);
}
} else if (diffy < 0) {//上拉
if (isTop) {//当scrollview置顶时就拦截,让recycleview滑动
getParent().requestDisallowInterceptTouchEvent(true);
}
} else {
//这里不仅要拦截,还要返回false,直接让scrollview滑动,不让recycleview滑动,
getParent().requestDisallowInterceptTouchEvent(false);
return false;
}
}
//记录上一次的位置
downY = (int) ev.getY();
break;
}
return super.dispatchTouchEvent(ev);
}
要看懂我重写的这个方法,就应该对android的事件分发机制有所了解,并且知道getParent().requestDisallowInterceptTouchEvent(false)方法的用处,这里如果传入是false表示父类可以拦截事件,当传入true时表示父类不可以拦截事件.还有我这里的isTop表示Scrollview是否滑动到指定的位置,不需要滑动了.这个是外面传入进来的.