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

时间:2013-09-16 06:40:40

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

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

详细信息:https://moqups.com/abhsax130778@gmail.com/lc0ZOERO/p:a5d7b55eb

  1. 使用onTouchEvent和使用自定义ViewPager的onInterceptTouchEvent禁用默认滑动。
  2. 声明FragmentStatePagerAdapter提供了一个片段列表,每个片段都显示在每个选项卡中。
  3. 在main_activity的main_layout中声明片段,其中包含此ViewPager。 想法是在单击ViewPager_fragment上的按钮时以及用户按下时返回时显示activity_fragments 按钮,然后使用添加后回栈事务再次显示默认的ViewPager_fragment,并在BackPressed上弹出它们 活动。因此,我也在维护我的自定义backStack,以便在后端堆栈时显示/隐藏activity_fragments 弹出交易。
  4. 现在我想要实现的是使用滑动手势进行上面的第三点,仅用于从右向左滑动。

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

    我面临的问题是:

    此动作适用于活动屏幕的位于片段下方和活动部分的部分。 我想要手势

    1. 在片段区域中,其布局中有多个视图。
    2. 仅在左右方向。
    3. 仅从activity_fragment到ViewPager的标签片段,表现得像onBakPressed / onKeyDown中的历史导航一样 使用后台堆栈弹出窗口和我的自定义后台堆栈实现。
    4. 我尝试了以下类,并在这样的布局中更改了我的活动片段。

      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() {
              }
          }
      

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

      <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>
      

      它帮助我很少,所以它应该帮助你找到解决方案。其中一个片段中的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并将其添加到我的自定义backstack中。

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

1 个答案:

答案 0 :(得分: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;
    }

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

有效管理片段的交易:

[注意:如果您正在使用FragmentStatePagerAdapter,您可以使用您所使用的方式将片段替换为您用作此适配器数据的片段列表中特定索引处的另一个片段。相同的选项卡,但其内容更改而不更改选项卡。然后使用notifyDataSetChanged()。在这里你不使用交易,但你不这样做。

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

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


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