三种类型 :接力型 /配合型 /单独型
单点触控
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}
}