android程序开发——事件分发机制

1.android布局层次


在我们的布局之上还存在四层布局,              所以我们应该减少布局的嵌套

2.事件分发

Android 中与 Touch 事件相关的方法包括:dispatchTouchEvent(MotionEvent ev)onInterceptTouchEvent(MotionEvent ev)onTouchEvent(MotionEvent ev);能够响应这些方法的控件包括:ViewGroup 及其子类Activity

@1

其中:

dispatchTouchEvent(MotionEvent ev)           事件分发                   Activity    ViewGroup   View   都有此方法

onInterceptTouchEvent(MotionEvent ev)       事件拦截                                          ViewGroup        有此方法

onTouchEvent(MotionEvent ev)                   事件响应                   Activity    ViewGroup   View   都有此方法

onTouch:

onTouch()是OnTouchListener接口的方法,它是获取某一个控件的触摸事件,因此使用时,必须使用setOnTouchListener绑定到控件,然后才能鉴定该控件的触摸事件。当一个View绑定了OnTouchLister后,当有touch事件触发时,就会调用onTouch方法。通过getAction()方法可以获取当前触摸事件的状态:
ACTION_DOWN:表示按下了屏幕的状态。
ACTION_MOVE :表示为移动手势
ACTION_UP      :表示为离开屏幕
ACTION_CANCEL :表示取消手势,不会由用户产生,而是由程序产生的

onTouch方法的优先级高于onTouchEvent。当onTouch 方法返回true时,会进行触摸事件处理,onTouchEvent不会处理。当onTouch返回false的时候,onTouchEvent擦会处理

@2

正常情况下:activity dispatchTouchEvent  -->>  layout dispatchTouchEvent ->> button dispatchTouchEvent -->button onTouchevent

@--1当被onInterceptTouchEvent拦截时,会执行当前的onTouchEvent 

@--2 当onTouchEvent  返回false时,返回给上一层的onTouchEvent ,如果还返回false,继续返回上一层的onTouchEvent  ,直至抛出

事件分发:public boolean dispatchTouchEvent(MotionEvent ev)
当有监听到事件时,首先由Activity的捕获到,进入事件分发处理流程。无论是Activity还是View,如前文所说,事件分发自身也具有消费能力,
如果事件分发返回true,表示改事件在本层不再进行分发且已经在事件分发自身中被消费了。至此,事件已经完结。如果你不想Activity中的任何控件具有任何的事件消费能力,
最简答的方法可以重写此Activity的dispatchTouchEvent方法,直接返回true就ok。
如果事件分发返回 false,表明事件在本层不再继续进行分发,并交由上层控件的onTouchEvent方法进行消费。
当然了,如果本层控件已经是Activity,那么事件将被系统消费或处理。
如果事件分发返回系统默认的 super.dispatchTouchEvent(ev),事件将分发给本层的事件拦截onInterceptTouchEvent 方法进行处理
(如果本层控件是Activity,由于其没有事件拦截,因此将直接将事件传递到子View,并交给子View的事件分发进行处理)。
事件拦截:public boolean onInterceptTouchEvent(MotionEvent ev) 
如果 onInterceptTouchEvent 返回 true,则表示将事件进行拦截,并将拦截到的事件交由本层控件 的 onTouchEvent 进行处理;
如果返回结果是false;则表示不对事件进行拦截,事件得以成功分发到子View。并由子View的dispatchTouchEvent进行处理。
如果返回super.onInterceptTouchEvent(ev),事件默认不会被拦截,交由子View的dispatchTouchEvent进行处理。
 事件响应:public boolean onTouchEvent(MotionEvent ev)
在 dispatchTouchEvent 返回 super.dispatchTouchEvent(ev) 并且 onInterceptTouchEvent 返回 true 或返回 super.onInterceptTouchEvent(ev) 的情况下 onTouchEvent 会被调用。

onTouchEvent 的事件响应逻辑如下:
如果事件传递到当前 View 的 onTouchEvent 方法,而该方法返回了 false,那么这个事件会从当前 View 向上传递,并且都是由上层 View 的 onTouchEvent 来接收,如果传递到上面的 onTouchEvent 也返回 false,这个事件就会“消失”,而且接收不到下一次事件。
如果返回了 true 则会接收并消费该事件。
如果返回 super.onTouchEvent(ev) 默认处理事件的逻辑和返回 false 时相同。

(我个人的判断是最里面的  返回false 则 其上层所有的onTouchEvent的的super  默认为false)



ScrollView  和  ListView的冲突(@1 ScrollView   嵌套Listview   @2 ScrollView  嵌套一个ScrollView)

@1 ScrollView  嵌套一个ListView

原因:

@1. 因为ListView需要支持长按操作,所以ListView本身的ACTION_MOVE,会有一定的初始距离检测,小于这个距离,代表没有移动,只有从按下到移动之间坐标位置相差大         一点,才回认为ListView需要移动;
@2. ScrollView 在检测滚动事件的时候,如果ScrollView的内容的高度>ScrollView显示的高度,就认为内部的内容可以滚动,是整体滚动;ScrollView在上下滚动的时候如果           DOWN的位置与当前MOVE的位置相差很小,认为没有滚动;
@3. 当按下位置与移动的位置超过一个固定的距离之后,ScrollView再分发事件的时候,就会检测出可以滚动,那么因为ScrollView内容高度可以滚动,那么就直接滚动自身 内         容,而不把滚动事件,传递给ListView了
@4. 根据代码的分析,ScrollView判断是否开始滚动,采用的是 滚动幅度是否大于8dp的方式,ListView也是采用滚动幅度>8dp的检测;只要>8的时候,ScrollView就会先收到          事件,然后把事件就给拦截了;不再给 ListView 了;

解决方案:

@1. 重写 ListView 的 onMeasure() 让ListView计算自身所有内容的高度,全部填满ScrollView
@2. 这种方案会产生效率的问题,因为一次会把所有的Item全部显示出来;没有复用;一定要注意,通常都是显示简单的文字信息和小图片;
@3. ListView在ScrollView中,高度测量的时候,传递的模式就是 “未指定”,所以ListView默认就会计算一行的高度;
@4. 解决方案就是在ListView计算尺寸之前,强制把 未指定 调整为AT_MOST, 指定的高度可以是一个非常大的数值,这样全部显示出来;


不可取的方法(原因:需要计算出ListView的高度,全部展现出来,这就有一个隐患:不敢加图片   否则卡出翔)

原始方法,易理解:

要在listView添加完adapter后  计算高度,在之前好像貌似没用

public static void setListViewHeight(ListView listView){
        if (listView == null){
            return;
        }
        ListAdapter adapter = listView.getAdapter();
        if (adapter == null) {
            return;
        }
        int Height = 0;
        /**
         * 内容的长度
         */
        for (int i = 0; i < adapter.getCount(); i++) {
            View adapterView = adapter.getView(i, null, listView);
            adapterView.measure(0,0);
            Height += adapterView.getMeasuredHeight();
        }
        ViewGroup.LayoutParams params = listView.getLayoutParams();
        /**
         * (listView.getDividerHeight()*(adapter.getCount() - 1)
         * ListView各个item的间隙长度
         */
        params.height = Height + (listView.getDividerHeight()*(adapter.getCount() - 1));
        listView.setLayoutParams(params);
    }
简单方法,只需要重写ListView里的onMeasure方法即可
package com.treasure_ct.android_xt.seniorcontrols.eventdistribution.widgets;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.AbsListView;
import android.widget.ListView;

/**
 * Created by treasure on 2016.09.27.
 */

public class MyListView extends ListView{

    public MyListView(Context context) {
        super(context);
    }

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

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int spec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
        super.onMeasure(widthMeasureSpec, spec);
    }
}

可取的方法(将可以滑动的权限调配,当手指点到LV的时候,不将滚动事件给父控件即SV   点到非LV时  吧滚动事件交给父控件SV)

重写ListView里的onInterceptTouchEvent方法

@Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        switch (ev.getAction()){
            case MotionEvent.ACTION_DOWN:
                setParentScrollAble(false);//手指触到listview的时候,让父ScrollView交出ontouch权限,也就是让父scrollview停住不能滚动
                Log.d(TAG, "onInterceptTouchEvent: down");
                break;
            case MotionEvent.ACTION_MOVE:
                Log.d(TAG, "onInterceptTouchEvent: move");
                break;
            case MotionEvent.ACTION_UP:
                Log.d(TAG, "onInterceptTouchEvent: up");
                break;
            case MotionEvent.ACTION_CANCEL:
                setParentScrollAble(true);//当手指松开时,让父ScrollView重新拿到onTouch权限
                Log.d(TAG, "onInterceptTouchEvent: cancel");
                break;
            default:
                break;
        }
        return super.onInterceptTouchEvent(ev);
    }
    /**
     * 是否把滚动事件交给父ScrollView
     */
    private void setParentScrollAble(boolean flag){
        getParent().requestDisallowInterceptTouchEvent(!flag);
    }
@2  ScrollView嵌套一个HorizontalScrollView     解决卡顿情况

网上的办法

package com.treasure_ct.android_xt.seniorcontrols.eventdistribution.widgets;

import android.content.Context;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ScrollView;

/**
 * Created by treasure on 2016.09.27.
 */

public class MyScrollView2 extends ScrollView {
    private GestureDetector mGestureDetector;
    View.OnTouchListener mOnTouchListener;
    public MyScrollView2(Context context) {
        super(context);
    }

    public MyScrollView2(Context context, AttributeSet attrs) {
        super(context, attrs);
        mGestureDetector = new GestureDetector(new YScrollDetector());
        setFadingEdgeLength(0);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return super.onInterceptTouchEvent(ev) && mGestureDetector.onTouchEvent(ev);
    }
    //如果Y角移动的绝对值大于X轴移动的绝对值,即纵向滑动返回true
    class YScrollDetector extends GestureDetector.SimpleOnGestureListener {
        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            if (Math.abs(distanceY) > Math.abs(distanceX)){
                return true;
            }
            return false;
        }
    }
}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我! 毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip
综合小区管理系统管理系统按照操作主体分为管理员和用户。管理员的功能包括报修管理、车位管理、车位分配管理、出入管理、字典管理、房屋管理、物业费缴纳管理、公告管理、物业人员投诉管理、我的私信管理、物业人员管理、用户管理、管理员管理。用户的功能包括管理部门以及部门岗位信息,管理招聘信息,培训信息,薪资信息等。该系统采用了Mysql数据库,Java语言,Spring Boot框架等技术进行编程实现。 综合小区管理系统管理系统可以提高综合小区管理系统信息管理问题的解决效率,优化综合小区管理系统信息处理流程,保证综合小区管理系统信息数据的安全,它是一个非常可靠,非常安全的应用程序。 管理员权限操作的功能包括管理公告,管理综合小区管理系统信息,包括出入管理,报修管理,报修管理,物业费缴纳等,可以管理操作员。 出入管理界面,管理员在出入管理界面中可以对界面中显示,可以对招聘信息的招聘状态进行查看,可以添加新的招聘信息等。报修管理界面,管理员在报修管理界面中查看奖罚种类信息,奖罚描述信息,新增奖惩信息等。车位管理界面,管理员在车位管理界面中新增。公告管理界面,管理员在公告管理界面查看公告的工作状态,可以对公告的数据进行导出,可以添加新公告的信息,可以编辑公告信息,删除公告信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值