Visualização personalizada: multitoque (1) - relé de dedo

Este artigo é uma série de artigos
com uma imagem que desliza com o dedo –
visualização personalizada com um único toque: multitoque (1) –
visualização personalizada de retransmissão de dedo: multitoque (2) –
visualização personalizada de colaboração com vários dedos: Multi- toque (3) – lutando entre si

O multitoque pode ser dividido em três tipos:

  1. tipo de relé
  2. Colaborativo
  3. lutar entre si

Então, qual das opções acima é a operação padrão com vários dedos? Infelizmente, não é. Podemos executar o que dissemos no artigo anterior, uma imagem arrastável , que não lida com operações com vários dedos. Quando nós dois Quando dois dedos operam ao mesmo tempo, você descobrirá que o efeito é o seguinte: o primeiro dedo funciona normalmente, o segundo dedo é colocado e começa a deslizar, mas não há resposta, somente quando o primeiro dedo é removido, o segundo operação de resposta do dedo, quando o primeiro dedo é colocado para trás, o segundo dedo torna-se inválido imediatamente, respondendo diretamente à operação do primeiro dedo

Por que isso acontece? Antes de falar sobre isso, vamos falar sobre um conceito, a sequência de eventos para operações com um único dedo.

Uma sequência mais simples de eventos geralmente se parece com isto

ACTION_DOWN
ACTION_MOVE
ACTION_MOVE
ACTION_MOVE
ACTION_MOVE
ACTION_MOVE
ACTION_MOVE
ACTION_MOVE
ACTION_MOVE
ACTION_UP

Desde pressionar até levantar, é contado como um evento, e ACTION_MOVE será acionado várias vezes, porque mesmo que você pense que não está se movendo, na verdade, até mesmo um leve tremor na tela será acionado

Existe outro tipo de ACTION_CANNEL que não é discutido, pois não é acionado pelo usuário, mas sim pela View pai. Quando o evento é roubado pela View pai, ele irá acionar o ACTION_CANNEL da View roubada , que é para permitir a criança Ver cuidar do funeral, ou seja, limpar a bunda

Então, qual é a sequência de eventos para operações com vários dedos?

ACTION_DOWN
ACTION_MOVE
ACTION_MOVE
ACTION_POINTER_DOWN
ACTION_MOVE
ACTION_MOVE
ACTION_POINTER_DOWN
ACTION_MOVE
ACTION_POINTER_UP
ACTION_MOVE
ACTION_POINTER_UP
ACTION_MOVE
ACTION_MOVE
ACTION_UP

Cada dedo extra terá um par de ACTION_POINTER_DOWN e ACTION_POINTER_UP

Observe que cada uma das sequências acima é da perspectiva de uma Visualização, não da perspectiva de dedos diferentes

Vários dedos da mesma Visualização estarão na mesma sequência de eventos, conforme descrito acima

Cada evento corresponde a uma coordenada, e o evento é acionado por um dedo, que corresponde a um ponto, também é direcionado à Vista na perspectiva da Vista.

Então, como você distingue entre diferentes dedos?

ACTION_DOWN		p(x,y,index,id)
ACTION_MOVE		p(x,y,index,id)
ACTION_MOVE		p(x,y,index,id)
ACTION_POINTER_DOWN		p(x,y,index,id)		p(x,y,index,id)
ACTION_MOVE		p(x,y,index,id)		p(x,y,index,id)
ACTION_MOVE		p(x,y,index,id)		p(x,y,index,id)
ACTION_POINTER_DOWN
ACTION_MOVE
ACTION_POINTER_UP
ACTION_MOVE
ACTION_POINTER_UP
ACTION_MOVE
ACTION_MOVE
ACTION_UP

Olhando para o conjunto de sequências acima, quando há um **p() , significa que esta View tem um dedo operando, e quando há dois p()**, significa que há dois dedos operando

O código acima foi modificado com base na operação com um único dedo do artigo anterior

import android.content.Context
import android.graphics.BitmapFactory
import android.graphics.Canvas
import android.graphics.Paint
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import com.example.viewtest.R

class MultiTouchView(context: Context, attrs: AttributeSet?) : View(context, attrs) {
    
    

    private val bitmap = BitmapFactory.decodeResource(resources, R.drawable.ic_choice_select)
    private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
    private var offsetX = 0f
    private var offsetY = 0f
    private var downX = 0f
    private var downY = 0f
    private var originOffsetX = 0f
    private var originOffsetY = 0f

    override 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.x
                downY = event.y
            }
            MotionEvent.ACTION_MOVE -> {
    
    
                // 记录最新的手指位置
                offsetX = event.x - downX + originOffsetX
                offsetY = event.y - downY + originOffsetY
                // 触发重绘
                invalidate()
            }
            MotionEvent.ACTION_UP -> {
    
    
                originOffsetX = offsetX
                originOffsetY = offsetY
            }
        }
        return true
    }
}

As coisas a serem observadas aqui são:

	override fun onTouchEvent(event: MotionEvent?): Boolean {
    
    
        when (event?.actionMasked) {
    
    
        }
    }

Use event?.actionMasked para lidar com eventos de operação com vários dedos

    override fun onTouchEvent(event: MotionEvent?): Boolean {
    
    
        when (event?.actionMasked) {
    
    
            MotionEvent.ACTION_DOWN -> {
    
    
                trackingPointerId = event.getPointerId(0)
                // 记录手指按下的坐标
                downX = event.x
                downY = event.y
            }
            // 新增的手指按下会触发
            MotionEvent.ACTION_POINTER_DOWN -> {
    
    
                val actionIndex = event.actionIndex
                trackingPointerId = event.getPointerId(actionIndex)
                // 记录新手指按下的坐标
                downX = event.getX(actionIndex)
                downY = event.getY(actionIndex)

                originOffsetX = offsetX
                originOffsetY = offsetY
            }
            MotionEvent.ACTION_MOVE -> {
    
    
                val index = event.findPointerIndex(trackingPointerId)
                // 记录最新的手指位置
                offsetX = event.getX(index) - downX + originOffsetX
                offsetY = event.getY(index) - downY + originOffsetY
                // 触发重绘
                invalidate()
            }
            MotionEvent.ACTION_UP -> {
    
    
                originOffsetX = offsetX
                originOffsetY = offsetY
            }
        }
        return true
    }

Aqui, olhamos apenas para o código relevante de onTouchEvent . Aqui, o tipo ACTION_POINTER_UP é adicionado e, em seguida, todas as aquisições de coordenadas são alteradas para usar getX ou getY . O índice padrão escrito antes é na verdade 0, e o índice atual é obtido por meio de id . , que explica a função de todos os parâmetros no conjunto de sequência de eventos

Até agora, corremos, e o evento de aquisição do segundo dedo é bom

Então precisamos lidar com a operação de levantar o não-último dedo. Na verdade, tratamos de pressionar ou levantar o não-primeiro dedo. Considerado

	override fun onTouchEvent(event: MotionEvent?): Boolean {
    
    
        when (event?.actionMasked) {
    
    
            ......
            // 当前 view 上所剩手指大于 1 时,有手指抬起会触发
            MotionEvent.ACTION_POINTER_UP -> {
    
    
                val actionIndex = event.actionIndex
                val pointerId = event.getPointerId(actionIndex)
                // 判断抬起手指的 ID 是否是正在操作的手指 ID,如果是,则需要选一根手指来接管操作
                if (pointerId == trackingPointerId) {
    
    
                    // 需要选一根手指来接管操作,具体选哪个手指,需要我们自己写算法,这里选最后一根手指
                    // 注意,这个时候去获取当前View的所有手指的时候,是包括当前正在抬起的手指的
                    // 如果抬起的手指就是最后一根手指,那么我自己是不可能接棒我自己的
                    val newIndex = if (actionIndex == event.pointerCount - 1) {
    
    
                        event.pointerCount - 2
                    } else {
    
    
                        event.pointerCount - 1
                    }

                    trackingPointerId = event.getPointerId(newIndex)

                    downX = event.getX(newIndex)
                    downY = event.getY(newIndex)

                    originOffsetX = offsetX
                    originOffsetY = offsetY
                }

            }
            .....
        }
        return true
    }

Ainda observe o método onTouchEvent, aqui observe apenas o evento ACTION_POINTER_UP, veja a descrição do comentário

Corre para ver o resultado:

  1. O primeiro dedo é pressionado para se mover, o segundo dedo é pressionado para se mover, o segundo dedo assume o controle suavemente, o primeiro dedo falha, o primeiro dedo é levantado primeiro e os dedos restantes ainda estão operando normalmente, sem problemas
  2. O primeiro dedo é pressionado para se mover, o segundo dedo é pressionado para se mover, o segundo dedo assume o controle suavemente, o primeiro dedo falha, o segundo dedo é levantado primeiro e os dedos restantes ainda estão operando normalmente, sem problemas

Realize perfeitamente o primeiro tipo de operação com vários dedos, o tipo de relé

Acho que você gosta

Origin blog.csdn.net/qq_35178391/article/details/132700645
Recomendado
Clasificación