SwipeRefreshLayout 嵌套ScrollView,
在实际app项目开发中,往往会遇到SwipeRefreshLayout
嵌套ScrollView
,ScrollView
嵌套RecyclerView
的情况,虽然官方文档上强烈建议了:ScrollView
不要嵌套RecyclerView
,ListView
滑动.gifNever add a RecyclerView or ListView to a scroll view. Doing so results in poor user interface performance and a poor user experience.
那我们就解决嵌套之后出现的问题。
问题一:SwipeRefreshLayout
与ScrollView
滑动冲突
SwipeRefreshLayout
负责的是下拉刷新,ScrollView
负责页面的上下滑动,可以根据具体的业务需求来解决滑动冲突。
(1)如果ScrollView
高度没有全屏,可以通过触碰的焦点是否在该ScrollView
上来设置
swipeRefreshLayout.isEnable = isFocus
(2)如果是全屏,ScrollView
有一个监听滑动的方法
void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY);
通过scrollY的滑动的位置来设置即可:
scrollView.setOnScrollChangeListener { _, _, _, _, _ ->
swipeRefreshLayout.isEnabled = (scrollView.scrollY <= 0)
}
问题二:ScrollView与RecyclerView滑动冲突
官方强烈建议二者不要嵌套,因为嵌套之后,ScrollView
会失去惯性滑动,造成页面卡顿。一个简单的办法就是关闭RecyclerView
的滑动。
class VerticalScrollLinearLayoutManager : LinearLayoutManager {
private var mIsScroll = false
constructor(context:Context):super(context)
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes)
fun setScrollEnabled(isScroll: Boolean) {
mIsScroll = isScroll
}
override fun canScrollVertically(): Boolean {
return mIsScroll && super.canScrollVertically()
}
}
通过对RecyclerView
的LayoutManager
来控制是否可以滑动,如果单纯的关闭RecyclerView
的滑动就会造成RecyclerView
无法上拉加载更多,所以当ScrollView
滑到底端时并且滑动手势向上时,要开启RecyclerView
的滑动。即setScrollEnable(true)
判断ScrollView
滑到底端的方法:
scrollView.getChildAt(0).height - scrollView.height == scrollView.scrollY
所以整个逻辑就是
when (event.action) {
MotionEvent.ACTION_DOWN -> {
if (ScreenUtil.isViewFocus(event, commentView)) {
lastY = event.rawY.toInt()
curY = event.rawY.toInt()
} else {
lastY = -1
curY = -1
}
}
MotionEvent.ACTION_MOVE -> {
if (ScreenUtil.isViewFocus(event, commentView)) {
curY = event.rawY.toInt()
if (lastY - curY > ViewConfiguration.get(context).scaledTouchSlop) {
isScrollUp = true
}
} else {
isScrollUp = false
curY = -1
lastY = -1
}
}
MotionEvent.ACTION_UP -> {
isScrollUp = false
lastY = -1
curY = -1
}
}
// 当滑倒最底端时且仍往上
if (commentTitle.visibility == View.VISIBLE
&& isScrollUp
&& scrollView.getChildAt(0).height - scrollView.height == scrollView.scrollY) {
recyclerView.setScrollEnable(true)
} else {
recyclerView.setScrollEnable(false)
}