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

Abh*_*ena 7 android android-fragments swipe-gesture android-viewpager

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

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

  1. 使用onTouchEvent和onInterceptTouchEvent使用自定义ViewPager禁用默认滑动.
  2. 声明FragmentStatePagerAdapter提供了一个片段列表,每个片段都显示在每个选项卡中.
  3. 在具有此ViewPager的main_activity的main_layout中声明Fragment.想法是在单击ViewPager_fragment上的按钮时以及当用户按下返回按钮时显示activity_fragments,然后使用添加的后堆栈事务再次显示默认的ViewPager_fragment,并在活动的BackPressed上弹出它们.因此,当后端堆栈弹出事务时,我也维护我的自定义backStack来显示/隐藏activity_fragments.

现在我想要实现的是在上面的第三点使用滑动手势进行右[从左到右]滑动.

我已经使用了GestureListener和SimpleOnGestureListener以及activity的OnTouchEvent.

我面临的问题是:

该手势在活动屏幕的位于片段下方和活动部分的部分上起作用.我希望手势有效

  1. 在片段区域中,其布局中具有多个视图.
  2. 只在左右方向.
  3. 仅从activity_fragment到ViewPager的选项卡片段,就像使用后台堆栈弹出窗口和我的自定义后台堆栈在onBakPressed/onKeyDown实现中已经完成的那样,就像历史导航一样.

我尝试了以下类,并在这样的布局中更改了我的活动片段.

My Gesture和Touch监听器扩展了框架布局:

        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() {
        }
    }
Run Code Online (Sandbox Code Playgroud)

然后将帧布局更改为此类引用:

<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>
Run Code Online (Sandbox Code Playgroud)

它帮助我很少,所以它应该帮助你找到解决方案.其中一个片段中的searchView停止工作,没有点击工作.如果你得到了我想达到的目标,请在这方面提供帮助.

更新1:在onTouchEvent和onInterceptTouchEvent中返回true具有所需的效果,但它会阻止SearchView所在的片段中的点击,在可点击的视图中没有点击工作.只有滑动才有效.更新:在我最新的:我也完全放弃了事务回写栈的使用,因为我依赖于我的自定义后台,我维护所有选项卡的导航历史记录.我使用ViewPager和FragmentStatePagerAdapter给出的setCurrentTab和onTabSelected方法.

更新2:这个难以实现:检查哪些事件需要被截获以及哪些事件要传递给子视图:http://developer.android.com/training/gestures/viewgroup.html

更新3:

  1. 在我的活动布局中,有一个视图寻呼机,在它下面的每个帧布局中都有一个片段.

  2. 启动应用程序时,viewPager会在第一个选项卡中显示该片段.

  3. 单击此片段上的按钮时,将显示viewpager下面的framelayouts中的一个片段,并将其添加到我的自定义后台堆栈中.

  4. 按下返回键时,将再次隐藏此片段以在viewPager中显示制表符片段.以上所有内容都已完成.只有我想要从左到右的滑动手势才能工作,我发现我可以通过拦截触摸事件来实现.但它根本不会这样做当我返回true时,只有滑动手势有效,否则此动作将被取消并且此片段的点击有效.

Abh*_*ena 1

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

检查哪些事件需要被拦截以及哪些事件要传递给子视图:http://developer.android.com/training/gestures/viewgroup.html

现在我在相对布局(片段的根视图)上使用它,而不是在附加片段的框架布局中使用我的滑动手势侦听器。

@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;
    }
Run Code Online (Sandbox Code Playgroud)

以下是我在活动中使用 Fragment 时遵循的一些提示:

有效管理碎片的交易:

[注意:如果您使用 FragmentStatePagerAdapter,您可以将一个片段替换为您用作此适配器数据的片段列表中特定索引处的另一个片段,就像您位于同一选项卡中一样但其内容已更改,但未更改选项卡。然后使用notifyDataSetChanged()。在这里您不使用事务,但否则您会使用]。

  1. 使用 Fragment.instantiate() 来初始化片段而不是构造函数。
  2. 使用侦听器更新/删除片段 onCreateView 和 onDestroy 实例的引用(来自用于引用它们的集合)。
  3. 使用 getView() 获取片段的根视图以及更新功能。
  4. 不要跟踪实例,事实上,尽可能避免静态指针。
  5. 使用 getSupportFragment 而不是在视图寻呼机适配器或其他地方保留 FragmentManager 的引用。
  6. 在事务隐藏视图上使用附加分离,以删除 Fragment 根视图上的子视图并重新初始化。这是因为一次只需要一个片段可见,其他片段需要分离。因此,请根据需要重新连接。
  7. getActivity() 或 getApplicationContext() 无论适用,而不是保留全局变量来保留对上下文的引用。
  8. onConfiguration 更改(方向、键盘、调整大小):在活动中执行并将其传递给管理它的活动片段。重要提示:如果您确实想使用片段进行事务,请不要在布局中声明它们。在添加片段事务中提供容器(布局)id。
  9. Fragment事务应该在事件调用中完成,而不是在其他地方,并且这样的事件不应该是重复的。这可以防止非法参数异常。
  10. 有一个 ViewPager 方法,您不必使用 Fragments。相反,您可以使用 Views 或 ViewGroups。这取代了片段的嵌套。
  11. 检测片段的级别,这意味着如果您想要片段“B”替换现有片段“A”,并且当您想在按回“B”时返回显示片段“A”时,请将该事务放在后面堆。

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


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