文章目录

  • 前言
  • 一、接力棒型或抢占型
    • 思路
    • 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:只有接力时,downXoriginOffsetY这些值才更新

完整代码

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

①:用sumXsumY通过遍历所有手指,记录下总的坐标
②:用sumXsumY同时除以手指数就拿到几何中心的位置了
③:如果event.actionMaskedMotionEvent.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 自定义控件相关推荐

  1. 单点触控、多点触控和自定义控件的使用

    单点触控的使用 比如图片的位移.旋转,透明,缩放等. 多点触控的使用 Android多点触控的本质:需要LCD驱动和保存程序本身设计上的支持 市场上的应用:HTC.Motorota和Samsung等知 ...

  2. 模拟Android多点触控

    Android多点触控 Android多点触控 多点触控实现思路 第一种adb shell input方式 第二种adb shell sendevent方式 多点触控实现思路   经过资料的查询,要在 ...

  3. Android自定义控件ImageViwe(四)——多点触控实现图片的自由移动

    效果图: 功能 : 可以随手指进行自由移动图片 按照适当的比例设置图片的显示 首先将图片按照适当的比例显示在自定义控件中(当图片的宽度或者高度大于控件的宽度或者高度的时候,会对图片进行适当的缩放,当图 ...

  4. Android 多点触控 MotionEvent详解

    相关API 介绍 MotionEvent.getY() 和 MotionEvent.getRawY() 的区别 getY 表示触摸事件在当前的View内的Y 坐标, getRawY表示触摸事件在整个屏 ...

  5. 【Android 应用开发】多点触控 ( 多点触控事件 | PointerId | PointerIndex | 坐标获取 | 触摸点个数 )

    文章目录 I . 多点触控事件 II . PointerId 与 PointerIndex 简介 III . 本次 PointerId 与 PointerIndex 获取 IV . PointerId ...

  6. android 关闭多点触控_Cocos Creator关闭多点触摸的问题

    一. 方案一:改写Node的派发事件 方法:改写node的派发事件,当有多个响应的时候不去进行dispatch. 在游戏开启的时候把node原来的方法: cc.Node.prototype.dispa ...

  7. Android多点触控MultiTouch浅析

    申明: 参考:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2013/0226/914.html 下面实现如何通过应用层支持多点触控操作, ...

  8. Android开发实例之多点触控程序

    智能终端设备的多点触控操作为我们带来了种种炫酷体验,这也使得很多Android开发者都对多点触控程序的开发感兴趣.实际上多点触控程序的实现并不是那么遥不可及,而是比较容易.本文就主要通过一个实例具体讲 ...

  9. android 多点触控缩放,Android多点触控(图片的缩放Demo)

    本文主要介绍Android的多点触控,使用了一个图片缩放的实例,来更好的说明其原理.需要实现OnTouchListener接口,重写其中的onTouch方法. 实现效果图: 源代码: 布局文件: ac ...

最新文章

  1. 【JavaWeb】Access restriction The type is not accessible due to restriction on required library
  2. 「面试题」介绍你做过最复杂的系统
  3. oracle 10g gateway 安装操作,Oracle 10g RAC启动节点报错 Default gateway is not defined
  4. 剑指offer之树的子结构
  5. hadoop运行wordcount实例,hdfs简单操作
  6. Devexpress Chart series 点击时获取SeriesPoint的值
  7. 七年级上册计算机教学反思,七年级信息技术上册教学反思
  8. ubuntu下安装opencv2
  9. U2Net——U-Net套U-Net——套娃式图像分割算法
  10. android 字体特效,Android自定义View实现闪耀字体效果
  11. android studio Statistic插件不显示
  12. 基于WPS的在线编辑服务【.net Core 3.1】
  13. Python实现任意多边形的最大内切圆算法
  14. 申论公文题-总结类-1
  15. 知识点滴 - X射线和伽马射线有什么区别?
  16. 图卷积神经网络4-空域卷积:空域卷积局限性分析和过平滑解决方案
  17. u盘虚拟启动cd linux,CDlinux制作U盘启动盘,打造自己的口袋系统
  18. 告别windows、拥抱linux,ThinkPad E485安装XUbuntu实录
  19. 滴滴收购优步谈判过程_大流行之后,优步正在为绿色业务做准备
  20. 光大证券5名高管被罚260万元

热门文章

  1. 奥特曼ol系列新生代服务器,奥特曼系列ol九游
  2. php 自定义编号,中国蚁剑自定义编码用法
  3. 生成一份mysql巡检报告
  4. 2021年秋招面经分享·商汤【22领航员-工程院-芯片设计工程师】
  5. UWB防爆基站等级详细说明
  6. 2022智能仓储与工业物流行业分析
  7. 【Arduino】入门篇——SOS求救信号器
  8. 在IT部门和研发部门的工作差别
  9. jstl mysql 更新_jstl sql:update标签
  10. 下单账号与支付账号不一致_开发者报丨网友微信/支付宝/百度云盘等账号集体被盗,支付宝官方回应...