- 前言
- 一、接力棒型或抢占型
- 思路
- code
- 一:`ACTION_DOWN`时,只有一根手指按下,就把图片操控权赋给index为0的这根唯一手指
- 二:`ACTION_POINTER_DOWN`时,就把图片控制权交给新手指
- 三:有手指抬起
- 完整代码
- 效果展示
- 二、协作型
- 思路
- code
- 一:在`onTouchEvent`中,在判断各种事件之前,先找到几何中心,找到那个虚拟出来的拥有图片控制权的手指的**x,y**坐标
- 二:如果是点击和抬起就更新一下点击位置和原本的位置
- 三:如果是移动,则改变图片偏移,利用几何中心的位置
- 效果展示
- 完整代码
- 四:各自为战型,各画各型
前言
在之前的那篇博客中我们做了一个可以随手指移动的图片view,只能支持单指操控,如果我们多指触控就没事我们想要的效果
多点触控可以有下面这三种类型
①:接力棒型或抢占型
②:协作型
③:互不干扰型
一、接力棒型或抢占型 思路
①:确认一个触摸点作为控制图片的特殊触摸点
②:移动时就把拥有图片控制权的触点作为唯一触点
③:如果有第二根手指按下,那么控制权第由一根手指交接到第二根手指
④:如果有多个手指,这时其中一个抬起,那么如果抬起的这根手指时拥有对图片控制权的,那么交换控制权
MotionEvent.ACTION_DOWN -> {
leadingPointerId = event.getPointerId(0)
downX = event.x
downY = event.y
originOffsetX = offsetX
originOffsetY = offsetY
}
二:ACTION_POINTER_DOWN时,就把图片控制权交给新手指
//接力,把图片控制权交给刚点击的指头
MotionEvent.ACTION_POINTER_DOWN -> {
val actionIndex = event.actionIndex
leadingPointerId = event.getPointerId(actionIndex)
downX = event.getX(actionIndex)
downY = event.getY(actionIndex)
originOffsetX = offsetX
originOffsetY = offsetY
}
三:有手指抬起
//接力,如果移走的指头时拥有控制权的指头,把控制权交给其他指头
MotionEvent.ACTION_POINTER_UP -> {
val isLeadingPointer = event.findPointerIndex(leadingPointerId) == event.actionIndex
if (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 = offsetX
originOffsetY = offsetY
}
}
1:如果抬起的手指没有图片的控制权,则不做处理
2:如果抬起的手指有图片的控制权
①:如果抬起的这个手指是最后一根,那么就把控制权交给倒数第二根
②:否则交给倒数第一根
3:只有接力时,downX,originOffsetY这些值才更新
package com.lbj23.customview.customview
import 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.getAvatar
class MultiTouchView(context: Context?, attrs: AttributeSet?) : View(context, attrs) {
private val image = getAvatar(resources, R.drawable.bg6, 85.dp.toInt())
private var offsetX = 0f
private var offsetY = 0f
private var originOffsetX = 0f
private var originOffsetY = 0f
private var downX = 0f
private var downY = 0f
private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
private var leadingPointerId = 0
override 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.x
downY = event.y
originOffsetX = offsetX
originOffsetY = offsetY
}
//接力,如果移走的指头时拥有控制权的指头,把控制权交给其他指头
MotionEvent.ACTION_POINTER_UP -> {
val isLeadingPointer = event.findPointerIndex(leadingPointerId) == event.actionIndex
if (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 = offsetX
originOffsetY = offsetY
}
}
//接力,把图片控制权交给刚点击的指头
MotionEvent.ACTION_POINTER_DOWN -> {
val actionIndex = event.actionIndex
leadingPointerId = event.getPointerId(actionIndex)
downX = event.getX(actionIndex)
downY = event.getY(actionIndex)
originOffsetX = offsetX
originOffsetY = offsetY
}
MotionEvent.ACTION_MOVE -> {
val index = event.findPointerIndex(leadingPointerId)
offsetX = event.getX(index) - downX + originOffsetX
offsetY = event.getY(index) - downY + originOffsetY
invalidate()
}
}
return true
}
}
效果展示
很明显只有一根手指拥有对图片的控制权
①:一根手指时,图片只由这一根手指控制
②:多根手指同时按在屏幕上时,由多根手指的几何中心作为一根虚拟的手指操控图片
var sumX = 0f
var sumY = 0f
val isPointerUP = event.actionMasked == MotionEvent.ACTION_POINTER_UP
for (index in 0 until event.pointerCount) {
//如果是抬起就要提前做操作,这时pointerCount还是没减去抬起手指的point数量,所以提前更新好位置
if (!(isPointerUP && index == event.actionIndex)) {
sumX += event.getX(index)
sumY += event.getY(index)
}
}
var pointerCount = event.pointerCount
if (isPointerUP) {
pointerCount--
}
//设置一个几何中心
val focusX = sumX / pointerCount
val 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 = focusX
downY = focusY
originOffsetX = offsetX
originOffsetY = offsetY
}
三:如果是移动,则改变图片偏移,利用几何中心的位置
MotionEvent.ACTION_MOVE -> {
offsetX = focusX - downX + originOffsetX
offsetY = focusY - downY + originOffsetY
invalidate()
}
效果展示
通过观察得出:
①:两根手指滑动时,图片拖动速度比较快
②:一根手指固定,另一根手指滑动,图片拖动速度较慢,为移动的那根手指的半速
package com.lbj23.customview.customview
import 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.getAvatar
class MultiTouchView2(context: Context?, attrs: AttributeSet?) : View(context, attrs) {
private val image = getAvatar(resources, R.drawable.bg6, 150.dp.toInt())
private var offsetX = 0f
private var offsetY = 0f
private var originOffsetX = 0f
private var originOffsetY = 0f
private var downX = 0f
private var downY = 0f
private 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 = 0f
var sumY = 0f
val isPointerUP = event.actionMasked == MotionEvent.ACTION_POINTER_UP
for (index in 0 until event.pointerCount) {
//如果是抬起就要提前做操作,这时pointerCount还是没减去抬起手指的point数量,所以提前更新好位置
if (!(isPointerUP && index == event.actionIndex)) {
sumX += event.getX(index)
sumY += event.getY(index)
}
}
var pointerCount = event.pointerCount
if (isPointerUP) {
pointerCount--
}
//设置一个几何中心
val focusX = sumX / pointerCount
val focusY = sumY / pointerCount
when (event.actionMasked) {
//如果是点击和抬起就更新一下点击位置和原本的位置
MotionEvent.ACTION_DOWN, MotionEvent.ACTION_POINTER_UP, MotionEvent.ACTION_POINTER_DOWN -> {
downX = focusX
downY = focusY
originOffsetX = offsetX
originOffsetY = offsetY
}
//如果是移动,则改变位置,利用几何中心
MotionEvent.ACTION_MOVE -> {
offsetX = focusX - downX + originOffsetX
offsetY = focusY - downY + originOffsetY
invalidate()
}
}
return true
}
}
四:各自为战型,各画各型
这种类型要求我们对每根手指都分开处理
点击详情



