扩展 ViewPager 的触摸区域

Expanding the touch area of a ViewPager

我的应用程序使用以下 ViewPager

ViewPager与显示器宽度相同

我在 xml 中为 ViewPager 添加了边距,这样我就可以看到左(蓝色)和右(灰色)页面。 结果一切正常,但我只能触摸绿色区域来移动页面。

我想将触摸区域扩大到整个屏幕,这样我就可以触摸任何地方来移动ViewPager

我尝试添加一个 TouchDelegate:

binding.pagerContainer.post {
        val rect = Rect()  
        binding.touchArea.getHitRect(rect)
        binding.pagerContainer.touchDelegate = TouchDelegate(rect, binding.viewPager)
    }

并且在 xml:

 <FrameLayout
        android:id="@+id/pager_container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:clipChildren="false">

        <android.support.v4.view.ViewPager
            android:id="@+id/viewPager"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_gravity="center"
            android:layout_marginBottom="150dp"
            android:layout_marginLeft="70dp"
            android:layout_marginRight="70dp"
            android:layout_marginTop="150dp"
            android:clipChildren="false"/>

        <View
            android:id="@+id/touchArea"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:alpha="0">
        </View>
    </FrameLayout>

Rect 的大小正确。 我正在发布一个 Runnable 以确保视图的布局。 我阅读了 TouchDelegate.

的文档

我不知道为什么它不起作用。

在 yourlayout.xml 中添加此行:

android:clickable="true"
android:focusable="true"
android:focusableInTouchMode="true"

试试这个块:

YOURActivityLayout.setOnTouchListener(new View.OnTouchListener() {  
        @Override
        public boolean onTouch(View arg0, MotionEvent arg1) {

            return true;//always return true 
        }
    });

希望这会奏效

好的。我想这次我得到了。经过一些研究 here and here,我得出了这个答案。我没有尝试使用 TouchDelegate 扩展 ViewPager 的区域,而是将触摸事件从 FrameLayout 重新路由到 ViewPager。 1、制作你自己的 FrameLayout

public class MyFrameLayout extends FrameLayout {

    // make sure to include all the necessary constructors here
    // with calls to super

    // only need to override 1 method
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        ViewPager pager = null;
        int count = getChildCount();
        for(int i=0; i<count; i++) {
            if(getChildAt(i) instanceof ViewPager) {
                pager = (ViewPager)getChildAt(i);
                break;
            }
        }
        if(pager != null) {
            return pager.onTouchEvent(event);
        }
        return super.onTouchEvent(event);
    }
}

如果你知道 ViewPager 总是在 FrameLayout 中的同一个地方,那么 onTouchEvent() 可以简化为

    ViewPager pager = (ViewPager)getChildAt(0); 
    return pager.onTouchEvent(event);

然后你在布局文件中使用自定义的FrameLayout

 <your.package.name.MyFrameLayout
    android:id="@+id/pager_container"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    etc. etc.

我已经测试过了,这个适合我。希望对你有用。

我的 viewpager 背后有一个视图作为背景。我注意到发送到 viewpager 中活动项目左侧和右侧的非活动项目的触摸事件被发送到背景视图。这给了我拦截那里的触摸并使用 viewpager 的假拖动的想法 api.

我像这样为 ViewPager2 构建了一个扩展函数:

fun ViewPager2.receiveFakeDragsFrom(view: View) {
    view.setOnTouchListener { _, event ->
        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                requestDisallowInterceptTouchEvent(true)
                beginFakeDrag()
                true
            }
            MotionEvent.ACTION_MOVE -> {
                if (event.historySize > 0) {
                    fakeDragBy(
                        event.x - event.getHistoricalX(0)
                    )
                }
                true
            }
            MotionEvent.ACTION_UP -> {
                endFakeDrag()
                requestDisallowInterceptTouchEvent(false)
                performClick()
                true
            }
            else -> {
                false
            }
        }
    }
}

然后在我的片段中设置 viewpager 时,我只是用背景视图作为参数调用了该函数:

myViewPager.receiveFakeDragsFrom(vpBackgroundView)