其实嵌套滚动已经算一个比较常见的特效了,下面这个动图就是嵌套滚动的一个例子:
看到这个动效,大家可能都知道可以用CoordinatorLayout去实现.其实CoordinatorLayout是基于NestedScroll机制去实现的,而我们直接通过NestedScroll机制也能很方便的实现这个动效.
原理
NestedScroll的其实很简单.
一般的触摸消息的分发都是从外向内的,由外层的ViewGroup的dispatchTouchEvent方法调用到内层的View的dispatchTouchEvent方法.
而NestedScroll提供了一个反向的机制,内层的view在接收到ACTION_MOVE的时候,将滚动消息先传回给外层的ViewGroup,看外层的ViewGroup是不是需要消耗一部分的移动,然后内层的View再去消耗剩下的移动.内层view可以消耗剩下的滚动的一部分,如果还没有消耗完,外层的view可以再选择把最后剩下的滚动消耗掉.
上面的描述可能有点绕,可以看下面的图来帮助理解:
具体实现
NestedScroll机制会涉及到四个类:
NestedScrollingChild, NestedScrollingChildHelper 和 NestedScrollingParent , NestedScrollingParentHelper
NestedScrollingChild和NestedScrollingParent是两个接口,我们先看看他们的声明:
public interface NestedScrollingChild { public void setNestedScrollingEnabled(boolean enabled); public boolean isNestedScrollingEnabled(); public boolean startNestedScroll(int axes); public void stopNestedScroll(); public boolean hasNestedScrollingParent(); public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int[] offsetInWindow); public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow); public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed); public boolean dispatchNestedPreFling(float velocityX, float velocityY); } public interface NestedScrollingParent { public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes); public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes); public void onStopNestedScroll(View target); public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed); public void onNestedPreScroll(View target, int dx, int dy, int[] consumed); public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed); public boolean onNestedPreFling(View target, float velocityX, float velocityY); public int getNestedScrollAxes(); }
这里真正重要的其实是NestedScrollingParent的几个方法,因为其他方法都能直接让NestedScrollingChildHelper或者NestedScrollingParentHelper去代理:
我们只要让子view和父view分别实现NestedScrollingChild和NestedScrollingParent接口,然后分别调用NestedScrollingChildHelper和NestedScrollingParentHelper的对应方法去代理一些具体功能,然后在NestedScrollingChild的onTouchEvent那里根据需求调用startNestedScroll/dispatchNestedPreScroll/stopNestedScroll就能实现嵌套滚动了:
//NestedScrollingChild private NestedScrollingChildHelper mHelper = new NestedScrollingChildHelper(this); public boolean startNestedScroll(int axes) { return mHelper.startNestedScroll(axes); } public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int[] offsetInWindow) { return mHelper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, offsetInWindow); } ...
//NestedScrollingParent private NestedScrollingParentHelper mHelper = new NestedScrollingParentHelper(this); public void onNestedScrollAccepted(View child, View target, int axes) { mHelper.onNestedScrollAccepted(child, target, axes); } public int getNestedScrollAxes() { return mHelper.getNestedScrollAxes(); } ...
但是如果你使用sdk21及以上的版本,NestedScroll机制已经直接集成到了View中了,你只需要直接重写View的对应方法就好
布局
我们先看布局文件
<me.linjw.nestedscrolldemo.NestedScrollParentView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <FrameLayout android:id="@+id/header" android:layout_width="match_parent" android:layout_height="wrap_content"> <ImageView android:layout_width="match_parent" android:layout_height="200dp" android:src="@mipmap/ic_launcher" /> </FrameLayout> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/colorAccent" android:text="Title" android:textAlignment="center" android:textSize="20dp" /> <android.support.v7.widget.RecyclerView android:id="@+id/list" android:layout_width="match_parent" android:layout_height="match_parent" /> </me.linjw.nestedscrolldemo.NestedScrollParentView>
最外层是我们自定义的NestedScrollParentView,其实它是一个LinearLayout,内部竖直排列了三个子view:
代码
为了简便起见,我们先直接用sdk22的版本用重写View方法的方式去实现它.
NestedScrollParentView中有两个方法比较重要,嵌套滚动基本上就是由这两个方法实现的:
@Override public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) { return true; } @Override public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) { super.onNestedPreScroll(target, dx, dy, consumed); boolean headerScrollUp = dy > 0 && getScrollY() < mHeaderHeight; boolean headerScrollDown = dy < 0 && getScrollY() > 0 && !target.canScrollVertically(-1); if (headerScrollUp || headerScrollDown) { scrollBy(0, dy); consumed[1] = dy; } }
onStartNestedScroll 这个方法如果返回true的话代表接受由内层传来的滚动消息,我们直接返回true就好,否则后面的消息都接受不到
onNestedPreScroll 这个方法用于消耗内层view的一部分滚动.我们需要将消耗掉的滚动存到counsumed中让consumed知道.例如我们这里在顶部的FrameLayout需要移动的情况下会消耗掉所有的dy,这样内层的view(即RecyclerView)就不会滚动了.
这里的mHeaderHeight保存的是顶部的FrameLayout的高度:
@Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mHeaderHeight = mHeader.getMeasuredHeight(); }
到这里基本上就实现了动图的效果,是不是很简单?
完整代码可以参考 https://github.com/bluesky466/NestedScrollDemo/tree/sdk22
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持小牛知识库。
我使用嵌套的Scrollview来包装recyclerview和其他按钮。它工作得很好,但我注意到当我滚动它时,它并不平滑。请指导如何使滚动平滑。
问题内容: 我想了解嵌套列表的理解。下面,我列出了一个列表理解表达式及其for循环等效项。 我不知道我的理解是否正确。 例如, 相当于 如果可以概括一下,我猜 表格可以翻译为以下内容。(我希望我是对的) 对于更简单的情况, 等于 而, 等于 我问了一个类似的问题,即用于复杂列表理解 的循环表达式的等效项。那里给出的答案是在理解了表单内部的内容之后重构了表单。 我想知道它是如何系统地工作的,因此我可
本文向大家介绍Android简单实现无限滚动自动滚动的ViewPager,包括了Android简单实现无限滚动自动滚动的ViewPager的使用技巧和注意事项,需要的朋友参考一下 经常我们会在应用中看到一个可以自动滚动,并且无限滚动的一个ViewPager,百度谷歌上面也有很多关于这方面的教程,但是感觉都略显麻烦,而且封装的都不是很彻底。所以试着封装一个比较好用的ViewPager 效果如下: 简
本文向大家介绍vue-router实现嵌套路由的讲解,包括了vue-router实现嵌套路由的讲解的使用技巧和注意事项,需要的朋友参考一下 一、嵌套路由(配置好父路由component后,在父路由下面添加children属性来配置这个父路由的子路由) 需要注意的是:父组件中的<router-view></router-view>是子组件的占位符是必不可少的 嵌套路由的现象:点击了路由跳转之后父路由
问题内容: 我正在尝试解析这种结构:(它使我发疯,并且我尝试了我能想到的一切。但是我不是很有经验) “ topDrop”就像文件名吗?player是一个JSONArray,包含5个播放器JSONObject。但是在JSON术语中,最重要的是什么。我在JSON验证程序上签出有效的凭证,我需要这样的凭证: topDrop作为JSONObject Player,作为JSONArray,并循环遍历数组中的