Android View、ViewGroup 事件分发机制(二)

本文通过自定义ViewGroup并分析其事件传递机制,详细解释了onInterceptTouchEvent方法的作用及其实现原理。通过实例展示了不同返回值的影响。

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

前一篇文章中已经讲述了关于View的事件传递机制,这篇文章主要介绍一下ViewGroup的事件传递机制,ViewGroup的事件传递是基于View的,有兴趣可以看一下《Android View、ViewGroup事件分发机制(一)》

1. 首先我们来自定义一个ViewGroup,继承自LinearLayout,重写它的onInterceptTouchEvent方法

public class MyLayout extends LinearLayout {
	public MyLayout(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	@Override
	public boolean onInterceptTouchEvent(MotionEvent ev) {
		// 默认返回false
		//return true;
		return super.onInterceptTouchEvent(ev);
	}
}

2. 然后我们在布局文件中引用MyLayout,添加两个Button

<com.viewgroup.MyLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/my_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <Button
        android:id="@+id/button1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Button1" />

    <Button
        android:id="@+id/button2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Button2" />

</com.viewgroup.MyLayout>

3.在MainActivity中使用2中的布局,并且添加根布局的触摸事件和两个Button的点击事件

public class MainActivity extends Activity {
	protected static final String TAG = MainActivity.class.getSimpleName();

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		
		MyLayout myLayout = (MyLayout) findViewById(R.id.my_layout);
		Button button1 = (Button) findViewById(R.id.button1);
		Button button2 = (Button) findViewById(R.id.button2);

		myLayout.setOnTouchListener(new OnTouchListener() {
			@Override
			public boolean onTouch(View v, MotionEvent event) {
				Log.d(TAG, "myLayout on touch");
				return false;
			}
		});

		button1.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				Log.d(TAG, "You clicked button1");
			}
		});

		button2.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				Log.d(TAG, "You clicked button2");
			}
		});
	}
}

4.我们分别点击Button1,Button2和其他空白地方,Log如下


5.我们将MyLayout.java中的onInterceptTouchEvent返回true,重新运行后Log如下


为什么会产生这种效果呢,我们知道它跟onInterceptTouchEvent方法的返回值有关系。流程如下图所示:


接下来,我们去查看一下ViewGroup的dispatchTouchEvent方法的伪源码(来自Android2.3源码)

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (!onFilterTouchEventForSecurity(ev)) {
            return false;
        }

        boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;

        if (action == MotionEvent.ACTION_DOWN) {
            if (mMotionTarget != null) {
                mMotionTarget = null;
            }
		//如果onInterceptTouchEvent方法返回false,进入if内部
            if (disallowIntercept || !onInterceptTouchEvent(ev)) {
                ev.setAction(MotionEvent.ACTION_DOWN);
                final int scrolledXInt = (int) scrolledXFloat;
                final int scrolledYInt = (int) scrolledYFloat;
                final View[] children = mChildren;
                final int count = mChildrenCount;
		// 遍历所以子View,找到被点击的View
                for (int i = count - 1; i >= 0; i--) {
                    final View child = children[i];
                    if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE
                            || child.getAnimation() != null) {
                        child.getHitRect(frame);
                        if (frame.contains(scrolledXInt, scrolledYInt)) {
                            // offset the event to the view's coordinate system
                            final float xc = scrolledXFloat - child.mLeft;
                            final float yc = scrolledYFloat - child.mTop;
                            ev.setLocation(xc, yc);
                            child.mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;
			// 调用子View的dispatchTouchEvent方法
                            if (child.dispatchTouchEvent(ev))  {
                                mMotionTarget = child;
                                return true;
                            }
                            // The event didn't get handled, try the next view.
                            // Don't reset the event's location, it's not
                            // necessary here.
                        }
                    }
                }
            }
        }


	//如果点击空白区域,则会调用父类View的dispatchTouchEvent方法,之后流程跟View的事件处理一致
        if (target == null) {
            // We don't have a target, this means we're handling the
            // event as a regular view.
            ev.setLocation(xf, yf);
            if ((mPrivateFlags & CANCEL_NEXT_UP_EVENT) != 0) {
                ev.setAction(MotionEvent.ACTION_CANCEL);
                mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;
            }
            return super.dispatchTouchEvent(ev);
        }

        return target.dispatchTouchEvent(ev);
    }
从上面伪代码的注释中可以看出, dispatchTouchEvent方法会依据 onInterceptTouchEvent方法的返回值,来确定是否拦截子View。如果返回值为true,则拦截子View,执行其父类View的 dispatchTouchEvent方法,否则,执行子View的dispatchTouchEvent方法。

下载Demo请猛戳


内容概要:本文介绍了基于SMA-BP黏菌优化算法优化反向传播神经网络(BP)进行多变量回归预测的项目实例。项目旨在通过SMA优化BP神经网络的权重和阈值,解决BP神经网络易陷入局部最优、收敛速度慢及参数调优困难等问题。SMA算法模拟黏菌寻找食物的行为,具备优秀的全局搜索能力,能有效提高模型的预测准确性和训练效率。项目涵盖了数据预处理、模型设计、算法实现、性能验证等环节,适用于多变量非线性数据的建模和预测。; 适合人群:具备一定机器学习基础,特别是对神经网络和优化算法有一定了解的研发人员、数据科学家和研究人员。; 使用场景及目标:① 提升多变量回归模型的预测准确性,特别是在工业过程控制、金融风险管理等领域;② 加速神经网络训练过程,减少迭代次数和训练时间;③ 提高模型的稳定性和泛化能力,确保模型在不同数据集上均能保持良好表现;④ 推动智能优化算法与深度学习的融合创新,促进多领域复杂数据分析能力的提升。; 其他说明:项目采用Python实现,包含详细的代码示例和注释,便于理解和次开发。模型架构由数据预处理模块、基于SMA优化的BP神经网络训练模块以及模型预测与评估模块组成,各模块接口清晰,便于扩展和维护。此外,项目还提供了多种评价指标和可视化分析方法,确保实验结果科学可信。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值