7

I found the question below: Android: FragmentActivity inside FragmentActivity (ScrollView in NavigationBar) . However, this question of mine is about how to use Transactions to show fragments as well as enabling swipe gesture detection in a safe way. Note: There is a link in the answer that I have posted (This also has an effective way of showing fragments in a container using transactions, including two scenarios). Please see that. I have tried a few things in regards, but by using a fragment supporting ViewPager, not nested:

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

  1. Disabled default swipe using onTouchEvent and onInterceptTouchEvent using custom ViewPager.
  2. Declared FragmentStatePagerAdapter provided with a list of fragments, each of which is displayed in each tab.
  3. Declare Fragments in the main_layout of the main_activity which has this ViewPager alongside. Idea is to show the activity_fragments when a button on a ViewPager_fragment is clicked and when the user presses the return button, then the default ViewPager_fragment is shown again using the back stack transactions on add and popping them on BackPressed of the activity. I am therefore also maintaining my custom back-stack to show/hide the activity_fragments when the back stack pops a transaction.

Now what I want to achieve is to do the third point above using swipe-gestures for the right [left to right] swipes only.

I have used GestureListener and SimpleOnGestureListener and activity's OnTouchEvent for this.

The problem that I face is:

This gesture works on the portion of the activity screen which is below the fragment and the portion of the activity. I want the gesture work

  1. On the Fragment area which has multiple views in its layout.
  2. In only the left-right direction.
  3. Only from activity_fragment to ViewPager's tab fragment to behave like history navigation as already done in onBakPressed/onKeyDown implementation using back stack popups and my custom back stack.

I tried the following class and change in my activity fragment in layouts like this.

My Gesture and Touch listener extended with frame layout:

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

and then change frame layouts to this class reference:

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

It helped me little, so should it help you in finding solution. There is a searchView in one of the fragments that stopped working, and no click works. If you get it what I want to achieve, please help in this regards.

Update 1: Returning true in both onTouchEvent and onInterceptTouchEvent has the desired effect, but it blocks the clicks in fragments where SearchView is there, no clicks work in the clickable views present. Only the swipe is working. Update: In my latest: I have also discarded the use of transaction-back-stacks completely because I rely on my custom back-stack where I maintain the navigation history for all the tabs. This I do using setCurrentTab and onTabSelected methods given by ViewPager and FragmentStatePagerAdapter.

Update 2: This one is difficult to implement: Check which events need to be intercepted and which are to be passed to the child views: http://developer.android.com/training/gestures/viewgroup.html

Update 3:

  1. In my layout for activity, there is a view pager, and in each frame layouts below it, there is one fragment.

  2. When you start the app, the ViewPager shows the fragment in the first tab.

  3. When a button on this fragment is clicked, one of the fragments in the frame layouts below view pager is shown and added to my custom back stack.

  4. When the return key is pressed, this fragment is hidden again to show the tab fragment in the view pager. Every of the above is done. Only I want the swipe gesture for the left to right to work, and I found that I can do it by intercepting touch events. But it does not do that at all When I return true, only the swipe gesture works, otherwise, this action is canceled and the clicks on this fragment work.

4

1 回答 1

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. 在事务隐藏视图上使用附加分离,以摆脱 Fragment 根视图上的子视图并重新初始化。这是因为一次只需要一个片段可见,其他片段需要分离。因此,按需重新连接。
  7. getActivity() 或 getApplicationContext() 任何适用的,而不是保留一个全局变量来保留对上下文的引用。
  8. onConfiguration 更改(方向、键盘、调整大小):在活动中执行并将其传递给管理它的活动片段。重要提示:如果您确实想将片段用于事务,请不要在布局中声明它们。在添加片段事务中提供容器(布局)ID。
  9. 片段事务应该在事件调用中完成,而不是其他任何地方,并且这样的事件不应该是重复的。这可以防止非法参数异常。
  10. 有一种 ViewPager 方法,您不必使用 Fragments。相反,您可以使用 Views 或 ViewGroups。这取代了片段的嵌套。
  11. 检测片段的级别,这意味着如果您希望片段“B”替换现有片段“A”,并且当您想要返回显示片段“A”时按下“B”,则将该事务放在后面堆。

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


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

于 2014-03-13T07:29:54.620 回答