【问题标题】:visual indication of over scroll in androidandroid中过度滚动的视觉指示
【发布时间】:2012-06-02 03:59:49
【问题描述】:

我正在尝试添加一些视觉指示,即在 ViewPager 中没有更多页面位于所需的投掷方向。但是,我正在努力寻找放置相关代码的地方。

我尝试使用以下代码扩展 ViewPager 类,但 Toast 未显示(ev.getOrientation() 始终返回 0)。我也尝试过使用历史记录点,但ev.getHistorySize() 也返回 0。

我错过了什么?

类示例:

public class CustomViewPager extends ViewPager {

    public CustomViewPager(Context context) {
        super(context);
    }

    public CustomViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    /**
     * @see android.support.v4.view.ViewPager#onTouchEvent(android.view.MotionEvent)
     */
    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        boolean result = super.onTouchEvent(ev);

        switch (ev.getAction() & MotionEventCompat.ACTION_MASK) {
            case MotionEvent.ACTION_MOVE:
                if (ev.getOrientation() > 0) {
                    Toast.makeText(getContext(), "left", 0).show();
                }
        }

        return result;
    }
}

【问题讨论】:

    标签: android android-viewpager android-compatibility android-overscoll


    【解决方案1】:

    如果您查看 v4 支持库,您会看到 ViewPager 使用了一个名为 EdgeEffectCompat 的类(当您到达 ICS+ 中视图寻呼机的开头或结尾时,它会提供发光效果)如果您查看实现在兼容库中,您将看到它有一个 if 语句来查看构建版本是否为 14+ (ICS)。如果是,那么它最终会使用 ICS 中引入的普通 EdgeEffect 类结束(如果您跟踪足够长的时间)。否则它使用 BaseEdgeEffectImpl ,它基本上没有任何内容。

    如果您愿意,您可以制作自己的自定义 ViewPager,使用您自己的 EdgeEffect。您可以查看 android 源代码以了解他们如何实现 EdgeEffect here,您几乎可以复制它(只需确保将 AOSP /res/drawable 目录中的 overscroll_edgeoverscroll_glow drawables 复制到您自己的项目中因为它们是 android 内部的)或继续创建您自己的版本。

    祝你好运。

    (顺便说一句,这就是他们如何在 ICS 的启动器菜单中创建看起来很酷的边缘倾斜效果......所以你几乎可以尽情发挥创意;)

    【讨论】:

    • 这看起来应该这样做!谢谢。
    【解决方案2】:

    我试图获得与此问题中提出的完全相同的效果。我为此苦苦挣扎,然后我阅读了@wna​​fee 的答案(没有它我无法做到)。

    但是我很难实现从答案中听起来很简单的东西。 我在实现它时遇到了很多麻烦,以至于我可能没有正确理解答案,但是由于我没有在兼容库的同一个包中工作,所以存在太多无法访问的 API 问题。

    在我尝试了一些方法后(没有一个成功,而且它们非常复杂),我转向了一个稍微不同的方向,现在它就像一个魅力。我用了一些反射,没用过的人不用担心,这真的是反射的基础。

    我不确定它是否是目前最好的解决方案,但它对我有用,所以如果您想使用它,欢迎您。请阅读 Wnafee 示例,因为它解释了我所做的一些事情。

    为了完成这项任务,您只需遵循我的三部分解决方案即可。 (需要 3-10 分钟)

    第一部分:

    正如 Wnafee 所说,我刚刚通过复制粘贴 here 的源代码制作了自己的 EdgeEffect 类,

    (只要确保复制 overscroll_edge 和 overscroll_glow AOSP /res/drawable 目录中的drawables 到你自己的项目 因为它们是 android 内部的)

    我只做了 2 个非常小的改动:

    1. 我声明该类扩展了 EdgeEffectCompat(我将我的类称为 EdgeEffectForEarlyVersions)。 public class EdgeEffectForEarlyVersions extends EdgeEffectCompat。进行此更改的原因是 mLeftEdgemRightEdge 的类型为 EdgeEffectCompat
    2. 在“我的”新类的构造函数的第一行,我添加了对父构造函数super(context); 的调用。由于EdgeEffectCompat 没有默认构造函数,因此您必须显式调用构造函数。

    第二部分

    除此之外,我还编写了另一个函数。该函数的目的是在早期版本(ICS 之前)的情况下,我们希望使用我们刚刚复制的EdgeEffectForEarlyVersions。为了达到这个目的,我使用了反射。

    这是函数:

    private static void changeEdgeEffectCompactOnEarlyVersions(ViewPager viewPager, Context context)
    {
        /* In case that the version is earlier than 14 there is only empty implementation for the edge effect, therefore we change it.
         * for more information look on the following links:
         * 1. http://stackoverflow.com/questions/10773565/visual-indication-of-over-scroll-in-android
         * 2. http://grepcode.com/file/repo1.maven.org/maven2/com.google.android/support-v4/r7/android/support/v4/view/ViewPager.java#ViewPager.0mLeftEdge
         * 3. http://grepcode.com/file/repo1.maven.org/maven2/com.google.android/support-v4/r7/android/support/v4/widget/EdgeEffectCompat.java#EdgeEffectCompat
         */
    
        if (Build.VERSION.SDK_INT < 14)
        {
            try
            {
                Class<ViewPager> viewPagerClass = ViewPager.class;
                //Get the left edge field, since it is private we used getDeclaredField and not getDeclared 
                Field leftEdge = viewPagerClass.getDeclaredField("mLeftEdge");
                leftEdge.setAccessible(true);
                //Get the right edge field, since it is private we used getDeclaredField and not getDeclared
                Field rightEdge = viewPagerClass.getDeclaredField("mRightEdge");
                rightEdge.setAccessible(true);
    
                EdgeEffectForEarlyVersions leftEdgeEffect = new EdgeEffectForEarlyVersions(context);
                EdgeEffectForEarlyVersions rightEdgeEffect = new EdgeEffectForEarlyVersions(context);
    
                //Set the mLeftEdge memeber of viewPager not to be the default one, but to be "our" edgeEffect  
                leftEdge.set(viewPager, leftEdgeEffect);
                //Set the mRightEdge memeber of viewPager not to be the default one, but to be "our" edgeEffect
                rightEdge.set(viewPager, rightEdgeEffect);              
            }
            catch (Exception ex)
            {
                Log.e("refelection", ex.getMessage());
            }
    
        }
    }
    

    第三部分

    现在剩下要做的就是在拥有 ViewPager 实例之后调用该函数,仅此而已。

    我希望它会对某人有所帮助。

    【讨论】:

    • 这不适用于 API
    【解决方案3】:

    wnafee 很好地解释了解决方案,但对于我们当中的懒惰者,我在很久以前就做了一个实际的工作实现。

    https://github.com/inovex/ViewPager3D

    如果您只想过度滚动,请看这里:

    https://github.com/inovex/ViewPager3D/issues/1

    【讨论】:

      【解决方案4】:

      您有很多选择,可以显示 Toast、显示 Dialog、在 UI 上显示 TextView 或图像等。或者因为您知道 ViewPager 中 View 项目的数量,您可以添加不同的在位置 0 和/或 n + 1 处查看消息并使其反弹到实际包含您的数据的最后一个视图。

      你可以实现:

      viewPager.setOnPageChangeListener(new OnPageChangeListener() {
          public void onPageSelected(int position) {
              //TODO If position is the 0 or n item, add a view at 0 or at n+1 to indicate there is no more pages with data.
          }
      
          public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
              // TODO Show a Toast, View or do anything you want when position = your first/last  item;
          }
      
          public void onPageScrollStateChanged(int state) {
          }
      });
      

      【讨论】:

      • 当您尝试滚动到 ViewPager 的末尾时,会出现系统标准的发光效果,这与滚动到列表底部的顶部时相同。我想要这样的东西 - 但它应该适用于所有版本(当前的发光是 ICS-only)。您的建议会使 UI 变得笨拙,如果这些确实是唯一的选择,那么我将坚持不做任何指示。
      • 我知道这对我的应用程序来说已经足够了,但如果@ekramus 问,我认为是因为他需要更多的东西。 :)
      【解决方案5】:

      只是为了补充@goBeepit 开发人员的答案,当您创建自己的 edgeffect 类并从 EdgeEffectCompat 扩展时,某些方法需要是布尔值。您可以将这些方法更改为布尔类型,然后在任何情况下都返回 true,这样一切正常

      【讨论】:

        【解决方案6】:

        您可以在片段中重载 setUserVisibleHint(boolean) 函数。伪代码:

            void setUserVisibleHint(boolean isVisibleToUser) {
                // If this fragment is becoming visible
                if (isVisibleToUser == true) {
                     // Check if it is the last fragment in the viewpager
                     if (indexOfThis == getActivity().indexOfLast) {
                        // Display right limit reached
                        Toast(..., "No more Frags to right",...)
                        }
                     // Check if it is the first fragment in the viewpager
                     else if (indexOfThis == getActivity().indexOfFirst) {
                        // Display Left Limit reached
                        Toast(..., "No more Frags to left",...)
                     }
                }
            }
        

        我没有为此目的使用此功能,但出于其他原因使用它并且它确实可以正常触发。希望这会有所帮助...

        【讨论】:

        • 这与 Oscar 的答案具有相同的 UI 含义,只是它覆盖了一个不打算被覆盖的方法,而不是使用侦听器,这似乎很危险。
        【解决方案7】:

        我已经基于 Renard 的 ViewPager3D 实现了反弹效果:https://stackoverflow.com/a/17425468/973379

        【讨论】:

          【解决方案8】:

          通常使用 ViewPager,使用 PagerAdapter(例如 FragmentPagerAdapterFragmentStatePagerAdapter)来让 ViewPager 充满内容(您的内容将成为视图)。

          现在,当您使用PagerAdapter 时,您有一个名为getCount()http://developer.android.com/reference/android/support/v4/view/PagerAdapter.html#getCount%28%29 的方法,它将为您提供内容的大小。

          从现在开始,知道可以使用 if 控制语句轻松显示消息的大小。

          试试这个代码:http://developer.android.com/reference/android/support/v4/view/ViewPager.html

          注意:我认为您不需要自定义 ViewPager。您还需要了解 ViewPager 的片段。查看 ApiDemos 中的示例。它是一个很好的来源。

          【讨论】:

          • 他不是这么问的。他特别想知道如何在 iOS 上制作像橡皮筋一样的过度滚动效果,至少在 ICS 之前,ViewPager 中都没有这种效果。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-09-07
          • 1970-01-01
          • 1970-01-01
          • 2014-10-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多