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.mzph.cn/news/138535.shtml

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

相关文章

10 # 手写 every 方法

every 使用 every() 方法测试一个数组内的所有元素是否都能通过指定函数的测试。它返回一个布尔值。 ele&#xff1a;表示数组中的每一个元素index&#xff1a;表示数据中元素的索引array&#xff1a;表示数组 <script>var arr [1, 3, 5, 7, 8];var result arr.ever…

win 命令替代鼠标的操作

操作方式都是在 winR 输入框输入或者终端输入 1、快速打开 控制面板 运行control 2、快速打开 电源选项 运行powercfg.cpl 3、快速打开 网络连接 运行ncpa.cpl 4、快速打开 程序和功能 运行appwiz.cpl 5、快速打开 Windows Defender防火墙 运行Firewall.cpl 6、快速打开 鼠标 …

Matlab的多项式留数与极点的计算

Matlab的多项式留数与极点的计算 以下面的多项式为例&#xff1a; 运算代码&#xff1a; clc clear closesyms p % 定义多项式 Zp(5*p^571*p^370*p)/(2*p^635*p^4117*p^236); % 提取分子与分母 [I,D]numden(Zp); Idouble(coeffs(I,p,"All"));%分子 Ddouble(coeffs…

多目标优化框架

随着模型越来越复杂&#xff0c;优化目标越来越多&#xff0c;传统算法都慢慢地无法胜任复杂优化任务&#xff0c;更为智能的优化方法也就应运而生了。其中有一类是进化优化算法&#xff0c;这类算法的思想来源是自然界的“优胜劣汰”法则&#xff0c;通过不停地保留好的个体最…

大漠插件(二、Qt使用插件时注意事项)

本章目的 在上篇已经注册完毕大漠&#xff0c;那么怎么使用大漠来制作脚本&#xff0c;我选择了我最熟悉的Qt来开发&#xff0c;毕竟只是小软件&#xff0c;用脚本或者c都差不了多少。本章就是开发途中的一些坑。 本人开发环境是 win11 64、Qt 5.15.2安装了5.10.0的msvc2015 32…

Linux - 基础IO(Linux 当中的文件,文件系统调用接口,文件描述符)- 上篇

前言 首先&#xff0c;关于文件我们最先要理解的是&#xff0c;文件不仅仅存储的是数据&#xff0c;一个文件包括 内容 数据。内容好理解&#xff0c;就是我们先要这文件存储哪一些数据&#xff0c;这些数据就是文件的内容。 但是&#xff0c;在计算机当中&#xff0c;有两种…

【数据结构】树与二叉树(十):二叉树的先序遍历(非递归算法NPO)

文章目录 5.2.1 二叉树二叉树性质引理5.1&#xff1a;二叉树中层数为i的结点至多有 2 i 2^i 2i个&#xff0c;其中 i ≥ 0 i \geq 0 i≥0。引理5.2&#xff1a;高度为k的二叉树中至多有 2 k 1 − 1 2^{k1}-1 2k1−1个结点&#xff0c;其中 k ≥ 0 k \geq 0 k≥0。引理5.3&…

WAF入侵防御系统标准检查表

软件开发全文档获取&#xff1a;进主页

GitHub Copilot Chat将于12月全面推出;DeepLearning.AI免费新课

&#x1f989; AI新闻 &#x1f680; GitHub Copilot Chat将于12月全面推出&#xff0c;提升开发者的生产力 摘要&#xff1a;GitHub宣布将于12月全面推出GitHub Copilot Chat&#xff0c;这是GitHub Copilot的一个新功能&#xff0c;旨在帮助开发者编写代码。它能够集成到开…

【Linux】语言层面缓冲区的刷新问题以及简易模拟实现

文章目录 前言一、缓冲区刷新方法分类a.无缓冲--直接刷新b.行缓冲--不刷新&#xff0c;直到碰到\n才刷新c.全缓冲--缓冲区满了才刷新 二、 缓冲区的常见刷新问题1.问题2.刷新本质 三、模拟实现1.Mystdio.h2.Mystdio.c3.main.c 前言 我们接下来要谈论的是我们语言层面的缓冲区&…

No source control providers registered

使用vscode时碰到这个问题 git扩展没启动

centos 7.9系统安装老版本jenkins,并解决插件问题

1.初衷 因为jenkins随着时间推移&#xff0c;其版本也越来越新&#xff0c;支持它运行的JDK也越来越新。基于不折腾的目标&#xff0c;我们安装一个老的固定版本就行。以前安装新版本&#xff0c;经常碰到的问题就是插件安装不兼容的问题。现在这个问题&#xff0c;可以把以前…

Sprint Boot 学习路线 4

微服务 Spring Microservices是一个框架&#xff0c;它使用Spring框架更容易地构建和管理基于微服务的应用程序。微服务是一种架构风格&#xff0c;其中一个大型应用程序被构建为一组小型、独立可部署的服务。每个服务具有明确定义的职责&#xff0c;并通过API与其他服务通信。…

解析html生成Word文档

内容&#xff1a;读取html文件中的文本内容&#xff0c;然后生成Word文档导出。 事例场景&#xff1a;需求开发完成之后需要写文档&#xff08;代码修改清单&#xff09;&#xff0c;文档内容就是这次需求修改/新增的所有代码&#xff0c;需要列出修改的文件路径以及代码片段&…

Python实战:绘制直方图的示例代码,数据可视化获取样本分布特征

文章目录 一、初步二、参数三、绘图类型四、多组数据直方图对比Python技术资源分享1、Python所有方向的学习路线2、学习软件3、精品书籍4、入门学习视频5、实战案例6、清华编程大佬出品《漫画看学Python》7、Python副业兼职与全职路线 一、初步 对于大量样本来说&#xff0c;如…

systemctl enable docker.service报错“Failed to execute operation: Bad message“

将docker加入到开机自启&#xff0c;报错&#xff1a; 解决&#xff1a; 重新粘贴复制&#xff1a; [Unit] DescriptionDocker Application Container Engine Documentationhttps://docs.docker.com Afternetwork-online.target firewalld.service Wantsnetwork-online.target…

VS c++多文件编译

前言&#xff1a;记录下我这个菜鸡学习的过程&#xff0c;如有错误恳请指出&#xff0c;不胜感激&#xff01; 1.简单多文件编译调试 文件目录&#xff1a; 编译&#xff1a; -g选项是告诉编译器生成调试信息&#xff0c;这样可以在程序崩溃或出现错误时更容易地进行调试。这…

Windows下安装Anaconda5.3.1+Python3.8+TensorFlow2.13.0-CPU版本总结

Python3.8安装可以参考博文https://janus.blog.csdn.net/article/details/55274849 进行安装即可。 【1】Anaconda 清华的开源软件镜像站&#xff1a;https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/下载&#xff0c;这里选择的是5.3.1版本。 然后正常安装就可以&am…

华为ensp:交换机接口划分vlan

现在要把 e0/0/1 接口放入vlan1 e0/0/2 接口放入vlan2 e0/0/3 接口放入vlan3 默认所有接口都在vlan1所以 e0/0/0 接口不用动 1.创建vlan 进入系统视图模式 直接输入 vlan 编号 即可创建对应vlan vlan 编号 vlan 2 创建vlan2 vlan 3 创建vlan3 2.将接口进入vlan…

HALSTM32通用定时器+EXTI实现单击/双击/长按功能

HALSTM32通用定时器EXTI实现单击/双击/长按功能 ✨在使用USB功率计的时候&#xff0c;发现上面的一个按键实现多画面功能切换&#xff0c;于是探索了一下是如何实现的&#xff0c;将其实现的基本思路以及综合网上收集的相关实现方法&#xff0c;粗陋的整理了一下&#xff0c;将…