android - 在 Fragment 级别应用的滑动手势以及禁用默认滑动的 ViewPager

标签 android android-fragments android-viewpager swipe-gesture

我发现下面的问题:
Android: FragmentActivity inside FragmentActivity (ScrollView in NavigationBar)
.然而,我的这个问题是关于如何使用事务来显示 fragment 以及以安全的方式启用滑动手势检测。
注意:我发布的答案中有一个链接(这也有一种使用事务在容器中显示 fragment 的有效方法,包括两种场景)。请看那个。
我已经尝试了一些有关方面的事情,但是通过使用支持 ViewPager 的 fragment ,而不是嵌套:

详情:https://moqups.com/abhsax130778@gmail.com/lc0ZOERO/p:a5d7b55eb

  • 使用自定义 ViewPager 禁用使用 onTouchEvent 和 onInterceptTouchEvent 的默认滑动。
  • 声明的 FragmentStatePagerAdapter 提供了一个 fragment 列表,每个 fragment 都显示在每个选项卡中。
  • 在 main_activity 的 main_layout 中声明 Fragments,它旁边有这个 ViewPager。
    想法是在单击 ViewPager_fragment 上的按钮以及用户按下返回时显示 activity_fragments
    按钮,然后使用后台堆栈事务再次显示默认的 ViewPager_fragment 并在 Activity 的 BackPressed 上弹出它们。因此,我还维护我的自定义后台堆栈,以在后台堆栈弹出事务时显示/隐藏 activity_fragments。

  • 现在我想要实现的是仅使用向右 [从左到右] 滑动的滑动手势来完成上面的第三点。

    为此,我使用了 GestureListener 和 SimpleOnGestureListener 以及 Activity 的 OnTouchEvent。

    我面临的问题是:

    此手势适用于 fragment 下方的 Activity 屏幕部分和 Activity 部分。
    我想要手势工作
  • 在其布局中有多个 View 的 Fragment 区域上。
  • 只在左右方向。
  • 仅从 activity_fragment 到 ViewPager 的选项卡 fragment ,其行为就像在 onBakPressed/onKeyDown 中已经完成的历史导航一样
    使用返回堆栈弹出窗口和我的自定义返回堆栈实现。

  • 我尝试了以下类(class),并在这样的布局中更改了我的 Activity fragment 。

    我的手势和触摸监听器扩展了框架布局:
            public class OnSwipeTouchListener extends FrameLayout {
    
            private final GestureDetector gestureDetector;
            private static final String TAG = "OnSwipeTouchListener";
        private Context context;
            public OnSwipeTouchListener(Context context, AttributeSet attrs) {
                super(context, attrs);
                this.context=context;
                gestureDetector = new GestureDetector(context, new GestureListener());
                setClickable(true);
    
            }
    
            @Override
            public boolean onInterceptTouchEvent(MotionEvent ev) {
                return super.onInterceptTouchEvent(ev);
            }
    
            @Override
            public boolean onTouchEvent(MotionEvent event) {
     gestureDetector.onTouchEvent(motionEvent);
                return super.onTouchEvent(event);
            }
    
    
            private final class GestureListener extends SimpleOnGestureListener {
    
                private static final int SWIPE_THRESHOLD = 100;
                private static final int SWIPE_VELOCITY_THRESHOLD = 100;
    
                @Override
                public boolean onDown(MotionEvent e) {
    
                    return true;
                }
    
                @Override
                public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
    
                    boolean result = false;
                    try {
                        float diffY = e2.getY() - e1.getY();
                        float diffX = e2.getX() - e1.getX();
                        if (Math.abs(diffX) > Math.abs(diffY)) {
                            if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
                                if (diffX > 0) {
                                    onSwipeRight();
                                } else {
                                    onSwipeLeft();
                                }
                            }
                        } else {
                            if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) >           SWIPE_VELOCITY_THRESHOLD) {
                                if (diffY > 0) {
                                    onSwipeBottom();
                                } else {
                                    onSwipeTop();
                                }
                            }
                        }
                    } catch (Exception exception) {
                        //see that e1 is null
                    }
                    return result;
                }
            }
    
            public void onSwipeRight() {
                ///manage my back stack history here.
            }
    
            public void onSwipeLeft() {
            }
    
            public void onSwipeTop() {
            }
    
            public void onSwipeBottom() {
            }
        }
    

    然后将框架布局更改为此类引用:
    <path.to.my.package.OnSwipeTouchListener
                android:id="@+id/activity_frag_frame_layout1"
                android:layout_width="fill_parent"
                android:layout_height="fill_parent"
                android:visibility="invisible" >
    
                <fragment
                    android:id="@+id/activity_frag1"
                    android:layout_width="fill_parent"
                    android:layout_height="fill_parent"
                    class="path.to.my.package.fragments.Activity_Frag1"
                    android:tag="act_frag1" />
            </path.to.my.package.OnSwipeTouchListener>
    

    它对我帮助不大,所以它应该可以帮助您找到解决方案。在停止工作的 fragment 之一中有一个searchView,并且没有点击工作。
    如果您得到了我想要实现的目标,请在这方面提供帮助。

    更新 1:
    在 onTouchEvent 和 onInterceptTouchEvent 中返回 true 具有预期的效果,但它会阻止 SearchView 所在 fragment 中的点击,在存在的可点击 View 中没有点击工作。只有滑动有效。更新:在我的最新消息中:我也完全放弃了事务返回堆栈的使用,因为我依赖于我的自定义返回堆栈,我在其中维护所有选项卡的导航历史记录。我使用 ViewPager 和 FragmentStatePagerAdapter 提供的 setCurrentTab 和 onTabSelected 方法来执行此操作。

    更新 2:
    这个很难实现:
    检查哪些事件需要拦截,哪些要传递给 subview :http://developer.android.com/training/gestures/viewgroup.html

    更新 3:
  • 在我的 Activity 布局中,有一个 View 寻呼机,在它下面的每个框架布局中,都有一个 fragment 。
  • 当您启动应用程序时,ViewPager 会在第一个选项卡中显示 fragment 。
  • 单击此 fragment 上的按钮时,将显示 View 寻呼机下方的框架布局中的一个 fragment 并将其添加到我的自定义返回堆栈中。
  • 当按下返回键时,该 fragment 再次隐藏以在 View 分页器中显示选项卡 fragment 。以上每一项都完成了。只有我想让从左到右的滑动手势起作用,我发现我可以通过拦截触摸事件来做到这一点。
    但它根本不这样做 当我返回 true 时,
    只有滑动手势有效,否则取消此操作并
    这个 fragment 的点击工作。
  • 最佳答案

    我在 http://mobi-app-dev.blogspot.in/2014/01/android-transactions.html 中提到了这个答案.

    检查哪些事件需要拦截,哪些要传递给 subview :http://developer.android.com/training/gestures/viewgroup.html

    而不是在框架布局中使用我的滑动手势监听器
    附有哪些 fragment ,
    现在我在相对布局上使用它,这些布局是
    fragment 。

    @Override
        public boolean onInterceptTouchEvent(MotionEvent event) {
            boolean intercepted = super.onInterceptTouchEvent(event);
    
            // In general, we don't want to intercept touch events. They should be
            // handled by the child view.
    
            gestureDetector.onTouchEvent(event);
            return false;
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            boolean touched = super.onTouchEvent(event);
            gestureDetector.onTouchEvent(event);
            return touched;
        }
    

    以下是我在 Activity 中使用 fragment 时遵循的一些提示:

    fragment 交易的有效管理:

    [注意:如果您正在使用 FragmentStatePagerAdapter,您可以在用作此适配器数据的 fragment 列表中的特定索引处用另一个 fragment 替换一个 fragment ,就像您在同一选项卡中一样但它的内容在不改变标签的情况下发生了变化。然后使用notifyDataSetChanged()。在这里您不使用事务,否则您使用]。
  • 使用 Fragment.instantiate() 来初始化你的 fragment 而不是
    构造函数。
  • 使用监听器更新/删除实例的引用
    (来自用于引用它们的集合) fragment onCreateView 和 onDestroy。
  • 使用 getView() 在每个地方和更新时获取 fragment 的根 View
    功能。
  • 不要跟踪实例,事实上尽可能避免使用静态指针。
  • 使用 getSupportFragment 而不是保留 FragmentManager 的引用
    在 View 寻呼机适配器或其他地方。
  • 在事务隐藏 View 上使用附加分离,以摆脱 subview
    Fragment 的根 View 并重新初始化。
    这是因为一次只需要一个 fragment 可见,其他 fragment 需要分离。
    因此,按需重新附加。
  • getActivity() 或 getApplicationContext() 任何适用的,而不是保留
    保持对上下文的引用的全局变量。
  • onConfiguration 更改(方向、键盘、调整大小):在 Activity 中执行并传递它
    到管理它的 Activity fragment 。
    重要提示:如果您确实想将 fragment 用于事务,请不要在布局中声明它们。
    在添加 fragment 事务中提供容器(布局)ID。
  • Fragment 事务应该在事件调用中完成,而不是在其他任何地方,
    并且这样的事件不应该重复。这可以防止非法参数异常。
  • 有一个 ViewPager 方法,您不必使用 Fragments。相反,
    您可以使用 View 或 View 组。这取代了 fragment 的嵌套。
  • 检测 fragment 的级别,这意味着如果您希望 fragment “B”替换现有 fragment “A”,并且当您想在按下“B”时返回以显示 fragment “A”时,请将该交易放回原处堆。


  • 提示:添加滑动功能时要小心,因为还有其他可点击的 View 。
    在 RootView 上使用拦截触摸滑动返回 false 但分析触摸。

    还有一件事:您应该观察到,一次将一个 fragment 放在一个容器中可以解决另一个问题:如果有两个 fragment ,一个在另一个 fragment 的顶部,则来自一个 fragment 的点击会转到下方的另一个 fragment 。所以隐藏或替换一次只有一个 fragment 。 Back-Stack 有助于维护导航级别,并且在配置更改或更新时,尝试更新目标 Activity fragment 的相同实例,而不是执行事务,因为这会更改导航 fragment 的顺序。

    关于android - 在 Fragment 级别应用的滑动手势以及禁用默认滑动的 ViewPager,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18821775/

    相关文章:

    android - 在 TabLayout 下面添加一行

    android - auth().signInWithPhoneNumber() 不适用于 react native

    android - 在 Android 中更改设备方向时如何避免黑屏

    android - 如何在移动到 viewpager 中的下一页之前检查条件

    Android - ViewPager 滚动重置

    java - 从命令行运行gradle时如何将自定义JAR文件添加到CLASSPATH?

    android - 改造和集中错误处理

    java - 带有 ViewPagers oncreateView 的 Android fragment 在错误的 fragment 中调用

    android - onDestroy后,生命周期回调被重新调用

    android - 在适配器的构造函数中传递 fragment