多点触控 Android 自定义控件
文章目录
- 前言
- 一、接力棒型或抢占型
- 思路
- code
- 一:`ACTION_DOWN`时,只有一根手指按下,就把图片操控权赋给index为0的这根唯一手指
- 二:`ACTION_POINTER_DOWN`时,就把图片控制权交给新手指
- 三:有手指抬起
- 完整代码
- 效果展示
- 二、协作型
- 思路
- code
- 一:在`onTouchEvent`中,在判断各种事件之前,先找到几何中心,找到那个虚拟出来的拥有图片控制权的手指的**x,y**坐标
- 二:如果是点击和抬起就更新一下点击位置和原本的位置
- 三:如果是移动,则改变图片偏移,利用几何中心的位置
- 效果展示
- 完整代码
- 四:各自为战型,各画各型
前言
在之前的那篇博客中我们做了一个可以随手指移动的图片view,只能支持单指操控,如果我们多指触控就没事我们想要的效果
多点触控可以有下面这三种类型
①:接力棒型或抢占型
②:协作型
③:互不干扰型
一、接力棒型或抢占型
思路
①:确认一个触摸点作为控制图片的特殊触摸点
②:移动时就把拥有图片控制权的触点作为唯一触点
③:如果有第二根手指按下,那么控制权第由一根手指交接到第二根手指
④:如果有多个手指,这时其中一个抬起,那么如果抬起的这根手指时拥有对图片控制权的,那么交换控制权
code
一:ACTION_DOWN
时,只有一根手指按下,就把图片操控权赋给index为0的这根唯一手指
MotionEvent.ACTION_DOWN -> {leadingPointerId = event.getPointerId(0)downX = event.xdownY = event.yoriginOffsetX = offsetXoriginOffsetY = offsetY}
二:ACTION_POINTER_DOWN
时,就把图片控制权交给新手指
//接力,把图片控制权交给刚点击的指头
MotionEvent.ACTION_POINTER_DOWN -> {val actionIndex = event.actionIndexleadingPointerId = event.getPointerId(actionIndex)downX = event.getX(actionIndex)downY = event.getY(actionIndex)originOffsetX = offsetXoriginOffsetY = offsetY
}
三:有手指抬起
//接力,如果移走的指头时拥有控制权的指头,把控制权交给其他指头
MotionEvent.ACTION_POINTER_UP -> {val isLeadingPointer = event.findPointerIndex(leadingPointerId) == event.actionIndexif (isLeadingPointer) {val newIndex =if (event.findPointerIndex(leadingPointerId) == event.pointerCount - 1) {event.pointerCount - 2} else {event.pointerCount - 1}leadingPointerId = event.getPointerId(newIndex)downX = event.getX(newIndex)downY = event.getY(newIndex)originOffsetX = offsetXoriginOffsetY = offsetY}
}
1:如果抬起的手指没有图片的控制权,则不做处理
2:如果抬起的手指有图片的控制权
①:如果抬起的这个手指是最后一根,那么就把控制权交给倒数第二根
②:否则交给倒数第一根
3:只有接力时,downX
,originOffsetY
这些值才更新
完整代码
package com.lbj23.customview.customviewimport 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.lbj23.customview.R
import com.lbj23.customview.dp
import com.lbj23.customview.getAvatarclass MultiTouchView(context: Context?, attrs: AttributeSet?) : View(context, attrs) {private val image = getAvatar(resources, R.drawable.bg6, 85.dp.toInt())private var offsetX = 0fprivate var offsetY = 0fprivate var originOffsetX = 0fprivate var originOffsetY = 0fprivate var downX = 0fprivate var downY = 0fprivate val paint = Paint(Paint.ANTI_ALIAS_FLAG)private var leadingPointerId = 0override fun onDraw(canvas: Canvas) {super.onDraw(canvas)canvas.drawBitmap(image, offsetX, offsetY, paint)}override fun onTouchEvent(event: MotionEvent): Boolean {when (event.actionMasked) {MotionEvent.ACTION_DOWN -> {leadingPointerId = event.getPointerId(0)downX = event.xdownY = event.yoriginOffsetX = offsetXoriginOffsetY = offsetY}//接力,如果移走的指头时拥有控制权的指头,把控制权交给其他指头MotionEvent.ACTION_POINTER_UP -> {val isLeadingPointer = event.findPointerIndex(leadingPointerId) == event.actionIndexif (isLeadingPointer) {val newIndex =if (event.findPointerIndex(leadingPointerId) == event.pointerCount - 1) {event.pointerCount - 2} else {event.pointerCount - 1}leadingPointerId = event.getPointerId(newIndex)downX = event.getX(newIndex)downY = event.getY(newIndex)originOffsetX = offsetXoriginOffsetY = offsetY}}//接力,把图片控制权交给刚点击的指头MotionEvent.ACTION_POINTER_DOWN -> {val actionIndex = event.actionIndexleadingPointerId = event.getPointerId(actionIndex)downX = event.getX(actionIndex)downY = event.getY(actionIndex)originOffsetX = offsetXoriginOffsetY = offsetY}MotionEvent.ACTION_MOVE -> {val index = event.findPointerIndex(leadingPointerId)offsetX = event.getX(index) - downX + originOffsetXoffsetY = event.getY(index) - downY + originOffsetYinvalidate()}}return true}
}
效果展示
很明显只有一根手指拥有对图片的控制权
二、协作型
思路
①:一根手指时,图片只由这一根手指控制
②:多根手指同时按在屏幕上时,由多根手指的几何中心作为一根虚拟的手指操控图片
code
一:在onTouchEvent
中,在判断各种事件之前,先找到几何中心,找到那个虚拟出来的拥有图片控制权的手指的x,y坐标
var sumX = 0fvar sumY = 0fval isPointerUP = event.actionMasked == MotionEvent.ACTION_POINTER_UPfor (index in 0 until event.pointerCount) {//如果是抬起就要提前做操作,这时pointerCount还是没减去抬起手指的point数量,所以提前更新好位置if (!(isPointerUP && index == event.actionIndex)) {sumX += event.getX(index)sumY += event.getY(index)}}var pointerCount = event.pointerCountif (isPointerUP) {pointerCount--}//设置一个几何中心val focusX = sumX / pointerCountval focusY = sumY / pointerCount
①:用sumX
和sumY
通过遍历所有手指,记录下总的坐标
②:用sumX
和sumY
同时除以手指数就拿到几何中心的位置了
③:如果event.actionMasked
是MotionEvent.ACTION_POINTER_UP
,由于这时遍历所有手指,这根抬起的手指还在,在之后的action中用到这个几何中心时就会出问题,所以如果是MotionEvent.ACTION_POINTER_UP
,那么就把这根抬起的手指从几何中心的计算中剥离出去
二:如果是点击和抬起就更新一下点击位置和原本的位置
MotionEvent.ACTION_DOWN, MotionEvent.ACTION_POINTER_UP, MotionEvent.ACTION_POINTER_DOWN -> {downX = focusXdownY = focusYoriginOffsetX = offsetXoriginOffsetY = offsetY
}
三:如果是移动,则改变图片偏移,利用几何中心的位置
MotionEvent.ACTION_MOVE -> {offsetX = focusX - downX + originOffsetXoffsetY = focusY - downY + originOffsetYinvalidate()
}
效果展示
通过观察得出:
①:两根手指滑动时,图片拖动速度比较快
②:一根手指固定,另一根手指滑动,图片拖动速度较慢,为移动的那根手指的半速
完整代码
package com.lbj23.customview.customviewimport 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.lbj23.customview.R
import com.lbj23.customview.dp
import com.lbj23.customview.getAvatarclass MultiTouchView2(context: Context?, attrs: AttributeSet?) : View(context, attrs) {private val image = getAvatar(resources, R.drawable.bg6, 150.dp.toInt())private var offsetX = 0fprivate var offsetY = 0fprivate var originOffsetX = 0fprivate var originOffsetY = 0fprivate var downX = 0fprivate var downY = 0fprivate val paint = Paint(Paint.ANTI_ALIAS_FLAG)override fun onDraw(canvas: Canvas) {super.onDraw(canvas)canvas.drawBitmap(image, offsetX, offsetY, paint)}override fun onTouchEvent(event: MotionEvent): Boolean {var sumX = 0fvar sumY = 0fval isPointerUP = event.actionMasked == MotionEvent.ACTION_POINTER_UPfor (index in 0 until event.pointerCount) {//如果是抬起就要提前做操作,这时pointerCount还是没减去抬起手指的point数量,所以提前更新好位置if (!(isPointerUP && index == event.actionIndex)) {sumX += event.getX(index)sumY += event.getY(index)}}var pointerCount = event.pointerCountif (isPointerUP) {pointerCount--}//设置一个几何中心val focusX = sumX / pointerCountval focusY = sumY / pointerCountwhen (event.actionMasked) {//如果是点击和抬起就更新一下点击位置和原本的位置MotionEvent.ACTION_DOWN, MotionEvent.ACTION_POINTER_UP, MotionEvent.ACTION_POINTER_DOWN -> {downX = focusXdownY = focusYoriginOffsetX = offsetXoriginOffsetY = offsetY}//如果是移动,则改变位置,利用几何中心MotionEvent.ACTION_MOVE -> {offsetX = focusX - downX + originOffsetXoffsetY = focusY - downY + originOffsetYinvalidate()}}return true}
}
四:各自为战型,各画各型
这种类型要求我们对每根手指都分开处理
点击详情
多点触控 Android 自定义控件相关推荐
- 单点触控、多点触控和自定义控件的使用
单点触控的使用 比如图片的位移.旋转,透明,缩放等. 多点触控的使用 Android多点触控的本质:需要LCD驱动和保存程序本身设计上的支持 市场上的应用:HTC.Motorota和Samsung等知 ...
- 模拟Android多点触控
Android多点触控 Android多点触控 多点触控实现思路 第一种adb shell input方式 第二种adb shell sendevent方式 多点触控实现思路 经过资料的查询,要在 ...
- Android自定义控件ImageViwe(四)——多点触控实现图片的自由移动
效果图: 功能 : 可以随手指进行自由移动图片 按照适当的比例设置图片的显示 首先将图片按照适当的比例显示在自定义控件中(当图片的宽度或者高度大于控件的宽度或者高度的时候,会对图片进行适当的缩放,当图 ...
- Android 多点触控 MotionEvent详解
相关API 介绍 MotionEvent.getY() 和 MotionEvent.getRawY() 的区别 getY 表示触摸事件在当前的View内的Y 坐标, getRawY表示触摸事件在整个屏 ...
- 【Android 应用开发】多点触控 ( 多点触控事件 | PointerId | PointerIndex | 坐标获取 | 触摸点个数 )
文章目录 I . 多点触控事件 II . PointerId 与 PointerIndex 简介 III . 本次 PointerId 与 PointerIndex 获取 IV . PointerId ...
- android 关闭多点触控_Cocos Creator关闭多点触摸的问题
一. 方案一:改写Node的派发事件 方法:改写node的派发事件,当有多个响应的时候不去进行dispatch. 在游戏开启的时候把node原来的方法: cc.Node.prototype.dispa ...
- Android多点触控MultiTouch浅析
申明: 参考:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2013/0226/914.html 下面实现如何通过应用层支持多点触控操作, ...
- Android开发实例之多点触控程序
智能终端设备的多点触控操作为我们带来了种种炫酷体验,这也使得很多Android开发者都对多点触控程序的开发感兴趣.实际上多点触控程序的实现并不是那么遥不可及,而是比较容易.本文就主要通过一个实例具体讲 ...
- android 多点触控缩放,Android多点触控(图片的缩放Demo)
本文主要介绍Android的多点触控,使用了一个图片缩放的实例,来更好的说明其原理.需要实现OnTouchListener接口,重写其中的onTouch方法. 实现效果图: 源代码: 布局文件: ac ...
最新文章
- 【JavaWeb】Access restriction The type is not accessible due to restriction on required library
- 「面试题」介绍你做过最复杂的系统
- oracle 10g gateway 安装操作,Oracle 10g RAC启动节点报错 Default gateway is not defined
- 剑指offer之树的子结构
- hadoop运行wordcount实例,hdfs简单操作
- Devexpress Chart series 点击时获取SeriesPoint的值
- 七年级上册计算机教学反思,七年级信息技术上册教学反思
- ubuntu下安装opencv2
- U2Net——U-Net套U-Net——套娃式图像分割算法
- android 字体特效,Android自定义View实现闪耀字体效果
- android studio Statistic插件不显示
- 基于WPS的在线编辑服务【.net Core 3.1】
- Python实现任意多边形的最大内切圆算法
- 申论公文题-总结类-1
- 知识点滴 - X射线和伽马射线有什么区别?
- 图卷积神经网络4-空域卷积:空域卷积局限性分析和过平滑解决方案
- u盘虚拟启动cd linux,CDlinux制作U盘启动盘,打造自己的口袋系统
- 告别windows、拥抱linux,ThinkPad E485安装XUbuntu实录
- 滴滴收购优步谈判过程_大流行之后,优步正在为绿色业务做准备
- 光大证券5名高管被罚260万元
热门文章
- 奥特曼ol系列新生代服务器,奥特曼系列ol九游
- php 自定义编号,中国蚁剑自定义编码用法
- 生成一份mysql巡检报告
- 2021年秋招面经分享·商汤【22领航员-工程院-芯片设计工程师】
- UWB防爆基站等级详细说明
- 2022智能仓储与工业物流行业分析
- 【Arduino】入门篇——SOS求救信号器
- 在IT部门和研发部门的工作差别
- jstl mysql 更新_jstl sql:update标签
- 下单账号与支付账号不一致_开发者报丨网友微信/支付宝/百度云盘等账号集体被盗,支付宝官方回应...