android传递在视图剪辑边界之外绘制的子视图的触摸事件(ViewPager第1页到第2页)

时间:2015-01-01 02:53:22

标签: android android-viewpager

我的Android ViewPager设置为在边界之外绘制视图(剪辑边界设置为false)。我在页面上显示的所有视图上都有一个触摸事件监听器。自定义视图显示在页面1上,在其剪切边界之外绘制并溢出到页面2.页面1上的触摸事件正常工作。滚动到第二页时,将显示剩余视图。问题是单击第2页时,自定义视图上的触摸事件(在页面1上添加)不会被调用。

PageViewActivity.cs

ViewPager mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setClipChildren(false);
mViewPager.setClipToPadding(false);

PageViewFragment.cs

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.page_layout, container, false);
    setHasOptionsMenu(true);

    View view1=(View)v.findViewById(R.id.view1);
    view1.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {

        Toast.makeText(getActivity(), "View clicked",Toast.LENGTH_SHORT).show();    
        }
    });return v;    

}

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 
android:layout_width="match_parent" 
android:layout_height="match_parent" 
android:clipChildren="false" 
android:clipToPadding="false" >
<View
    android:id="@+id/view1"
    android:layout_width="200dp"
    android:layout_height="200dp"
    android:layout_marginLeft="250dp"
    android:layout_marginTop="20dp"
    android:background="#ff0000" />

片段布局 - page_layout.xml

有什么建议吗?

2 个答案:

答案 0 :(得分:0)

这里有一个问题。我们只能刷中间视图。这是因为触摸事件发生在ViewPagers边界之外。我们可以覆盖ViewPagerContainer的onTouchEvent并将事件分派给ViewPager来解决这个问题。

private ViewPager mPager;

@Override
protected void onFinishInflate() {
    mPager = (ViewPager) getChildAt(0);
}

@Override
public boolean onTouchEvent(MotionEvent ev) {
    return mPager.dispatchTouchEvent(ev);
}

但事实是,你最好使用更现代的解决方案。

<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/main_content"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/appbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

        <android.support.design.widget.TabLayout
            android:id="@+id/result_tabs"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/grey"
            app:tabIndicatorColor="@color/colorPrimary"
            app:tabMode="scrollable"
            app:tabSelectedTextColor="@color/colorPrimary"
            app:tabTextColor="@color/medium_grey" />
    </android.support.design.widget.AppBarLayout>

    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />

</android.support.design.widget.CoordinatorLayout>

标签布局和正确设置的viewpager。虽然谷歌在他们的架构组件中完成导航位后,即使这样也会过时了。

答案 1 :(得分:0)

您必须手动检测触摸事件,并查看其坐标是否位于边界外的页面范围内。因此,在将触摸事件发送到寻呼机之前,要了解Tatarize所说的内容,您应该检查事件是否在视图寻呼机的其中一个页面中。

这是示例代码,我只检查x是否位于边界内而不是childContains()中的y。

@Override
public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_MOVE:
                return pager.dispatchTouchEvent(event);
            case MotionEvent.ACTION_UP:
                int childCount = pager.getChildCount();
                int x = (int) event.getX();
                int y = (int) event.getY();
                for (int i = 0; i < childCount; i++) {
                    final View child = pager.getChildAt(i);
                    if (childContains(child, x)) {
                        // delay the click minimally in-case
                        // callOnClick performs mods on the pager
                        // 
                        new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
                            @Override
                            public void run() {
                                child.callOnClick();
                            }
                        }, 100);
                        return true;
                    }
                }
                break;
        }

        return pager.dispatchTouchEvent(event);
    }

int[] loc = new int[2];
private boolean childContains(View child, final int x) {
        child.getLocationOnScreen(loc);
        int x1_child = loc[0];
        int x2_child = x1_child + child.getWidth();
        int x0 = x;
        boolean isInside = x0 >= x1_child && x0 < x2_child;

        Log.v("childContains()", String.format("x: %s x1_child: %s x2_child: %s isInside: %s",
                x0, x1_child, x2_child, String.valueOf(isInside)));
        return isInside;
    }