栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

多点触控 Android 自定义控件

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

多点触控 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.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
    }
}
效果展示


很明显只有一根手指拥有对图片的控制权

二、协作型 思路

①:一根手指时,图片只由这一根手指控制
②:多根手指同时按在屏幕上时,由多根手指的几何中心作为一根虚拟的手指操控图片

code 一:在onTouchEvent中,在判断各种事件之前,先找到几何中心,找到那个虚拟出来的拥有图片控制权的手指的x,y坐标
        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
    }
}
四:各自为战型,各画各型

这种类型要求我们对每根手指都分开处理
点击详情

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/298235.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号