Android 多点触控

三种类型 :接力型 /配合型 /单独型

单点触控

package com.example.myapplication.viewimport android.content.Context
import android.graphics.Canvas
import android.graphics.Paint
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import com.example.myapplication.dpclass MultiTouchView1(context: Context, attrs: AttributeSet) : View(context, attrs) {private val bitmap = getBitmap()private val paint = Paint(Paint.ANTI_ALIAS_FLAG)private var offsetX = 0f //初始位置private var offsetY = 0fprivate var downX = 0f //按下的位置private var downY = 0fprivate var originalOffsetX = 0f //偏移位置private var originalOffsetY = 0foverride fun onDraw(canvas: Canvas) {super.onDraw(canvas)canvas.drawBitmap(bitmap, offsetX, offsetY, paint)}override fun onTouchEvent(event: MotionEvent): Boolean {when (event.actionMasked) {MotionEvent.ACTION_DOWN -> {downX = event.xdownY = event.yoriginalOffsetX = offsetXoriginalOffsetY = offsetY}MotionEvent.ACTION_MOVE -> {offsetX = event.x - downX + originalOffsetXoffsetY = event.y - downY + originalOffsetYinvalidate()}}return true}
}

触摸事件序列是针对View而不是手指

x,y ,index ,id 属于一个point ,一个序列,getX 获取index为0的手指位置

  public final float getX() {return nativeGetAxisValue(mNativePtr, AXIS_X, 0, HISTORY_CURRENT);}

point_move 两个point,当第二根手指up,index会设置为0而不是1,有时候第0根手指down 为0index的会给按下的,然后0变为1

index作用是在发生MotionEvnent时,通过index遍历每个Point的操作

getX(),getX(index),index通过evnent.pointCount获取

for遍历event.point,通过getX(index) 如果某一个point抬起会报错 找不到Index,这时可以通过id查找

 MotionEvent.ACTION_MOVE -> {event.getX(event.actionIndex) //正在按下手指的IDevent.getX(event.findPointerIndex(downId)) //通过ID获取
}

action_move 不适合这种方法,因为在实时移动 更新,没有所谓的Point 也就是index ,id,只有在down / up 才有意义

接力型

package com.example.myapplication.viewimport android.content.Context
import android.graphics.Canvas
import android.graphics.Paint
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import com.example.myapplication.dpclass MultiTouchView1(context: Context, attrs: AttributeSet) : View(context, attrs) {private val bitmap =getBitmap()private val paint = Paint(Paint.ANTI_ALIAS_FLAG)private var offsetX = 0f //初始位置private var offsetY = 0fprivate var downX = 0f //按下的位置private var downY = 0fprivate var originalOffsetX = 0f //偏移位置private var originalOffsetY = 0fprivate var trackingPointerId = 0 //当前按下的手指IDoverride fun onDraw(canvas: Canvas) {super.onDraw(canvas)canvas.drawBitmap(bitmap, offsetX, offsetY, paint)}override fun onTouchEvent(event: MotionEvent): Boolean {when (event.actionMasked) {MotionEvent.ACTION_DOWN -> {trackingPointerId = event.getPointerId(0)downX = event.xdownY = event.yoriginalOffsetX = offsetXoriginalOffsetY = offsetY}//多个MotionEvent.ACTION_POINTER_DOWN -> {val actionIndex = event.actionIndextrackingPointerId = event.getPointerId(actionIndex) //按下的手指序号获取ID//更新 接管downX = event.getX(actionIndex)downY = event.getY(actionIndex)originalOffsetX = offsetXoriginalOffsetY = offsetY}MotionEvent.ACTION_POINTER_UP -> {val actionIndex = event.actionIndexval pointerId = event.getPointerId(actionIndex)if (pointerId == trackingPointerId) {//如果是正在跟踪的手指 进行替换val newIndex = if (actionIndex == event.pointerCount - 1) {event.pointerCount - 2} else {event.pointerCount - 1}trackingPointerId = event.getPointerId(newIndex) //按下的手指序号获取ID//更新 接管downX = event.getX(newIndex)downY = event.getY(newIndex)originalOffsetX = offsetXoriginalOffsetY = offsetY}}MotionEvent.ACTION_MOVE -> {val index = event.findPointerIndex(trackingPointerId)offsetX = event.getX(index) - downX + originalOffsetXoffsetY = event.getY(index) - downY + originalOffsetYinvalidate()}}return true}
}

配合型:

package com.example.myapplication.viewimport android.content.Context
import android.graphics.Canvas
import android.graphics.Paint
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import com.example.myapplication.dp
import com.example.myapplication.getAvatar//双指滑动
class MultiTouchView2(context: Context, attrs: AttributeSet) : View(context, attrs) {private val bitmap = getAvatar(resources, 200.dp.toInt())private val paint = Paint(Paint.ANTI_ALIAS_FLAG)private var offsetX = 0f //初始位置private var offsetY = 0fprivate var downX = 0f //按下的位置private var downY = 0fprivate var originalOffsetX = 0f //偏移位置private var originalOffsetY = 0foverride fun onDraw(canvas: Canvas) {super.onDraw(canvas)canvas.drawBitmap(bitmap, offsetX, offsetY, paint)}override fun onTouchEvent(event: MotionEvent): Boolean {val focusX : Float//焦点 两值相加 /2val focusY : Floatvar pointerCount = event.pointerCountvar sumX = 0fvar sumY = 0fval inPointerUp = event.actionMasked == MotionEvent.ACTION_POINTER_UP //如果是抬起for (i in 0 until  pointerCount){if (!(inPointerUp && i == event.actionIndex)){ //当前位置并且不是抬起 则计算sumX += event.getX(i) //得到每个点的坐标sumY += event.getY(i)}}if (inPointerUp){pointerCount -- //处理额外偏移}focusX = sumX / pointerCount //得到焦点值 当抬起后count会变focusY = sumY /pointerCountwhen (event.actionMasked) {MotionEvent.ACTION_DOWN,MotionEvent.ACTION_POINTER_DOWN, MotionEvent.ACTION_POINTER_UP -> {downX = focusXdownY = focusYoriginalOffsetX = offsetXoriginalOffsetY = offsetY}MotionEvent.ACTION_MOVE -> {offsetX = focusX - downX + originalOffsetXoffsetY = focusY - downY + originalOffsetYinvalidate()}}return true}
}

多指

package com.example.myapplication.viewimport android.content.Context
import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.Path
import android.util.AttributeSet
import android.util.SparseArray
import android.view.MotionEvent
import android.view.View
import androidx.core.util.isEmpty
import com.example.myapplication.dpclass MultiTouchView3(context: Context, attrs: AttributeSet) : View(context, attrs) {private val paint = Paint(Paint.ANTI_ALIAS_FLAG)private var paths = SparseArray<Path>()init {paint.style = Paint.Style.STROKEpaint.strokeWidth = 4.dppaint.strokeCap = Paint.Cap.ROUNDpaint.strokeJoin = Paint.Join.ROUND}override fun onDraw(canvas: Canvas) {super.onDraw(canvas)for (i in 0 until paths.size()){val path = paths.valueAt(i)canvas.drawPath(path,paint)}}override fun onTouchEvent(event: MotionEvent): Boolean {when(event.actionMasked){MotionEvent.ACTION_DOWN,MotionEvent.ACTION_POINTER_DOWN ->{val actionIndex = event.actionIndexval path = Path()path.moveTo(event.getX(actionIndex),event.getY(actionIndex))paths.append(event.getPointerId(actionIndex),path)invalidate()}MotionEvent.ACTION_MOVE ->{if (!paths.isEmpty()){for (i in 0 until paths.size()){val pointerId = event.getPointerId(i)val path = paths.get(pointerId)path.lineTo(event.getX(i),event.getY(i))}invalidate()}}MotionEvent.ACTION_UP,MotionEvent.ACTION_POINTER_UP -> {val actionIndex = event.actionIndexval pointerId = event.getPointerId(actionIndex)paths.remove(pointerId)invalidate()}}return true}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/183243.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

优思学院|诺桑比亚大学精益六西格玛大会 2023

国际精益六西格玛研究所&#xff08;ILSSI&#xff09;今年将赞助诺桑比亚大学&#xff08;Northumbria University&#xff09;的第九届国际精益六西格玛大会&#xff0c;大会将于2023年11月13日和14日在英国新卡斯尔市&#xff0c;诺桑比亚大学举行。 这次大会的核心主题是&a…

埃隆·马斯克的 AI 聊天机器人 Grok 已经上线

昨天&#xff0c;埃隆马斯克 (Elon Musk) 通过他的公司 xAI 推出了一款名为 Grok 的新型人工智能聊天机器人。这款新的聊天机器人将通过 Twitter 更新实时获取世界知识&#xff0c;使其成为最新的对话 AI 系统。 Grok 的独特和基本优势在于它可以通过 &#x1d54f; 平台实时了…

四.pyqt5 登录界面和功能

一.使用qt creator 设置登录界面 主界面为之前设计的界面 from123.py 文章地址&#xff1a;三.listview或tableviw显示 二.导出ui文件为py文件 # from123.py 为导出 py文件 form.ui 为 qt creator创造的 ui 文件 pyuic5 -o x:\xxx\Fromlogin20230809.py form.ui三.python 显…

Nacos-2.2.2源码修改集成高斯数据库GaussDB,postresql

一 &#xff0c;下载代码 Release 2.2.2 (Apr 11, 2023) alibaba/nacos GitHub 二&#xff0c; 执行打包 mvn -Prelease-nacos -Dmaven.test.skiptrue -Drat.skiptrue clean install -U 或 mvn -Prelease-nacos ‘-Dmaven.test.skiptrue’ ‘-Drat.skiptrue’ clean instal…

网络运维Day05

文章目录 实验环境用户与组概述用户账号创建查看用户-查创建用户-增修改用户属性-改删除用户-删 用户密码管理交互式修改密码非交互式修改密码 用户初始配置文件基本权限和归属基本权限的类别权限适用对象(归属)查看权限 修改权限设置基本权限如何判断用户对某目录所具备怎样的…

研发管理用什么软件?

研发管理用什么软件 研发管理用的软件有&#xff1a;1、JIRA&#xff1b;2、Confluence&#xff1b;3、彩虹PDM软件。彩虹PDM软件 是由南宁市二零二五科技有限公司 自主研发&#xff0c;为用户提供“产品全生命周期管理解决方案”。产品结构管理、BOD管理、零部件管理、工艺管理…

SS928开发板 开发记录三: nfs 挂载

1.创建nfs文件 1.安装nfs sudo apt-get install nfs-kernel-server 2.创建文件 sudo mkdir /home/nfsroot 3.给权限 sudo chmod 777 nfsroot 4.设置 vim /etc/exports 最后一行加入 /nfsroot *(rw,sync,no_root_squash)5. 重启nfs sudo service nfs-kernel-server r…

Redis高级数据类型-HyperLogLogBitmap以及使用两种数据类型完成网站数据统计

网站数据统计 定义相关的Redis Key /*** 单日UV*/public static String getUVKey(String date) {return PREFIX_UVSPLITdate;}/*** 记录区间UV* param startData 开始日期* param endDate 结束日期* return*/public static String getUVkey(String startData,String endDate){r…

SpringBoot+AOP+自定义注解,优雅实现日志记录

文章目录 前言准备阶段1、数据库日志表2、自定义注解编写3、AOP切面类编写4、业务层4.1、Service 层&#xff1a;4.2 Service 实现层&#xff1a; 5、测试 前言 首先我们看下传统记录日志的方式是什么样的&#xff1a; DeleteMapping("/deleteUserById/{userId}") …

ARM64 linux并发与同步之原子操作

卷2&#xff1a;调试与案例分析 第一章 并发与同步 画了两张简图&#xff0c;方便理解&#xff0c;如下&#xff1a; 针对并发源的问题&#xff0c;我接触的项目中都是SMP系统&#xff0c;目前大部分也都是SMP系统&#xff1b; 对于SMP系统&#xff0c;情况会更复杂。 □ 同…

数据可视化:动态柱状图

终于来到最后一个数据可视化的文章拿啦~~~ 在这里学习如何绘制动态柱状图 我先整个活 (๑′ᴗ‵๑)&#xff29; Lᵒᵛᵉᵧₒᵤ❤ 什么是pyecharts&#xff1f; 答&#xff1a; Python的Pyecharts软件包。它是一个用于Python数据可视化和图表绘制的库&#xff0c;可用于制作…

音乐免费下载mp3格式+音频格式转换+剪辑音频+合并音频教程

1.在qq音乐网页版搜索想要的歌曲 qq音乐网站&#xff1a;https://y.qq.com/ 如果你是vip可以直接下载vip的歌曲&#xff0c;如果不是选择不是vip的歌曲进行第一步的操作 2.点击播放进入页面后F12拿到音频地址 然后双击src里面的音频地址复制 网页新标签打开赋值的这个链接&a…

SpringBoot-WebSocket浏览器-服务器双向通信

文章目录 WebSocket 介绍入门案例 WebSocket 介绍 WebSocket 是基于 TCP 的一种新的网络协议。它实现了浏览器与服务器全双工通信——浏览器和服务器只需要完成一次握手&#xff0c;两者之间就可以创建持久性的连接&#xff0c;并进行双向数据传输。 应用场景&#xff1a; 视…

Markdown语法教程

Markdown&#xff1a;一种轻量级语言&#xff0c;有简洁的编写方式&#xff0c;能够提高大家的工作效率。 一、标题 1.1 标题 标题的编写格式以#号开始&#xff0c;分别表示h1 ~ h6&#xff0c;注意&#xff1a;# 后面有空格&#xff01; # 一级标题 ## 二级标题 ### 三级标题…

vue2.0 打包,nginx部署

1、修改这里为空 否则报错&#xff1a;vue is undefined 2、修改为hash&#xff0c;重点&#xff1a;打包dist文件运行&#xff0c;必须这样 3、安装ngnix&#xff0c;重点&#xff1a;使用node的包&#xff1a;httpserve&#xff0c;失败 4、重点&#xff1a;配置代理转发 前端…

2024天津理工大学中环信息学院专升本机械设计制造自动化专业考纲

2024年天津理工大学中环信息学院高职升本科《机械设计制造及其自动化》专业课考试大纲《机械设计》《机械制图》 《机械设计》考试大纲 教 材&#xff1a;《机械设计》&#xff08;第十版&#xff09;&#xff0c;高等教育出版社&#xff0c;濮良贵、陈国定、吴立言主编&#…

ElementUI-tree拖拽功能与节点自定义

前言 在管理端会遇到多分类时&#xff0c;要求有层次展示出来&#xff0c;并且每个分类有额外的操作。例如&#xff1a;添加分类、编辑分类、删除、拖到分类等。 下面将会记录这样的一个需求实习过程。 了解需求 分类展示按层级展示分类根据特定的参数展示可以操作的按钮&a…

四阶龙格库塔与元胞自动机

龙格库塔法参考&#xff1a; 【精选】四阶龙格库塔算法及matlab代码_四阶龙格库塔法matlab_漫道长歌行的博客-CSDN博客 龙格库塔算法 Runge Kutta Method及其Matlab代码_龙格库塔法matlab_Lzh_023016的博客-CSDN博客 元胞自动机参考&#xff1a; 元胞自动机&#xff1a;森林…

Leetcode Daily Challenge 1845. Seat Reservation Manager

1845. Seat Reservation Manager 题目要求&#xff1a;初始化一个SeatManager类包括默认构造函数和类函数&#xff0c;所有的seat初始化为true。reverse函数返回最小的true&#xff0c;然后把这个编号的椅子赋值为false。unreverse(seatNumber)函数把编号为seatNumber的椅子恢…

阿里云中的云服务器的ubuntu中的vim没有显示行号

没有行号&#xff1a; 在终端输入命令&#xff1a; vim ~/.vimrc set nu