Sobes.tech
Middle

Como determinar se o utilizador clicou numa camada (layer) na aplicação?

sobes.tech IA

Resposta da IA

Para detectar toques em CALayer, podem ser usadas várias abordagens:

  1. Usar hitTest(_:event:) na vista (View):

    • UIView tem o método hitTest(_:with:), que percorre recursivamente a hierarquia de subviews e devolve a subview mais profunda que contém o ponto dado.
    • Este método considera por padrão as camadas relacionadas às vistas.
    • Pode-se sobrescrever hitTest(_:with:) numa vista personalizada para um controlo mais detalhado ou para tratar toques diretamente nas subcamadas que não estão relacionadas com vistas.
  2. Transformar coordenadas usando convert:

    • Ao receber um evento de toque (por exemplo, em métodos de UIView), tens as coordenadas do toque relativamente à janela (UIWindow) ou vista.
    • Para determinar se o toque caiu numa camada específica, precisas de converter essas coordenadas para o sistema de coordenadas dessa camada.
    • Para isso, usam-se os métodos convert(_:from:) ou convert(_:to:) de CALayer.
    • Após a conversão, podes verificar se o ponto está dentro dos limites da camada (bounds) ou usar verificações mais específicas, como contains(_:).
  3. Anexar UITapGestureRecognizer à vista:

    • Podes adicionar um gesto UITapGestureRecognizer à UIView associada à camada.
    • No manipulador do gesto, obter a localização do toque relativamente à vista.
    • Depois, usar o método de conversão de coordenadas (ponto 2) para verificar se o ponto de toque está dentro da camada ou das suas subcamadas.
  4. Criar uma UIView para cada camada interativa:

    • Se tiveres camadas que devem ser interativas, uma forma simples é criar uma UIView para cada uma.
    • Posicioná-la e ajustar o seu tamanho para coincidir com a camada.
    • Adicionar manipuladores de gestos (UITapGestureRecognizer) ou sobrescrever métodos de tratamento de eventos de toque (touchesBegan, touchesEnded, etc.) nessa vista.
    • Esta é a forma mais idiomática de tratar entrada do utilizador no UIKit, pois UIView foi desenhada para isso.

Exemplo de uso de hitTest em UIView:

// Numa vista personalizada
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
    // Converter o ponto de toque para as coordenadas da subcamada
    let pointInLayer = mySublayer.convert(point, from: layer!)
    
    // Verificar se o ponto está dentro dos limites da subcamada
    if mySublayer.contains(pointInLayer) {
        // Se o ponto estiver dentro da subcamada, podemos devolver esta vista ou outra
        // ou realizar as ações necessárias.
        // Neste caso, determinamos que o toque foi "sobre" a subcamada.
        print("Toque em mySublayer")
        // Podemos devolver nil se não quisermos que esta vista trate o toque, ou super.hitTest se quisermos manter o comportamento padrão.
    }
    
    // Permitir que o hitTest padrão trate os outros casos
    return super.hitTest(point, with: event)
}

Exemplo de uso da conversão de coordenadas no manipulador de gesto:

// Numa vista personalizada com UITapGestureRecognizer ligado
@objc func handleTap(_ sender: UITapGestureRecognizer) {
    let tapLocationInView = sender.location(in: self)
    
    // Converter a localização do toque para as coordenadas da subcamada
    let tapLocationInSublayer = mySublayer.convert(tapLocationInView, from: layer!)
    
    // Verificar se o ponto está dentro dos limites da subcamada
    if mySublayer.contains(tapLocationInSublayer) {
        print("Toque em mySublayer")
        // Executar ações relacionadas com o toque na subcamada
    }
}