前言
近期看了几篇关于 ScrollView 回弹的文章,比如下面几篇
可以看到,这几篇实现的原理,嗯,都是大同小异。但是,如果仔细看看网友的回复以及评论后,你会发现,好像这个是存在些许不完美的地方,并且我也遇到了。下面讲讲我复现的问题
复现
Step One
我的布局如下
<com.lib.bounceScrollView
android:id="@+id/bs_test"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusable="true"
android:focusableInTouchMode="true">
<android.support.v7.widget.RecyclerView
android:id="@+id/rc_test"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v7.widget.RecyclerView>
</com.lib.bounceScrollView>
ScrollView 中嵌套了 RecyclerView
Step Two
上面的 RecyclerView 中的模拟数据如下
/**
* 初始化数据
*/
private void initData(){
for(int i = 0; i < 5; i ++){
List<String> url = new ArrayList<>();
url.add("http://g.hiphotos.baidu.com/image/pic/item/c75c10385343fbf25431e823b27eca8065388f95.jpg");
url.add("http://g.hiphotos.baidu.com/image/pic/item/960a304e251f95ca2f34115acd177f3e6609521d.jpg");
mLists.add(url);
}
}
就是利用 Fresco 加载图片,用一个循环添加多条数据
Step Three
首先是模拟 RecyclerView 里面的数据高度不超过 ScrollView 的高度,效果如下:
可以看到,当我在下面空白区域进行上下拖动的时候,是有明显的回弹效果的;但是当点击图片上下拖动时,是不会存在回弹效果的(这个 Bug 也是大家发现最多的)
其次,模拟 RecyclerView 里面的数据高度超过 ScrollView 的高度,效果如下:
可以看出,当上滑到底部和头部的时候,是没有回弹效果的(这个 Bug 是我在使用 RecyclerView 后发现的,当我使用自定义 View 的时候没有发现)
why
从博客主那里,并没有得到相关的解释,那么我们就自己想想这究竟是为什么?
从上面的失败情况来看,很大的可能就是事件冲突导致的,大家可以想想整个事件的一个基本流程 ScrollView --> RecyclerView --> ItemView,尤其从未超过 ScrollView 高度来看,是最明显的:首先点击 ScrollView 的其他空白区域,可以明显的进行拖动显示回弹效果;但点击图片的位置上线拖到却没有效果,说明 ACTION_DOWN、ACTION_MOVE、ACTION_UP 等相关事件肯定存在被 RecyclerView 的 Item 的布局所消费。
解决
Step One
带着怀疑的态度,我在 ScrollView 中做了如下的更改
/**
* 用于解决事件冲突
* @param ev 事件
* @return 是否拦截
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
int offset = inner.getMeasuredHeight() - getHeight();//子布局总长度是否超过了scrollview的高度
if (offset <= 0) {//未超过
boolean intercepted = false;
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
intercepted = false;
break;
case MotionEvent.ACTION_MOVE:
intercepted = true;
break;
case MotionEvent.ACTION_UP:
intercepted = false;
break;
}
return intercepted;
}
else {//超过
return super.onInterceptTouchEvent(ev);
}
}
运行效果在 未超过 ScrollView 的情况下运行良好,但是,超过 ScrollView 的高度后,存在问题,如下图所示
可以看到,滑倒顶部或者头部,还是有问题(但是嵌套我写的一个自定义布局中,表现良好),说明事件分发没有写好
首先,上下滑动的事件 RecyclerView 自己就支持(而我写的自定义布局,需要使用到 Scrollview,二者的区别),而 ScrollView 自己也是支持这个的,所以二者存在冲突
Step Two
既然这样,我们既要支持 RecyclerView 的上下滑动,也要支持 ScrollView 滑倒底部和顶部的拖动效果,那么解决方法如下
/**
* solve the problem for not support little view to bounce
* @param ev event
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
super.onInterceptTouchEvent(ev);
boolean intercepted = false;
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
intercepted = false;
break;
case MotionEvent.ACTION_MOVE:
intercepted = true;
break;
case MotionEvent.ACTION_UP:
intercepted = false;
break;
}
return intercepted;
}
运行情况 如下
嵌套子 View 超过 ScrollVeiw 高度 嵌套子 View 未超过 ScrollVeiw 高度运行良好,Bingo。(这个过程中,还要解决 onClick 事件冲突,整个过程比较坎坷)该代码已传 Github,可以看看写的示例。
另外,在定义布局中,事件的分发机制是一个重点也是一个难点更是面试过程中的“考点”,大家一定要把这方面理解吃透,补充一个自己之前写的一个理解性的项目,希望对大家有帮助。
总结
现在的开源环境很良好,但是总会有很多的 Bug,所以大家在发现问题后,一方面可以咨询原主,但是最大的方面,还是要靠我们自己解决,要不然总是在 Copy 中,很难锻炼自己。
网友评论