解决android中HorizontalScrollView的滚动事件与组件的Touch冲突问题

本文介绍如何解决Android应用中组件的Touch事件与滚动事件的冲突问题。通过自定义HorizontalScrollView并重写onInterceptTouchEvent方法,配合标志位来判断是否允许拦截Touch事件,从而确保滑动操作正常工作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 


在上一章中我们实现了抽屉+滚动功能,但是遗留了一个问题就是滚动事件与组件的Touch事件冲突,接下来我们看一下他们冲突的原因

public boolean onInterceptTouchEvent (MotionEvent ev)

使用此方法可以拦截所有触摸屏动作引发的事件。这意味着你可以监视分派给子项的事件,并且可以拿到任何当前手势的所有权。

使用此方法需谨慎。因为它与View.onTouchEvent(MotionEvent)有相当复杂的交互影响。这两者都必须同时正确地实现。事件将按以下顺序来被方法接收:

   1. 接收到down事件

   2. 事件将被视图组的一个子视图处理,或者被传递给自己的onTouchEvent()方法处理;这意味着你必须实现onTouchEvent(),并且返回true,这样才可以接着接受到其他的手势(而不是寻求一个父视图来处理它)。onTouchEvent()返回true后,你将不再接受到onInterceptTouchEvent()的任何事件,同时所有对触摸动作的处理必须像往常一样在onTouchEvent()中进行。

   3. 如果返回false,则接下来的每个事件(所有的up事件,包含最后一个up)将会首先被传递到这里,然后到目标对象view的onTouchEvent()。

   4. 如果返回ture,你将不会接收到以下任何事件:目标view将会接收到相同的事件,但是带着ACTION_CANCEL的动作。所有在此之后的事件将会被传递到你的onTouchEvent()方法中,并且不再在这里出现。

参数

ev    沿着树型结构往下分派的动作事件

         返回值

             若将动作事件从子视图中截获并通过onTouchEvent()将他们分派给当前ViewGroup,则返回true。当前目标将收到一个ACTION_CANCEL事件,并且不再会有其他消息被传递到这里。

 

onInterceptTouchEvent 这个功能只有在布局中才会有的,如上面所述,所以我们解决这个问题,就要实现当我们实现组件的Touch事件的时候,需要onInterceptTouchEvent 返回false,否则组件无法捕获Touch事件,知道原理以后,我们就可以编写代码,我们使用一个标志位来标准HorizontalScrollView的子View是否正在实现Touch事件,如果有则设置flag = 0;当Touch_up的时候,设置flag = -1,而在HorizontalScrollView的onInterceptTouchEvent 函数中判断flag是否等于-1,如果flag == -1,则onInterceptTouchEvent 返回return super.onInterceptTouchEvent(ev);,否则返回false。下面我们使用代码来实现:

布局文件需要重新编写:

<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"
    tools:context=".MainActivity" >

    <SlidingDrawer
        android:id="@+id/slidingDrawer1"
        android:layout_width="wrap_content"
        android:layout_height="80dp"
		android:layout_alignParentBottom="true"
        android:content="@+id/content"
        android:handle="@+id/handle" >

        <Button
            android:id="@+id/handle"
            android:layout_width="wrap_content"
            android:layout_height="20dp"
            android:text="Handle" />

        <com.example.test.Horizon
            android:id="@+id/content"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:background="@android:color/black"
            android:scrollbars="none" >

            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="50dp"
                android:layout_gravity="center_vertical"
                android:gravity="center_vertical"
                android:id="@+id/content_linear"
                android:orientation="horizontal" >

                <Button
                    android:layout_width="70dp"
                    android:layout_height="50dp"
                    android:layout_marginLeft="10dp"
                    android:id="@+id/btn1"
                    android:text="btn1" >
                </Button>

                <Button
                    android:layout_width="70dp"
                    android:layout_height="50dp"
                    android:layout_marginLeft="10dp"
                    android:text="btn2" >
                </Button>

                <Button
                    android:layout_width="70dp"
                    android:layout_height="50dp"
                    android:layout_marginLeft="10dp"
                    android:text="btn3" >
                </Button>

                <Button
                    android:layout_width="70dp"
                    android:layout_height="50dp"
                    android:layout_marginLeft="10dp"
                    android:text="btn4" >
                </Button>

                <Button
                    android:layout_width="70dp"
                    android:layout_height="50dp"
                    android:layout_marginLeft="10dp"
                    android:text="btn5" >
                </Button>

                <Button
                    android:layout_width="70dp"
                    android:layout_height="50dp"
                    android:layout_marginLeft="10dp"
                    android:text="btn5" >
                </Button>

                <Button
                    android:layout_width="70dp"
                    android:layout_height="50dp"
                    android:layout_marginLeft="10dp"
                    android:text="btn5" >
                </Button>

                <Button
                    android:layout_width="70dp"
                    android:layout_height="50dp"
                    android:layout_marginLeft="10dp"
                    android:text="btn5" >
                </Button>

                <Button
                    android:layout_width="70dp"
                    android:layout_height="50dp"
                    android:layout_marginLeft="10dp"
                    android:text="btn5" >
                </Button>
            </LinearLayout>
        </com.example.test.Horizon>
    </SlidingDrawer>

</RelativeLayout>


与上面上一章中的布局文件不同的地方就是用com.example.test.Horizon替换HorizontalScrollView,下面就是Horizon类的内容:

Horizon.java

 

package com.example.test;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.HorizontalScrollView;

public class Horizon extends HorizontalScrollView{

	public Horizon(Context context) {
		super(context);
	}
	
	public Horizon(Context context, AttributeSet attrs) {
		super(context, attrs);
	}


	@Override
	public boolean onInterceptTouchEvent(MotionEvent ev) {
		if (MainActivity.flag == -1) {
			return super.onInterceptTouchEvent(ev);
		}else{
			return false;
		}
	}

}


主类的内容如下:

package com.example.test;

import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.Button;

public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		btn1 = (Button)findViewById(R.id.btn1);
		btn1.setOnTouchListener(new OnTouchListener() {
			@Override
			public boolean onTouch(View v, MotionEvent event) {
				switch (event.getAction()) {
				case MotionEvent.ACTION_DOWN:
					flag = 0;
					Log.e("test", "down");
					break;
				case MotionEvent.ACTION_MOVE:
					Log.e("test", "move");
					break;
				case MotionEvent.ACTION_UP:
					flag = -1;
					Log.e("test", "up");
					break;
				}
				return false;
			}
		});
	
	}

	public Button btn1;
	public static int flag = -1;
}


测试结果如下:

07-06 21:49:04.639: E/test(409): down
07-06 21:49:04.659: E/test(409): move
07-06 21:49:04.669: E/test(409): move
07-06 21:49:04.679: E/test(409): move
07-06 21:49:04.699: E/test(409): move
07-06 21:49:04.709: E/test(409): move
07-06 21:49:04.719: E/test(409): move
07-06 21:49:04.739: E/test(409): move
07-06 21:49:04.749: E/test(409): move
07-06 21:49:04.769: E/test(409): move
07-06 21:49:04.769: E/test(409): up


上面组件btn1实现了Touch事件同时移动,但是能够测试到up事件,不过你移动组件的时候,是不能移动滚动条

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值