截取包含可滚动窗口小部件(scrollview,listview等)的片段上的手势

时间:2014-05-28 21:36:03

标签: android android-fragments android-listview fragment gesture

我在处理有关手势识别的应用程序的一部分时出现问题,这种应用程序已经让我疯了几个小时了...

我有一个活动,其中包含两个填充整个屏幕的FrameLayouts,一个包含应用程序的主要内容,另一个包含聊天记录。一次只能设置一个。我的想法是,我可以直接在主要内容片段上滑动,聊天片段将在Facebook样式界面中显示。再次,在聊天片段上向左滑动将使主要内容片段重新进入视图。

滑动侦听器的代码:

 private void attachFragmentSwipeListeners() {
        int screenOrientation = getResources().getConfiguration().orientation;
        if (screenOrientation == Configuration.ORIENTATION_PORTRAIT) {
            FrameLayout mainContent = (FrameLayout) findViewById(R.id.flMainContent);
            mainContent.setOnTouchListener(new OnSwipeTouchListener(ExICS_Main.this) {
                @Override
                public void onSwipeLeft() {
                    showChatLog();
                    super.onSwipeLeft();
                }
            });

        FrameLayout chatWindow = (FrameLayout) findViewById(R.id.flChatWindow);
        chatWindow.setOnTouchListener(new OnSwipeTouchListener(ExICS_Main.this) {
            @Override
            public void onSwipeRight() {
                hideChatLog();
                super.onSwipeRight();
            }
        });
    }
}

听众本身:

public class OnSwipeTouchListener implements View.OnTouchListener {
    private static final String TAG = OnSwipeTouchListener.class.getName();
    private final GestureDetector gestureDetector;

    public OnSwipeTouchListener(Context context) {
        gestureDetector = new GestureDetector(context, new GestureListener());
    }

    public void onSwipeLeft() {
    }

    public void onSwipeRight() {
    }

    public boolean onTouch(View v, MotionEvent event) {
        return gestureDetector.onTouchEvent(event);
    }

    private final class GestureListener extends GestureDetector.SimpleOnGestureListener {
        private static final int SWIPE_DISTANCE_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) {
            Log.i(TAG, "OnSwipeTouchListener Fling");
            float distanceX = e2.getX() - e1.getX();
            float distanceY = e2.getY() - e1.getY();
            if (Math.abs(distanceX) > Math.abs(distanceY) && Math.abs(distanceX) > SWIPE_DISTANCE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
                if (distanceX > 0) onSwipeRight();
                else onSwipeLeft();
                return true;
            }
            return false;
        }
    }
}

这已经过测试,并且在使用两个仅包含textviews等的占位符片段时可以正常工作。我遇到的问题是片段包含交互式小部件,例如scrollview或listview。

在这些情况下,使用小部件使得它们只能以垂直方式滚动,但是,它们正在消耗拖曳交互,甚至是水平交互,这样在应用程序中的片段级别上监听的GestureDetectors永远不会被触发

我想要做的是在片段上进行滑动时,让片段上的gesturedetector决定它的水平滑动是否足以触发主内容和聊天之间的切换,反之亦然,如果是,则调用show / hideChatLog()在活动级别。如果没有,将TouchEvent传播回片段的子视图,无论它是什么,所以它可以按照自己的意愿进行。

或者,覆盖窗口小部件本身的gesturedetection,如果片段手势监听器正在侦听的水平滑动,则将其推回到视图层次结构而不消耗它,以便片段手势检测器将看到并因此对其进行操作

我尝试创建一个新的手势监听器,它按如下方式实现onFling方法,并将其附加到ListView或ScrollView等。

public class IgnoreHorizontalSwipeInterceptor implements View.OnTouchListener {
    private static final String TAG = IgnoreHorizontalSwipeInterceptor.class.getName();
    private final GestureDetector gestureDetector;

    public IgnoreHorizontalSwipeInterceptor(Context context) {
        gestureDetector = new GestureDetector(context, new GestureListener());
    }

    public void onSwipeLeft() {
    }

    public void onSwipeRight() {
    }

    public boolean onTouch(View v, MotionEvent event) {
        return gestureDetector.onTouchEvent(event);
    }

    private final class GestureListener extends GestureDetector.SimpleOnGestureListener {
        private static final int SWIPE_DISTANCE_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) {
            Log.i(TAG, "OnSwipeTouchListener Fling");
            float distanceX = e2.getX() - e1.getX();
            float distanceY = e2.getY() - e1.getY();
            if (Math.abs(distanceX) > Math.abs(distanceY) && Math.abs(distanceX) > SWIPE_DISTANCE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
                return false;
            }
            return false;
        }
    }
}

并将其附加如下:

public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    View fragmentView = inflater.inflate(R.layout.fragment_room_list, container, false);
    ListView roomListView = (ListView) fragmentView.findViewById(R.id.lvRoomList);
    ...
    RoomListFragmentListAdapter adapter = new RoomListFragmentListAdapter(getActivity(), R.layout.room_list_item_layout, rooms);
    roomListView.setAdapter(adapter);
    roomListView.setOnTouchListener(new IgnoreHorizontalSwipeInterceptor(getActivity().getBaseContext()));
    return fragmentView;
}

我原本希望总是在附加到listView的IgnoreHorizo​​ntalSwipeInterceptor中的onFling()中返回false,它会导致事件返回到父级,片段本身,但这不会发生。

当我在列表视图上滑动时,我可以在IgnoreHorizo​​ntalSwipeInterceptor onFling()的日志OnSwipeTouchListener Fling中看到。如果我对不包含可滚动小部件的片段执行相同操作,我可以同样看到OnSwipeTouchListener Fling,我希望如此。

我找到了Android documentation for gestures on viewgroups,但这对我来说真的没有多大意义......它提到了onInterceptTouchEvent,但我无法弄清楚这样做或者如何才有意义。如果这确实是正确的方法,那么在哪里以及如何做到这一点的某些方向将是值得赞赏的。

另一种(可能更容易)方法是实现一个接口,这样当片段小部件检测到自身的水平滑动时,它会使用对父活动的回调来触发我期望的动作,show / hideChatLog()。然而,这似乎是一种相当肮脏的方式,如果可能的话,宁可避免。

显示我对布局的意思;

在内容视图中使用此片段,向右滑动以显示聊天记录按预期工作:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/holo_blue_bright"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="XXXX.Activities.ExICS_Main$PlaceholderFragment">

    <TextView
        android:id="@+id/section_label"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="This is a fragment" />

</RelativeLayout>

但是这个并不是因为listview正在使用触摸事件并且它没有被传递给片段onTouchEvent GestureListener:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="XXX.Fragments.Room_List_Fragment">

    <ListView
        android:id="@+id/lvRoomList"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" />

</LinearLayout>

0 个答案:

没有答案