在片段级别与ViewPager一起应用了“滑动手势",但禁用了默认滑动 [英] Swipe Gesture applied at Fragment level along with ViewPager with its default swipe disabled

查看:113
本文介绍了在片段级别与ViewPager一起应用了“滑动手势",但禁用了默认滑动的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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:

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

  1. 使用onTouchEvent和使用自定义ViewPager的onInterceptTouchEvent禁用默认滑动.
  2. 声明的FragmentStatePagerAdapter带有片段列表,每个片段显示在每个选项卡中.
  3. 在main_activity的main_layout中声明片段,该片段与ViewViewr并排放置. 想法是在单击ViewPager_fragment上的按钮时以及用户按下回车键时显示activity_fragments 按钮,然后使用添加时的向后堆栈事务再次显示默认ViewPager_fragment,并在活动的BackPressed上将其弹出.因此,我还维护了自定义的后堆栈,以在后堆栈弹出事务时显示/隐藏activity_fragments.
  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.

为此,我使用了GestureListener和SimpleOnGestureListener以及活动的OnTouchEvent.

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

我面临的问题是:

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

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. 在片段"区域中,该区域的布局具有多个视图.
  2. 仅在左右方向上.
  3. 只有从activity_fragment到ViewPager的选项卡片段,其行为才类似于onBakPressed/onKeyDown中的历史记录导航 使用后堆栈弹出窗口和我的自定义后堆栈实现.
  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>

它对我没有多大帮助,所以应该对您有所帮助.在其中一个片段中有一个searchView停止工作,并且没有单击起作用. 如果您能达到我想要的目标,请在这方面提供帮助.

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.

更新1: 在onTouchEvent和onInterceptTouchEvent中都返回true具有所需的效果,但是它会阻止SearchView所在的片段中的单击,在可单击的视图中没有单击起作用.仅划动有效.更新:在我的最新文章中:我也完全放弃了使用事务后退堆栈,因为我依赖于我自定义的后退堆栈,其中我维护所有选项卡的导航历史记录.我确实使用ViewPager和FragmentStatePagerAdapter给出的setCurrentTab和onTabSelected方法.

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.

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

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

更新3:

  1. 在我的活动布局中,有一个视图寻呼机,在其下方的每个框架布局中,都有一个片段.

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

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

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

单击此片段上的按钮时,将显示视图分页器下面的帧布局中的一个片段,并将其添加到我的自定义后退堆栈中.

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.

按下返回键时,此片段再次被隐藏以在视图寻呼机中显示选项卡片段.以上所有步骤均已完成.只有我想要从左到右的滑动手势才能工作,我发现可以通过拦截触摸事件来做到这一点. 但这根本不做.当我返回true时, 只有滑动手势有效,否则,此操作将被取消, 点击此片段即可.

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.

推荐答案

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

Check which events needs to be intercepted and which are to be passed to the child views: http://developer.android.com/training/gestures/viewgroup.html

与其在框架布局中使用我的滑动手势监听器 附有哪些片段, 现在我在相对布局上使用它,这是 碎片.

Instead of using my swipe gesture listener in frame-layout on which fragments are attached, now I am using it on the relative-layouts which are the root-views of the fragments.

@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;
    }

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

Here are some tips that I follow now while using fragments in my activities:

[注意:如果您使用的是FragmentStatePagerAdapter,则可以按照您所处的方式,用片段的列表中特定索引处的片段替换另一个片段,该片段列表将用作此适配器的数据.相同的标签,但其内容被更改而不更改标签.然后使用notifyDataSetChanged().在这里,您不使用事务,但是您可以使用].

[Note: In case you are using FragmentStatePagerAdapter, you can play with replacing a fragment with another fragment at a particular index in the list of fragment that you are using as a data for this adapter, in a way that you are in the same tab but its content is changed without changing the tab. Then use notifyDataSetChanged(). Here you do not use transactions, but otherwise you do].

  1. 使用Fragment.instantiate()初始化片段,而不是初始化 构造函数.
  2. 使用侦听器更新/删除实例的引用 (来自用于引用它们的集合)片段onCreateView和onDestroy.
  3. 使用getView()获取片段的根视图,无论何时何地以及在更新时 功能.
  4. 请勿跟踪实例,实际上应尽可能避免使用静态指针.
  5. 使用getSupportFragment而不是保留FragmentManager的引用 在View寻呼机适配器中或其他位置.
  6. 在事务隐藏视图上使用附加分隔符,以摆脱上的子视图 片段的根视图并重新初始化. 这是因为一次只需要一个片段可见,而另一个则需要分离. 因此,按需重新连接.
  7. getActivity()或getApplicationContext()适用,而不是保留 一个全局变量以保留对上下文的引用.
  8. onConfiguration更改(方向,键盘,调整大小):在活动中进行并传递 到管理它的活动片段. 重要说明:如果确实要使用片段进行事务处理,请不要在布局中声明它们. 在添加片段事务中提供容器(布局)ID.
  9. 片段事务应在事件调用中完成,而不是在其他任何地方进行, 并且此类事件不应重复.这样可以防止非法参数异常.
  10. 有一个ViewPager方法,您不必使用Fragments.相反, 您可以使用视图"或视图组".这将取代片段的嵌套.
  11. 检测片段的级别,这意味着如果您希望片段'B'替换现有的片段'A',并且当您想返回显示片段'A'并按回'B'时,请输入事务在后堆栈中.
  1. Use Fragment.instantiate() to initialize your fragments instead of constructor.
  2. Use listeners to update/delete the reference of instance (from the collection used to refer them) of fragment onCreateView and onDestroy.
  3. Use getView() to get the root view of fragment every where and on update functionality.
  4. Do not keep track of instances, infact avoid static pointers where ever possible.
  5. Use getSupportFragment instead of keeping reference of FragmentManager in view pager adapter or elsewhere.
  6. Use attach detatch on transaction hide view, to get rid of child views on Fragment's root view and re initialize. This is because only one fragment needs to be visible at a time, the others need to detach. Therefore re-attach on demand.
  7. getActivity() or getApplicationContext() whatever applicable, instead of keeping a global variable to keep references to context.
  8. onConfiguration change (orientation, keyboard, resize): do in activity and pass it to active fragment which manages it. Important: If you do want to use fragments for transactions, do not declare them in layouts. Provide container (layout) id in add fragment transaction.
  9. A Fragment transaction should be done in an event call, not anywhere else, and such an event should not be repetitive. This prevents Illegal Argument Exception.
  10. There is a ViewPager method where you do not have to use Fragments.Instead, you can use Views, or ViewGroups. This replaces the nesting of fragments.
  11. Detect the level of fragments, that means if you want a fragment 'B' to replace existing fragment 'A', and when you want to go back to show fragment 'A' when pressing back on 'B', put that transaction in back stack.


提示:添加滑动功能时要小心,因为还有其他可单击的视图. 在RootView上使用拦截触摸轻扫,返回假但分析触摸.


Tip : Carefull while adding swipe feature because there are other clickable views. Swipe with intercept touch on RootView returning false but analysing touches.

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

One more thing: you should observe that having one fragment in one container at a time resolves another issue: If there are two fragments , one on the top of the other, the clicks from one fragment goes to the other fragment that is beneath. So hide or replace to have just one fragment at a time. Back-Stack helps in maintaining the navigation levels, and on configuration change or update, try to update the same instance of the target active fragment, instead of doing transactions because that changes the order of fragments navigated.

这篇关于在片段级别与ViewPager一起应用了“滑动手势",但禁用了默认滑动的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆