• Android 多点触控


    三种类型 :接力型 /配合型 /单独型

    单点触控

    1. package com.example.myapplication.view
    2. import android.content.Context
    3. import android.graphics.Canvas
    4. import android.graphics.Paint
    5. import android.util.AttributeSet
    6. import android.view.MotionEvent
    7. import android.view.View
    8. import com.example.myapplication.dp
    9. class MultiTouchView1(context: Context, attrs: AttributeSet) : View(context, attrs) {
    10. private val bitmap = getBitmap()
    11. private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
    12. private var offsetX = 0f //初始位置
    13. private var offsetY = 0f
    14. private var downX = 0f //按下的位置
    15. private var downY = 0f
    16. private var originalOffsetX = 0f //偏移位置
    17. private var originalOffsetY = 0f
    18. override fun onDraw(canvas: Canvas) {
    19. super.onDraw(canvas)
    20. canvas.drawBitmap(bitmap, offsetX, offsetY, paint)
    21. }
    22. override fun onTouchEvent(event: MotionEvent): Boolean {
    23. when (event.actionMasked) {
    24. MotionEvent.ACTION_DOWN -> {
    25. downX = event.x
    26. downY = event.y
    27. originalOffsetX = offsetX
    28. originalOffsetY = offsetY
    29. }
    30. MotionEvent.ACTION_MOVE -> {
    31. offsetX = event.x - downX + originalOffsetX
    32. offsetY = event.y - downY + originalOffsetY
    33. invalidate()
    34. }
    35. }
    36. return true
    37. }
    38. }

    触摸事件序列是针对View而不是手指

    x,y ,index ,id 属于一个point ,一个序列,getX 获取index为0的手指位置

    1. public final float getX() {
    2. return nativeGetAxisValue(mNativePtr, AXIS_X, 0, HISTORY_CURRENT);
    3. }

    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查找

    1. MotionEvent.ACTION_MOVE -> {
    2. event.getX(event.actionIndex) //正在按下手指的ID
    3. event.getX(event.findPointerIndex(downId)) //通过ID获取
    4. }

    action_move 不适合这种方法,因为在实时移动 更新,没有所谓的Point 也就是index ,id,只有在down / up 才有意义

    接力型

    1. package com.example.myapplication.view
    2. import android.content.Context
    3. import android.graphics.Canvas
    4. import android.graphics.Paint
    5. import android.util.AttributeSet
    6. import android.view.MotionEvent
    7. import android.view.View
    8. import com.example.myapplication.dp
    9. class MultiTouchView1(context: Context, attrs: AttributeSet) : View(context, attrs) {
    10. private val bitmap =getBitmap()
    11. private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
    12. private var offsetX = 0f //初始位置
    13. private var offsetY = 0f
    14. private var downX = 0f //按下的位置
    15. private var downY = 0f
    16. private var originalOffsetX = 0f //偏移位置
    17. private var originalOffsetY = 0f
    18. private var trackingPointerId = 0 //当前按下的手指ID
    19. override fun onDraw(canvas: Canvas) {
    20. super.onDraw(canvas)
    21. canvas.drawBitmap(bitmap, offsetX, offsetY, paint)
    22. }
    23. override fun onTouchEvent(event: MotionEvent): Boolean {
    24. when (event.actionMasked) {
    25. MotionEvent.ACTION_DOWN -> {
    26. trackingPointerId = event.getPointerId(0)
    27. downX = event.x
    28. downY = event.y
    29. originalOffsetX = offsetX
    30. originalOffsetY = offsetY
    31. }
    32. //多个
    33. MotionEvent.ACTION_POINTER_DOWN -> {
    34. val actionIndex = event.actionIndex
    35. trackingPointerId = event.getPointerId(actionIndex) //按下的手指序号获取ID
    36. //更新 接管
    37. downX = event.getX(actionIndex)
    38. downY = event.getY(actionIndex)
    39. originalOffsetX = offsetX
    40. originalOffsetY = offsetY
    41. }
    42. MotionEvent.ACTION_POINTER_UP -> {
    43. val actionIndex = event.actionIndex
    44. val pointerId = event.getPointerId(actionIndex)
    45. if (pointerId == trackingPointerId) {
    46. //如果是正在跟踪的手指 进行替换
    47. val newIndex = if (actionIndex == event.pointerCount - 1) {
    48. event.pointerCount - 2
    49. } else {
    50. event.pointerCount - 1
    51. }
    52. trackingPointerId = event.getPointerId(newIndex) //按下的手指序号获取ID
    53. //更新 接管
    54. downX = event.getX(newIndex)
    55. downY = event.getY(newIndex)
    56. originalOffsetX = offsetX
    57. originalOffsetY = offsetY
    58. }
    59. }
    60. MotionEvent.ACTION_MOVE -> {
    61. val index = event.findPointerIndex(trackingPointerId)
    62. offsetX = event.getX(index) - downX + originalOffsetX
    63. offsetY = event.getY(index) - downY + originalOffsetY
    64. invalidate()
    65. }
    66. }
    67. return true
    68. }
    69. }

    配合型:

    1. package com.example.myapplication.view
    2. import android.content.Context
    3. import android.graphics.Canvas
    4. import android.graphics.Paint
    5. import android.util.AttributeSet
    6. import android.view.MotionEvent
    7. import android.view.View
    8. import com.example.myapplication.dp
    9. import com.example.myapplication.getAvatar
    10. //双指滑动
    11. class MultiTouchView2(context: Context, attrs: AttributeSet) : View(context, attrs) {
    12. private val bitmap = getAvatar(resources, 200.dp.toInt())
    13. private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
    14. private var offsetX = 0f //初始位置
    15. private var offsetY = 0f
    16. private var downX = 0f //按下的位置
    17. private var downY = 0f
    18. private var originalOffsetX = 0f //偏移位置
    19. private var originalOffsetY = 0f
    20. override fun onDraw(canvas: Canvas) {
    21. super.onDraw(canvas)
    22. canvas.drawBitmap(bitmap, offsetX, offsetY, paint)
    23. }
    24. override fun onTouchEvent(event: MotionEvent): Boolean {
    25. val focusX : Float//焦点 两值相加 /2
    26. val focusY : Float
    27. var pointerCount = event.pointerCount
    28. var sumX = 0f
    29. var sumY = 0f
    30. val inPointerUp = event.actionMasked == MotionEvent.ACTION_POINTER_UP //如果是抬起
    31. for (i in 0 until pointerCount){
    32. if (!(inPointerUp && i == event.actionIndex)){ //当前位置并且不是抬起 则计算
    33. sumX += event.getX(i) //得到每个点的坐标
    34. sumY += event.getY(i)
    35. }
    36. }
    37. if (inPointerUp){
    38. pointerCount -- //处理额外偏移
    39. }
    40. focusX = sumX / pointerCount //得到焦点值 当抬起后count会变
    41. focusY = sumY /pointerCount
    42. when (event.actionMasked) {
    43. MotionEvent.ACTION_DOWN,MotionEvent.ACTION_POINTER_DOWN, MotionEvent.ACTION_POINTER_UP -> {
    44. downX = focusX
    45. downY = focusY
    46. originalOffsetX = offsetX
    47. originalOffsetY = offsetY
    48. }
    49. MotionEvent.ACTION_MOVE -> {
    50. offsetX = focusX - downX + originalOffsetX
    51. offsetY = focusY - downY + originalOffsetY
    52. invalidate()
    53. }
    54. }
    55. return true
    56. }
    57. }

    多指

    1. package com.example.myapplication.view
    2. import android.content.Context
    3. import android.graphics.Canvas
    4. import android.graphics.Paint
    5. import android.graphics.Path
    6. import android.util.AttributeSet
    7. import android.util.SparseArray
    8. import android.view.MotionEvent
    9. import android.view.View
    10. import androidx.core.util.isEmpty
    11. import com.example.myapplication.dp
    12. class MultiTouchView3(context: Context, attrs: AttributeSet) : View(context, attrs) {
    13. private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
    14. private var paths = SparseArray<Path>()
    15. init {
    16. paint.style = Paint.Style.STROKE
    17. paint.strokeWidth = 4.dp
    18. paint.strokeCap = Paint.Cap.ROUND
    19. paint.strokeJoin = Paint.Join.ROUND
    20. }
    21. override fun onDraw(canvas: Canvas) {
    22. super.onDraw(canvas)
    23. for (i in 0 until paths.size()){
    24. val path = paths.valueAt(i)
    25. canvas.drawPath(path,paint)
    26. }
    27. }
    28. override fun onTouchEvent(event: MotionEvent): Boolean {
    29. when(event.actionMasked){
    30. MotionEvent.ACTION_DOWN,MotionEvent.ACTION_POINTER_DOWN ->{
    31. val actionIndex = event.actionIndex
    32. val path = Path()
    33. path.moveTo(event.getX(actionIndex),event.getY(actionIndex))
    34. paths.append(event.getPointerId(actionIndex),path)
    35. invalidate()
    36. }
    37. MotionEvent.ACTION_MOVE ->{
    38. if (!paths.isEmpty()){
    39. for (i in 0 until paths.size()){
    40. val pointerId = event.getPointerId(i)
    41. val path = paths.get(pointerId)
    42. path.lineTo(event.getX(i),event.getY(i))
    43. }
    44. invalidate()
    45. }
    46. }
    47. MotionEvent.ACTION_UP,MotionEvent.ACTION_POINTER_UP -> {
    48. val actionIndex = event.actionIndex
    49. val pointerId = event.getPointerId(actionIndex)
    50. paths.remove(pointerId)
    51. invalidate()
    52. }
    53. }
    54. return true
    55. }
    56. }

  • 相关阅读:
    Web 后端的一生之敌:分页器
    案例解读华为隐私计算产品TICS如何实现城市跨部门数据隐私计算
    node.js的模块
    GCN 链结预测 负采样 想要请教链结预测当中的负采样问题
    产品代码都给你看了,可别再说不会DDD(六):聚合根与资源库
    代码随想录算法训练营第四十一天|卡码网46. 携带研究材料(第六期模拟笔试)、416. 分割等和子集
    Pytest插件
    上周热点回顾(7.17-7.23)
    学习大数据可以进入哪些公司?
    C# 读取Execl文件3种方法
  • 原文地址:https://blog.csdn.net/qq_29769851/article/details/134261668