- CompoundButton 源码分析
- LinearLayout 源码分析
- SearchView 源码解析
- LruCache 源码解析
- ViewDragHelper 源码解析
- BottomSheets 源码解析
- Media Player 源码分析
- NavigationView 源码解析
- Service 源码解析
- Binder 源码分析
- Android 应用 Preference 相关及源码浅析 SharePreferences 篇
- ScrollView 源码解析
- Handler 源码解析
- NestedScrollView 源码解析
- SQLiteOpenHelper/SQLiteDatabase/Cursor 源码解析
- Bundle 源码解析
- LocalBroadcastManager 源码解析
- Toast 源码解析
- TextInputLayout
- LayoutInflater 和 LayoutInflaterCompat 源码解析
- TextView 源码解析
- NestedScrolling 事件机制源码解析
- ViewGroup 源码解析
- StaticLayout 源码分析
- AtomicFile 源码解析
- AtomicFile 源码解析
- Spannable 源码分析
- Notification 之 Android 5.0 实现原理
- CoordinatorLayout 源码分析
- Scroller 源码解析
- SwipeRefreshLayout 源码分析
- FloatingActionButton 源码解析
- AsyncTask 源码分析
- TabLayout 源码解析
捋一捋流程
1、当 NestedScrollingChild(下文用 Child 代替) 要开始滑动的时候会调用 onStartNestedScroll
,然后交给代理类 NestedScrollingChildHelper(下文 ChildHelper 代替)的 onStartNestedScroll
请求给最近的 NestedScrollingParent(下文 Parent 代替).
2、当 ChildHelper 的 onStartNestedScroll
方法 返回 true 表示同意一起处理 Scroll 事件的时候时候,ChildHelper 会通知 Parent 回调 onNestedScrollAccepted
做一些准备动作
3、当 Child 要开始滑动的时候,会先发送 onNestedPreScroll
,交给 ChildHelper 的 onNestedPreScroll
请求给 Parent ,告诉它我现在要滑动多少距离,你觉得行不行,这时候 Parent 根据实际情况告诉 Child 现在只允许你滑动多少距离.然后 ChildHelper 根据 onNestedPreScroll 中回调回来的信息对滑动距离做相对应的调整。
4、在滑动的过程中 Child 会发送 onNestedScroll
通知 ChildeHelpaer 的 onNestedScroll
告知 Parent 当前 Child 的滑动情况。
5、当要进行滑行的时候,会先发送 onNestedFling 请求给 Parent,告诉它 我现在要滑行了,你说行不行,这时候 Parent 会根据情况告诉 Child 你是否可以滑行。
6、Child 通过 onNestedFling
返回的 Boolean 值来觉得是否进行滑行.如果要滑行的话,会在滑行的时候发送 onNestedFling 通知告知 Parent 滑行情况。
7、当滑动事件结束就会 child 发送 onStopNestedScroll
通知 Parent 去做相关操作。
如果你此刻还是看得模模糊糊,没错,是我的责任,啊哈哈哈。要不我给个例子实践下,我们知道 5.0 之前的 ListView 是没有实现 NestedScrollingChild 这个接口的,如果要实现 CoordinatorLayout 里嵌套着 ListView 和 Toolbar,我们上下滑动 ListView 的时候,Toolbar 会随之显现隐藏,就必须重写 ListView.给出我实现的代码吧!
package com.cjj.nestedlistview;
import android.content.Context;
import android.support.v4.view.MotionEventCompat;
import android.support.v4.view.NestedScrollingChild;
import android.support.v4.view.NestedScrollingChildHelper;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.ListView;
public class NestedListView extends ListView implements NestedScrollingChild {
private NestedScrollingChildHelper mChildHelper;
private int mLastY;
private final int[] mScrollOffset = new int[2];
private final int[] mScrollConsumed = new int[2];
private int mNestedOffsetY;
public NestedListView(Context context) {
super(context);
init();
}
public NestedListView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public NestedListView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
mChildHelper = new NestedScrollingChildHelper(this);
setNestedScrollingEnabled(true);
}
@Override
public void setNestedScrollingEnabled(boolean enabled) {
mChildHelper.setNestedScrollingEnabled(enabled);
}
@Override
public boolean startNestedScroll(int axes) {
return mChildHelper.startNestedScroll(axes);
}
@Override
public void stopNestedScroll() {
mChildHelper.stopNestedScroll();
}
@Override
public boolean hasNestedScrollingParent() {
return mChildHelper.hasNestedScrollingParent();
}
@Override
public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int[] offsetInWindow) {
return mChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, offsetInWindow);
}
@Override
public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) {
return mChildHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow);
}
@Override
public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
return mChildHelper.dispatchNestedFling(velocityX, velocityY, consumed);
}
@Override
public boolean dispatchNestedPreFling(float velocityX, float velocityY) {
return mChildHelper.dispatchNestedPreFling(velocityX, velocityY);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
final int action = MotionEventCompat.getActionMasked(event);
int y = (int) event.getY();
event.offsetLocation(0, mNestedOffsetY);
switch (action) {
case MotionEvent.ACTION_DOWN:
mLastY = y;
mNestedOffsetY = 0;
break;
case MotionEvent.ACTION_MOVE:
int dy = mLastY - y;
int oldY = getScrollY();
startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL);
if (dispatchNestedPreScroll(0, dy, mScrollConsumed, mScrollOffset)) {
dy -= mScrollConsumed[1];
event.offsetLocation(0, -mScrollOffset[1]);
mNestedOffsetY += mScrollOffset[1];
}
mLastY = y - mScrollOffset[1];
if (dy < 0) {
int newScrollY = Math.max(0, oldY + dy);
dy -= newScrollY - oldY;
if (dispatchNestedScroll(0, newScrollY - dy, 0, dy, mScrollOffset)) {
event.offsetLocation(0, mScrollOffset[1]);
mNestedOffsetY += mScrollOffset[1];
mLastY -= mScrollOffset[1];
}
}
stopNestedScroll();
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
stopNestedScroll();
break;
}
return super.onTouchEvent(event);
}
}
效果:
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论