android - 使用内部的 NestedScrollView 处理 VerticalViewPager 的滚动

标签 android android-viewpager scrollview android-nestedscrollview nestedscrollview

背景:

我正在使用 ViewPager 的变体,它不是在水平方向滚动,而是在垂直方向滚动。

VerticalViewPager: https://android.googlesource.com/platform/packages/apps/DeskClock/+/master/src/com/android/deskclock/VerticalViewPager.java

android.support.v4.app.FragmentStatePagerAdapter 用于设置 VerticalViewPager 中的内容。

每次 getItem() 时,我都会从 FragmentStatePagerAdapter 创建并返回 android.support.v4.app.Fragment 的新实例FragmentStatePagerAdapter 的调用如下所示:

@Override
public Fragment getItem(int position) {
   return  PreviewFragment.getNewFragmentInstance(position);
}

PreviewFragment 呈现可能不适合屏幕的内容。 为了显示所有不适合屏幕的内容,android.support.v4.widget.NestedScrollView 被用作 PreviewFragment 布局的父元素。

问题:

PreviewFragment 的内容确实按预期滚动到位置 0。 但是滑动到位置 1 的页面非常困难,因为必须多次执行滑动或滑动操作才能切换到下一页。

此外,向回位置 0 猛扑或轻扫非常困难或几乎不可能。

必需:

滑动或滑动或切换到 PreviewFragment 的下一个实例应该是平滑的。 换句话说,内容的滚动应该是流畅的,同时请记住滑动到下一页也应该是流畅的。

Link to the sample project as mentioned above

最佳答案

我浏览了你的Github代码。我让它为你工作。我也发送了一个拉取请求。问题是 onInterceptTouchEvent 如果返回 true 它会使 ViewPager 滚动,如果我们返回它 false 它禁用 ViewPager 触摸并使 NestedScrollView 滚动。所以我在这里做的是检查 NestedScrollView 是否需要滚动然后我返回它 false 如果 NestedScrollView 在顶部或底部,我返回它为 true。我在这里发布代码。您可以修改它并使其更干净。

Github 链接 - https://github.com/karanatwal/vertical-viewpager-nestedscrollview

下面是VerticalViewPager代码 -

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    boolean toIntercept = super.onInterceptTouchEvent(flipXY(ev));
    // Return MotionEvent to normal


    float x = ev.getX();

    flipXY(ev);
    int direction=1;

    switch (ev.getAction()) {
        case MotionEvent.ACTION_DOWN:
            mStartDragX = x;
            break;

        case MotionEvent.ACTION_MOVE:
            if (mStartDragX < x ) {
                direction=-1;
            } else if (mStartDragX > x) {
                direction=1;
            }
            MainActivity.MyPagerAdapter adapter = (MainActivity.MyPagerAdapter)this.getAdapter();
            if (adapter.getCurrentFragment() instanceof FragmentViewPager){
                FragmentViewPager fragmentViewPager = (FragmentViewPager)adapter.getCurrentFragment();
                toIntercept = !fragmentViewPager.getNestedScrollView().canScrollVertically(direction);
                int range = fragmentViewPager.getNestedScrollView().computeVerticalScrollRange();
                int offset = fragmentViewPager.getNestedScrollView().computeVerticalScrollOffset();
                int extent = fragmentViewPager.getNestedScrollView().computeVerticalScrollExtent();
                int percentage = (int)(100.0 * offset / (float)(range - extent));

                System.out.println("  range: "+range);
                System.out.print("  offset: "+offset);
                System.out.print("  extent: "+extent);                  
                System.out.print("  percentage: "+percentage);
                System.out.print("  direction: "+direction);

                if (fragmentViewPager.getNestedScrollView().computeVerticalScrollOffset()==0 && direction==-1){
                    //top
                    return true;
                }
                else if (percentage>99 && direction==1){
                    //bottom
                    return true;
                }else {
                    //scroll nestedscrollview
                    return false;
                }

            }

            break;
    }


    return toIntercept;
}

您的 MyPagerAdapter -

public class MyPagerAdapter extends FragmentStatePagerAdapter {

    public MyPagerAdapter(FragmentManager fm) {
        super(fm);
    }

    private Fragment mCurrentFragment;

    public Fragment getCurrentFragment() {
        return mCurrentFragment;
    }
    //...
    @Override
    public void setPrimaryItem(ViewGroup container, int position, Object object) {
        if (getCurrentFragment() != object) {
            mCurrentFragment = ((Fragment) object);
        }
        super.setPrimaryItem(container, position, object);
    }

    @Override
    public android.support.v4.app.Fragment getItem(int pos) {
        switch (pos) {
            case 0:
                return FragmentViewPager.newInstance("Title Start", R.drawable.ic_launcher_background);
            case 1:
                return FragmentViewPager.newInstance("Rock", R.drawable.rock);
            case 2:
                return FragmentViewPager.newInstance("Paper", R.drawable.paper);
            case 3:
                return FragmentViewPager.newInstance("Scissors", R.drawable.scissors);
            case 4:
                return FragmentViewPager.newInstance("Title End", R.drawable.ic_launcher_background);
            default:
                return FragmentViewPager.newInstance("Default Title", R.drawable.rock);
        }
    }

    @Override
    public int getCount() {
        return 5;
    }
}

为避免受限的 API 方法 - 使用以下逻辑作为替代

 //offset , range and extent
            int scrollY = scrollView.getScrollY();               
            int scrollContentHeight = scrollView.getChildAt(0).getHeight();
            int screenHeight = Utility.getScreenHeight(context); 
            int statusBarHeight = Utility.getStatusBarHeight(context);

            double percent = ((((float) scrollY) / ((float) (scrollContentHeight - screenHeight + statusBarHeight))));

您只需要滚动的百分比和滑动的方向。在 SO 上还有很多关于查找滚动百分比和滑动方向的问题,例如 thisthis .你应该为它做一点研发。

关于android - 使用内部的 NestedScrollView 处理 VerticalViewPager 的滚动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49877547/

相关文章:

android - Jetpack Compose 中的居中文本

Android水平滚动列表

android - 垂直 ViewPager 和 Android Pie 与滑动手势不一致的行为

java - ScrollView 始终可聚焦

ios - ScrollView 不滚动并在底部创建空白

android - 无法设置动态部分大小 : Memory exhausted

android - 居中 WRAP_CONTENT

android - 显示 fragment 时停止滚动 CollapsingToolbarLayout

android - 查看寻呼机和 ListView

ios - 无法检测到 ScrollView 中的 Swift UI 组件