10

我正在尝试添加一些视觉指示,即在 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;
    }
}
4

8 回答 8

19

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

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

祝你好运。

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

于 2012-07-15T03:37:40.920 回答
7

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

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

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

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

为了完成这项任务,您应该遵循我的三部分解决方案。(将带您 3-10 分钟)

第一部分:

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

(只需确保将 AOSP /res/drawable 目录中的 overscroll_edge 和 overscroll_glow 可绘制对象复制到您自己的项目中,因为它们是 android 内部的)

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

  1. 我声明该类扩展了 EdgeEffectCompat (我称我的类EdgeEffectForEarlyVersions)。public class EdgeEffectForEarlyVersions extends EdgeEffectCompat. 进行此更改的原因是mLeftEdgeandmRightEdge属于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 实例之后调用该函数,仅此而已。

我希望它会帮助某人。

于 2012-08-11T03:24:50.257 回答
3

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

https://github.com/inovex/ViewPager3D

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

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

于 2012-12-11T15:08:39.530 回答
1

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

于 2012-09-04T16:59:22.613 回答
1

您有很多选择,可以显示 Toast、显示 Dialog、使 TextView 或图像显示在您的 UI 上等。或者因为您知道 ViewPager 中 View 项目的数量,您可以在位置添加不同的 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) {
    }
});
于 2012-07-11T20:46:58.583 回答
0

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

于 2013-07-02T12:22:33.623 回答
0

您可以在片段中重载 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",...)
             }
        }
    }

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

于 2012-07-13T10:14:00.827 回答
-1

通常使用 ViewPager,使用PagerAdapter诸如FragmentPagerAdapterFragmentStatePagerAdapter用内容填充 ViewPager(您的内容将是视图)。

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

既然您现在知道了大小,您就可以使用 if 控制语句轻松显示消息。

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

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

于 2012-06-15T09:42:26.763 回答