【问题标题】:android Passing touch events of a Child view drawn outside of view clip bounds (ViewPager Page 1 to Page 2)android传递在视图剪辑边界之外绘制的子视图的触摸事件(ViewPager第1页到第2页)
【发布时间】:2018-06-20 13:07:29
【问题描述】:

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

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

有什么建议吗?

【问题讨论】:

  • 显示代码的相关部分。
  • @PM77-1 添加了代码。 @+id/view1 显示在第 1 页和第 2 页上。点击事件在页面 1 上起作用,而不是在 page2 上。

标签: android android-viewpager


【解决方案1】:

您必须手动检测触摸事件,并查看它的坐标是否位于边界之外的页面边界内。因此,脱离 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;
    }

【讨论】:

    【解决方案2】:

    这里有问题。我们只能滑动中间视图。这是因为触摸事件发生在 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。尽管一旦 Google 在其架构组件中完成导航位,即使这也将有些过时。

    【讨论】:

    • 好的,删除它。现在大多数答案都是垃圾。大多数情况下,您可以现代地适当地拥有填充屏幕并捕获触摸事件的查看器,而无需从父容器委派它们,但足以说明上述不起作用的原因是因为它没有获得触摸事件因为它没有被触摸,因为它的大小和位置不是发生触摸事件的地方。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-09-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多