Existe uma maneira simples de permitir a interação com um botão em um UIView que fica sob outro UIView - onde não há objetos reais do UIView superior na parte superior do botão?
Por exemplo, no momento eu tenho um UIView (A) com um objeto na parte superior e um objeto na parte inferior da tela e nada no meio. Ele fica em cima de outro UIView que tem botões no meio (B). No entanto, não consigo interagir com os botões no meio de B.
Eu posso ver os botões em B - eu defini o plano de fundo de A para clearColor - mas os botões em B não parecem receber toques, apesar do fato de que não há objetos de A realmente no topo desses botões.
EDITAR - Eu ainda quero ser capaz de interagir com os objetos no UIView superior
Certamente existe uma maneira simples de fazer isso?
fonte
UIButton
que está sob uma semitransparente,UIView
enquanto a parte não transparente doUIView
ainda responderá aos eventos de toque.Respostas:
Você deve criar uma subclasse UIView para sua vista superior e substituir o seguinte método:
Você também pode consultar o método hitTest: event:.
fonte
return
declaração está fazendo, masreturn CGRectContainsPoint(eachSubview.frame, point)
funciona para mim. Resposta extremamente útil caso contrárioMIDDLE_Y1<=y<=MIDDLE_Y2
área.Embora muitas das respostas aqui funcionem, estou um pouco surpreso ao ver que a resposta mais conveniente, genérica e infalível não foi dada aqui. @Ash chegou mais perto, exceto que há algo estranho acontecendo com o retorno do superview ... não faça isso.
Esta resposta foi retirada de uma resposta que dei a uma pergunta semelhante, aqui .
[super hitTest:point withEvent:event]
retornará a visão mais profunda na hierarquia dessa visão que foi tocada. SehitView == self
(ou seja, se não houver subvisualização sob o ponto de toque), retornenil
, especificando que esta visualização não deve receber o toque. A maneira como a cadeia de resposta funciona significa que a hierarquia de visualização acima desse ponto continuará a ser percorrida até que seja encontrada uma visualização que responda ao toque. Não devolva o superview, pois não cabe a ele se o superview deve aceitar toques ou não!Esta solução é:
pointInside:withEvent:
para retornar uma área tocável específica).Eu uso isso com freqüência suficiente para abstrair em uma subclasse para salvar subclasses de visão sem sentido para uma substituição. Como bônus, adicione uma propriedade para torná-la configurável:
Então vá à loucura e use esta visualização onde quer que você possa usar uma planície
UIView
. Configurá-lo é tão simples quanto definironlyRespondToTouchesInSubviews
paraYES
.fonte
Existem várias maneiras de lidar com isso. Meu favorito é substituir hitTest: withEvent: em uma visão que é uma visão geral comum (talvez indiretamente) para as visões conflitantes (parece que você as chama de A e B). Por exemplo, algo assim (aqui A e B são ponteiros UIView, onde B é o "oculto", que normalmente é ignorado):
Você também pode modificar o
pointInside:withEvent:
método como gyim sugerido. Isso permite que você alcance essencialmente o mesmo resultado efetivamente "abrindo um buraco" em A, pelo menos para tocar.Outra abordagem é o encaminhamento de evento, o que significa substituir
touchesBegan:withEvent:
métodos semelhantes (comotouchesMoved:withEvent:
etc) para enviar alguns toques para um objeto diferente daquele onde foram inicialmente. Por exemplo, em A, você poderia escrever algo assim:No entanto, isso nem sempre funcionará da maneira que você espera! O principal é que os controles embutidos como o UIButton sempre irão ignorar os toques encaminhados. Por causa disso, a primeira abordagem é mais confiável.
Há uma boa postagem no blog explicando tudo isso com mais detalhes, junto com um pequeno projeto xcode funcional para demonstrar as ideias, disponível aqui:
http://bynomial.com/blog/?p=74
fonte
Você tem que definir
upperView.userInteractionEnabled = NO;
, caso contrário, a vista superior interceptará os toques.A versão do Interface Builder é uma caixa de seleção na parte inferior do painel View Attributes chamada "User Interaction Enabled". Desmarque-a e você estará pronto para ir.
fonte
Implementação personalizada de pointInside: withEvent: de fato parecia o caminho a seguir, mas lidar com coordenadas codificadas parecia estranho para mim. Então acabei verificando se o CGPoint estava dentro do botão CGRect usando a função CGRectContainsPoint ():
fonte
Ultimamente eu escrevi uma aula que vai me ajudar exatamente nisso. Usando-o como uma classe personalizada para um
UIButton
ouUIView
irá passar eventos de toque que foram executados em um pixel transparente.Esta solução é um pouco melhor do que a resposta aceita porque você ainda pode clicar em um
UIButton
que está sob um semitransparente,UIView
enquanto a parte não transparente doUIView
ainda responderá a eventos de toque.Como você pode ver no GIF, o botão Giraffe é um retângulo simples, mas os eventos de toque nas áreas transparentes são passados para o amarelo
UIButton
abaixo.Link para a aula
fonte
Acho que estou um pouco atrasado para esta festa, mas acrescentarei esta possível solução:
Se você usar este código para substituir a função hitTest padrão de um UIView personalizado, ele ignorará SOMENTE a própria visualização. Quaisquer subvisualizações dessa visão retornarão seus resultados normalmente, e quaisquer acessos que teriam ido para a própria visão são passados para sua supervisão.
-Cinza
fonte
[self superview]
. a documentação sobre este método afirma "Retorna o descendente mais distante do receptor na hierarquia de exibição (incluindo ele mesmo) que contém um ponto especificado" e "Retorna nulo se o ponto estiver completamente fora da hierarquia de exibição do receptor". Eu acho que você deveria voltarnil
. quando você retornar nil, o controle passará para o supervisualizador para que ele verifique se há ocorrências ou não. então, basicamente, ele fará a mesma coisa, exceto que retornar o superview pode interromper algo no futuro.Estou apenas revisando a Resposta Aceita e colocando isso aqui para minha referência. A resposta aceita funciona perfeitamente. Você pode estendê-lo assim para permitir que as subvisualizações de sua visualização recebam o toque OU passá-lo para quaisquer visualizações atrás de nós:
Nota: Você nem mesmo precisa fazer recursão na árvore de subvisualização, porque cada
pointInside:withEvent:
método cuidará disso para você.fonte
A configuração da propriedade userInteraction desabilitada pode ajudar. Por exemplo:
(Observação: no código acima, 'self' se refere a uma visualização)
Dessa forma, você só pode exibir no topView, mas não obterá entradas do usuário. Todos os toques do usuário passarão por essa visualização e a visualização inferior responderá por eles. Eu usaria este topView para exibir imagens transparentes ou para animá-las.
fonte
Essa abordagem é bastante limpa e permite que subvisualizações transparentes também não reajam aos toques. Basta
UIView
criar uma subclasse e adicionar o seguinte método à sua implementação:fonte
Minha solução aqui:
Espero que isto ajude
fonte
Há algo que você pode fazer para interceptar o toque em ambas as visualizações.
Vista do topo:
Mas essa é a ideia.
fonte
Aqui está uma versão Swift:
fonte
Swift 3
fonte
Nunca construí uma interface de usuário completa usando o kit de ferramentas de IU, então não tenho muita experiência com ele. Aqui está o que eu acho que deve funcionar.
Cada UIView, e esta a UIWindow, tem uma propriedade
subviews
, que é um NSArray contendo todas as subvisualizações.A primeira subvisualização adicionada a uma visão receberá o índice 0, e a próxima índice 1 e assim por diante. Você também pode substituir
addSubview:
porinsertSubview: atIndex:
ouinsertSubview:aboveSubview:
e esses métodos que podem determinar a posição de sua subvisão na hierarquia.Portanto, verifique seu código para ver qual visualização você adiciona primeiro à sua UIWindow. Esse será 0, o outro será 1.
Agora, a partir de uma de suas subvisões, para chegar a outra, você faria o seguinte:
Deixe-me saber se isso funciona para o seu caso!
(abaixo deste marcador está minha resposta anterior):
Se as visualizações precisam se comunicar umas com as outras, elas devem fazer isso por meio de um controlador (ou seja, usando o modelo MVC popular ).
Ao criar uma nova visualização, você pode ter certeza de que ela se registrará em um controlador.
Portanto, a técnica é garantir que suas visualizações sejam registradas em um controlador (que pode armazená-las por nome ou o que você preferir em um Dicionário ou Array). Você pode fazer com que o controlador envie uma mensagem para você ou pode obter uma referência para a visualização e se comunicar diretamente com ela.
Se sua visão não tem um link de volta para o controlador (o que pode ser o caso), então você pode usar singletons e / ou métodos de classe para obter uma referência para seu controlador.
fonte
Acho que a maneira certa é usar a cadeia de visualização incorporada à hierarquia de visualização. Para suas subvisualizações que são enviadas para a exibição principal, não use o UIView genérico, mas, em vez disso, subclasse UIView (ou uma de suas variantes como UIImageView) para fazer MYView: UIView (ou qualquer supertipo que você desejar, como UIImageView). Na implementação de YourView, implemente o método touchesBegan. Este método será invocado quando essa visualização for tocada. Tudo que você precisa ter nessa implementação é um método de instância:
este touchBegan é uma api respondente, então você não precisa declará-lo em sua interface pública ou privada; é uma daquelas APIs mágicas que você precisa conhecer. Este self.superview irá borbulhar a solicitação eventualmente para o viewController. No viewController, então, implemente este touchesBegan para lidar com o toque.
Observe que a localização dos toques (CGPoint) é automaticamente ajustada em relação à visão abrangente para você, à medida que é rebatida para cima na cadeia de hierarquia da visão.
fonte
Só quero postar isso, porque eu tive um problema semelhante, passei uma quantidade substancial de tempo tentando implementar respostas aqui sem sorte. O que acabei fazendo:
e implementando
UIGestureRecognizerDelegate
:A vista inferior era um controlador de navegação com um número de segues e eu tinha uma espécie de porta em cima dele que poderia fechar com o gesto panorâmico. A coisa toda estava embutida em outro VC. Funcionou como um encanto. Espero que isto ajude.
fonte
Implementação de Swift 4 para solução baseada em HitTest
fonte
Derivado da resposta excelente e principalmente infalível de Stuart e da implementação útil do Segev, aqui está um pacote Swift 4 que você pode colocar em qualquer projeto:
E então com hitTest:
fonte