【问题标题】:Handle scrolling for VerticalViewPager with NestedScrollView inside使用 NestedScrollView 处理 VerticalViewPager 的滚动
【发布时间】:2018-04-17 12:01:02
【问题描述】:

背景:

我正在使用 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 时,我都会从FragmentStatePagerAdapter 创建并返回一个android.support.v4.app.Fragment 的新实例,如下所列:

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

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

问题:

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

此外,弹回或滑回位置 0 非常非常困难或几乎不可能。

必填:

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

Link to the sample project as mentioned above

【问题讨论】:

  • 这不是一个真正的问题。你的问题是什么?如果您的问题是“我该怎么做?”,您尝试过什么?您可以考虑研究如何将NestedScrollView 与常规ViewPager 一起使用,看看它的技术是否可以适应您的场景。或者,也许尝试使用RecyclerView 而不是VerticalViewPager,尽管这需要您从片段切换到页面视图。
  • 是的,我该怎么做?我的问题是“如何使用我在问题中提到的当前实现来完成这项工作?”。我尝试使用 RecyclerView(项目宽度和高度设置为 match_parent),通过将每个子项包装在 NestedScrollView 中,但没有运气。没有运气,我切换到 VerticalViewPager,其中每个页面再次包装在 NestedScrollView 中。如何在使用 RecyclerView 或 VerticalViewPager 使页面本身滚动或切换到下一页的同时使内容滚动?
  • @CommonsWare 这就像如何使子级或页面内的滚动与被包裹在另一个 ScrollView(RecyclerView 或 ViewPager)之类的组中的子级一起工作?如果我遗漏任何信息,请告诉我。
  • 我从来没有使用过NestedScrollView,所以我不知道有什么解决方案让它适合你的情况。我已经发布了一个赏金,看看我们是否能得到答案。
  • @CommonsWare 当然。谢谢你:-)

标签: android android-viewpager scrollview android-nestedscrollview nestedscrollview


【解决方案1】:

我浏览了您的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))));

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

【讨论】:

  • NestedScrollView.computeVerticalScrollRange()、NestedScrollView.computeVerticalScrollOffset()、NestedScrollView.computeVerticalScrollExtent(),只能在同一个库组内调用(groupId=com.android.support) 此API已被标记有一个尚未满足的限制。
  • 不应从 android 框架访问受限制的方法,因为这是不可接受的,并且限制将来可能会更加严格,或者可以随时更改。这将使应用程序无法编译并明显破坏当前功能。
  • 别担心,您可以使用 @SuppressLint("RestrictedApi") 。看到这个 - stackoverflow.com/questions/41150995/…
  • Anurag Singh 是对的,这些方法受到限制是有原因的,Google 不想让它们成为 API 的一部分,以便它们可以随时更改或消失。
  • @KarandeepAtwal,感谢您从百忙之中抽出时间并发布解决方案。我仍在修改您发布的解决方案以克服 RestrictedApi 访问并修改我当前的嵌套滚动方法。 FYKI,我没有投反对票。我不知道还有一个功能可以知道谁投了反对票。
猜你喜欢
  • 2019-09-17
  • 2018-11-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-11
  • 2020-03-05
  • 1970-01-01
相关资源
最近更新 更多