Android手掌抑制功能的实现

2024-01-15 16:30

本文主要是介绍Android手掌抑制功能的实现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

        最近需要实现一个功能,在Activity中有一个手写区域,为了更好的用户体验,需要满足即使整个手掌放在屏幕上时(android平板,屏幕比较大)也只响应手写区域内的操作,即在支持多点触控的情况下,只响应指定的区域,我将这个功能称作“手掌抑制”,即在手写时,手掌放在屏幕上面不做任何响应。

        初看这个功能很简单,按照之前处理listview、gridview里面的子view不能响应的方式,只要在activity层不拦截向手写view传递的消息即可实现想要的效果,但经过实际测试和对android消息机制的详细研究发现,要实现这个功能会有点小复杂。

 

一、android的消息传递机制:

1、基础知识:

        (1) 所有Touch事件都被封装成了MotionEvent对象,包括Touch的位置、时间、历史记录以及第几个手指(多指触摸)等。

        (2) 事件类型分为ACTION_DOWN, ACTION_UP, ACTION_MOVE, ACTION_POINTER_DOWN, ACTION_POINTER_UP, ACTION_CANCEL,每个事件都是以ACTION_DOWN开始ACTION_UP结束。

        (3) 对事件的处理包括三类:

        传递——dispatchTouchEvent()

        拦截——onInterceptTouchEvent()

        消费——onTouchEvent()和OnTouchListener

 

2、传递流程

        (1) 事件从Activity.dispatchTouchEvent()开始传递,只要没有被停止或拦截,从最上层的View(ViewGroup)开始一直往下(子View)传递。子View可以通过onTouchEvent()对事件进行处理。

        (2) 事件由父View(ViewGroup)传递给子View,ViewGroup可以通过onInterceptTouchEvent()对事件做拦截,停止其往下传递。

        (3) 如果事件从上往下传递过程中一直没有被停止,且最底层子View没有消费事件,事件会反向往上传递,这时父View(ViewGroup)可以进行消费,如果还是没有被消费的话,最后会到Activity的onTouchEvent()函数。

        (4) 如果View没有对ACTION_DOWN进行消费,之后的其他事件不会传递过来。

        (5) OnTouchListener优先于onTouchEvent()对事件进行消费。

        上面的消费即表示相应函数返回值为true。

 

3、实际情况:

        能够响应事件处理方法的控件包括:ViewGroup、View、Activity,各类控件对三个事件响应处理方法的支持情况如下:

 

         这三个控件,Activity是处于最外层的,消息的传递首先是系统回调消息给Activity,Activity将消息传递给每一个ViewGroup,然后ViewGroup会将消息传递给相应地子View。

        本文所描述的手写控件是一个view,在有系统消息回调时只有上层控件将消息分发下来,它才能够消费和处理这些消息。

 

二、问题现象:

        接着我们进入正题,按照我在开篇介绍的那种处理方式,写一个手写view,在Activity和ViewGroup(自定义一个Layout即可)层将消息分发给该view,目前的代码看上去是这样子的:

 

public class DrawView extends View {public DrawView(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);initPaintView( );}public DrawView(Context context, AttributeSet attrs) {super(context, attrs);initPaintView( );}public DrawView(Context context) {super(context);initPaintView( );}public void clear() {  if (null != mPath) {  mPath.reset();  invalidate();  }  }  private void initPaintView() {  mPaint.setAntiAlias(true);  mPaint.setColor(Color.WHITE);  mPaint.setStyle(Paint.Style.STROKE);  mPaint.setStrokeJoin(Paint.Join.ROUND);  mPaint.setStrokeWidth(5f);  }@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);mViewWidth = MeasureSpec.getSize(widthMeasureSpec);   //获取ViewGroup宽度    mViewHeight = MeasureSpec.getSize(heightMeasureSpec);  //获取ViewGroup高度}@Override  protected void onDraw(Canvas canvas) {  canvas.drawPath(mPath, mPaint);  }  public boolean inArea( float x, float y ){return ( x >= 0 && x <= mViewWidth && y >= 0 && y <= mViewHeight)?true:false;}@Override  public boolean onTouchEvent(MotionEvent event) {float eventX = event.getX( );  float eventY = event.getY( );switch (event.getAction()) {case MotionEvent.ACTION_DOWN: {  mPath.moveTo(eventX, eventY);mLastTouchX = eventX;  mLastTouchY = eventY;invalidate( );}  return true;  case MotionEvent.ACTION_MOVE:{drawView( event, eventX, eventY );}break;case MotionEvent.ACTION_UP:{  drawView( event, eventX, eventY );}  break;  default:  return false;  }  return true;  }private void drawView( MotionEvent event, float eventX, float eventY ){resetDirtyRect(eventX, eventY);  int historySize = event.getHistorySize();  for (int i = 0; i < historySize; i++) {  float historicalX = event.getHistoricalX(i);  float historicalY = event.getHistoricalY(i);  getDirtyRect(historicalX, historicalY);  mPath.lineTo(historicalX, historicalY);  }  mPath.lineTo(eventX, eventY);  invalidate((int) (mDirtyRect.left - HALF_STROKE_WIDTH), 

这篇关于Android手掌抑制功能的实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/609513

相关文章

C语言小项目实战之通讯录功能

《C语言小项目实战之通讯录功能》:本文主要介绍如何设计和实现一个简单的通讯录管理系统,包括联系人信息的存储、增加、删除、查找、修改和排序等功能,文中通过代码介绍的非常详细,需要的朋友可以参考下... 目录功能介绍:添加联系人模块显示联系人模块删除联系人模块查找联系人模块修改联系人模块排序联系人模块源代码如下

Java中使用Java Mail实现邮件服务功能示例

《Java中使用JavaMail实现邮件服务功能示例》:本文主要介绍Java中使用JavaMail实现邮件服务功能的相关资料,文章还提供了一个发送邮件的示例代码,包括创建参数类、邮件类和执行结... 目录前言一、历史背景二编程、pom依赖三、API说明(一)Session (会话)(二)Message编程客

Java中List转Map的几种具体实现方式和特点

《Java中List转Map的几种具体实现方式和特点》:本文主要介绍几种常用的List转Map的方式,包括使用for循环遍历、Java8StreamAPI、ApacheCommonsCollect... 目录前言1、使用for循环遍历:2、Java8 Stream API:3、Apache Commons

C#提取PDF表单数据的实现流程

《C#提取PDF表单数据的实现流程》PDF表单是一种常见的数据收集工具,广泛应用于调查问卷、业务合同等场景,凭借出色的跨平台兼容性和标准化特点,PDF表单在各行各业中得到了广泛应用,本文将探讨如何使用... 目录引言使用工具C# 提取多个PDF表单域的数据C# 提取特定PDF表单域的数据引言PDF表单是一

使用Python实现高效的端口扫描器

《使用Python实现高效的端口扫描器》在网络安全领域,端口扫描是一项基本而重要的技能,通过端口扫描,可以发现目标主机上开放的服务和端口,这对于安全评估、渗透测试等有着不可忽视的作用,本文将介绍如何使... 目录1. 端口扫描的基本原理2. 使用python实现端口扫描2.1 安装必要的库2.2 编写端口扫

PyCharm接入DeepSeek实现AI编程的操作流程

《PyCharm接入DeepSeek实现AI编程的操作流程》DeepSeek是一家专注于人工智能技术研发的公司,致力于开发高性能、低成本的AI模型,接下来,我们把DeepSeek接入到PyCharm中... 目录引言效果演示创建API key在PyCharm中下载Continue插件配置Continue引言

MySQL分表自动化创建的实现方案

《MySQL分表自动化创建的实现方案》在数据库应用场景中,随着数据量的不断增长,单表存储数据可能会面临性能瓶颈,例如查询、插入、更新等操作的效率会逐渐降低,分表是一种有效的优化策略,它将数据分散存储在... 目录一、项目目的二、实现过程(一)mysql 事件调度器结合存储过程方式1. 开启事件调度器2. 创

使用Python实现操作mongodb详解

《使用Python实现操作mongodb详解》这篇文章主要为大家详细介绍了使用Python实现操作mongodb的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一、示例二、常用指令三、遇到的问题一、示例from pymongo import MongoClientf

SQL Server使用SELECT INTO实现表备份的代码示例

《SQLServer使用SELECTINTO实现表备份的代码示例》在数据库管理过程中,有时我们需要对表进行备份,以防数据丢失或修改错误,在SQLServer中,可以使用SELECTINT... 在数据库管理过程中,有时我们需要对表进行备份,以防数据丢失或修改错误。在 SQL Server 中,可以使用 SE

基于Go语言实现一个压测工具

《基于Go语言实现一个压测工具》这篇文章主要为大家详细介绍了基于Go语言实现一个简单的压测工具,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录整体架构通用数据处理模块Http请求响应数据处理Curl参数解析处理客户端模块Http客户端处理Grpc客户端处理Websocket客户端