模拟可折叠Toolbar:滚动偏移量不一致问题求助
嘿,我之前也碰到过这种滚动偏移量不稳定的坑,给你几个经过实践验证的靠谱方案,帮你解决快速滚动时的位置跳变问题:
1. 用NestedScrollView的滚动回调(如果用的是这个容器)
别直接重写onScrollChanged,改用setOnScrollChangeListener,它的回调参数里的scrollY是系统处理后的稳定值,兼容场景更多,快速滚动时也不会跳变:
nestedScrollView.setOnScrollChangeListener(new NestedScrollView.OnScrollChangeListener() { @Override public void onScrollChange(NestedScrollView v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) { float offsetFactorDown = (float) scrollY / (float) scrollRange; float scaleFactor = 1F - offsetFactorDown * 0.9F; scaleImage(scaleFactor, scaleFactor); } });
2. 基于RecyclerView的OnScrollListener(如果列表是RecyclerView)
如果你的滚动容器是RecyclerView,用它自带的滚动监听获取偏移量会更稳定,尤其是快速滚动时的惯性阶段:
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager(); if (layoutManager != null) { // 通过第一个可见Item的位置和顶部偏移计算总滚动量 int firstVisibleItemPos = layoutManager.findFirstVisibleItemPosition(); View firstVisibleItem = layoutManager.findViewByPosition(firstVisibleItemPos); int scrollY = (firstVisibleItemPos * layoutManager.getChildAt(0).getHeight()) - firstVisibleItem.getTop(); float offsetFactorDown = (float) scrollY / (float) scrollRange; float scaleFactor = 1F - offsetFactorDown * 0.9F; scaleImage(scaleFactor, scaleFactor); } } });
3. 直接计算头部布局的可见高度差
另一个思路是绕开滚动量,直接计算目标头部布局的可见高度变化:
// 先在布局测量完成后获取头部总高度 int headerTotalHeight = headerView.getMeasuredHeight(); // 在滚动回调里计算可见高度 int headerVisibleHeight = headerView.getBottom() - getScrollY(); if (headerVisibleHeight < 0) headerVisibleHeight = 0; // 用总高度减去可见高度作为实际偏移量 float offsetFactorDown = (float)(headerTotalHeight - headerVisibleHeight) / (float) scrollRange; float scaleFactor = 1F - offsetFactorDown * 0.9F; scaleImage(scaleFactor, scaleFactor);
4. 给getScrollY()加平滑处理(应急方案)
如果一定要用onScrollChanged的t参数(其实t就是当前的scrollY),可以做个简单的平滑加权处理,减少快速滚动时的跳变:
private float lastScrollY = 0; // 平滑因子,0.8是比较适中的值,可根据需求调整 private static final float SMOOTH_FACTOR = 0.8f; @Override protected void onScrollChanged(int l, int t, int oldl, int oldt) { // 用加权平均平滑滚动值,避免跳变 float currentScrollY = SMOOTH_FACTOR * lastScrollY + (1 - SMOOTH_FACTOR) * t; float offsetFactorDown = currentScrollY / (float) scrollRange; float scaleFactor = 1F - offsetFactorDown * 0.9F; scaleImage(scaleFactor, scaleFactor); lastScrollY = currentScrollY; }
内容的提问来源于stack exchange,提问作者Mr. Nacho
相关产品推荐
相关产品推荐

