Adicione uma UIView acima de tudo, até a barra de navegação

181

Quero exibir, acima de qualquer outra visualização, até a barra de navegação, um tipo de visualização "pop-up" que se parece com isso:

  • fundo preto de tela cheia com um alfa de 0,5 para ver o outro UIViewControllerpor baixo.
  • uma UIViewjanela no meio com algumas informações (um calendário, se você quiser saber tudo).

Para fazer isso, criei um UIViewController que contém os dois UIViews(plano de fundo e janela) e estou tentando exibi-lo. Eu tentei um simples [mySuperVC addSubview:myPopUpVC.view], mas ainda tenho a barra de navegação acima.

Tentei apresentá-lo como modal, mas o que está UIViewControllerpor baixo desaparece e perco meu efeito de transparência.

Alguma idéia para fazer isso, tenho certeza que é bem simples ...

Obrigado!

Nicolas Roy
fonte
Adicione uma subvisão na janela do seu aplicativo. Manipulação de alterações de orientação pode ser complicada: stackoverflow.com/questions/8774495/…
Amar

Respostas:

197

Você pode fazer isso adicionando sua visualização diretamente à keyWindow:

UIView *myView = /* <- Your custom view */;
UIWindow *currentWindow = [UIApplication sharedApplication].keyWindow;
[currentWindow addSubview:myView];

UPDATE - Para Swift 4.1 e superior

let currentWindow: UIWindow? = UIApplication.shared.keyWindow
currentWindow?.addSubview(myView)
ROM.
fonte
2
Obrigado :) Infelizmente, se você estiver no modo paisagem, precisará girar a exibição. Não sei se sei fazer isso corretamente.
Nicolas Roy
Sim, estou apenas no modo paisagem e o myView aparece com uma rotação de 90 graus. Parece ser o que eles estão falando aqui: stackoverflow.com/questions/8774495/…
Nicolas Roy
O problema de orientação ocorre em dispositivos pré-iOS8, para os quais essa solução infelizmente não funciona.
Thgc
@NicolasRoy Autolayout irá ajudar
Darmen Amanbayev
4
não cobre a barra da guia. Alguma solução para isso?
Manisha
134

[self.navigationController.view addSubview:overlayView]; é o que você realmente quer

dalef
fonte
5
Você precisa definir o quadro
Gabriel Goncalves
1
Muito boa solução, especialmente, quando você adiciona um vista como um "controlador de vista da criança"
Richard Topchii
2
Isso não funciona com a visão de um controlador de exibição filho. A alteração do nível z da barra de navegação (como sugere o Nam) também funciona com os controladores de exibição infantil.
Tapani
Parece uma solução mais elegante do que adicionar vista à janela Chave. Como isso garante uma visualização adicional, move-se ao longo da animação da visualização base. Como se a exibição for adicionada na janela da chave, ela não será fornecida com animação e deverá ser removida separadamente se você quiser descartar o controlador.
soan Saini
não acabou, mas é a coisa certa para o meu caso. Obrigado))
Dilshod Zopirov 08/02/19
112

Aqui está uma solução simples e elegante que está funcionando para mim. Você pode definir a posição z da barra de navegação abaixo da visualização:

self.navigationController.navigationBar.layer.zPosition = -1;

Lembre-se de configurá-lo novamente para 0 quando terminar.

Nam
fonte
1
Isso funciona muito melhor do que adicionar a visualização de sobreposição como uma subvisão à visualização do controlador de navegação (que, a propósito, causa uma falha). Essa solução da posição z provavelmente é muito mais confiável e causa menos problemas no futuro.
Tapani
Isso funciona muito bem quando se trabalha com storyboards. Você pode adicionar a vista dentro do storyboard!
Jos Koomen 30/05
Funciona muito bem para mim também. Seria ótimo mencionar que o zPosition deve voltar ao valor 0 (você acabou de mencionar que deve voltar ao final). E eu tenho tabBar (de TabBarController na minha tela também. Tentei definir zPosition, mas ao retornar ao valor 0, tabBar ainda não estava visível. Portanto, para tabBar, é melhor usar a propriedade isHidden.
Libor Zapletal
1
Não trabalhe com acessibilidade. O movimento panorâmico sobre a vista não o focalizará.
antonjn
Eu te amo!! <3
chr0x 20/03
57

Versões Swift para a resposta verificada:

Swift 4:

let view = UIView()
view.frame = UIApplication.shared.keyWindow!.frame
UIApplication.shared.keyWindow!.addSubview(view)

Swift 3.1:

let view = UIView()
view.frame = UIApplication.sharedApplication().keyWindow!.frame 
UIApplication.sharedApplication().keyWindow!.addSubview(view)
Kevin ABRIOUX
fonte
6
Posso fazer com que essa cobertura abranja todas as visualizações atuais (controlador de exibição), mas deixe o novo controlador de exibição exibido acima dele?
Michał Ziobro
24

Adicione você visualizar como a subvisão do NavigationController.

[self.navigationController.navigationBar addSubview: overlayView)]

Você também pode adicioná-lo sobre a janela:

UIView *view = /* Your custom view */;
UIWindow *window = [UIApplication sharedApplication].keyWindow;
[window addSubview:view];

Espero que isto ajude.. :)

Rashad
fonte
Sobre a vista está chegando, mas, quando adicionar um botão não poderia entrar em ação botão ou conjunto de texto de rótulo personalizado na visão geral
Vineesh TP
Funciona bem para mim:let navigationBar = viewController.navigationController!.navigationBar navigationBar.addSubview(coverView)
Arthur Clemens
22

Dalef ótima solução em rápida:

self.navigationController?.view.addSubview(view)
Allreadyhome
fonte
11

A resposta do @ Nam funciona muito bem se você apenas deseja exibir sua visualização personalizada, mas se ela precisar de interação do usuário, será necessário desativar a interação para onavigationBar .

self.navigationController.navigationBar.layer.zPosition = -1
self.navigationController.navigationBar.isUserInteractionEnabled = false

Como dito na resposta de Nam, não se esqueça de reverter essas mudanças:

self.navigationController.navigationBar.layer.zPosition = 0
self.navigationController.navigationBar.isUserInteractionEnabled = true


Você pode fazer isso de uma maneira melhor com uma extensão:

extension UINavigationBar {
    func toggle() {
        if self.layer.zPosition == -1 {
            self.layer.zPosition = 0
            self.isUserInteractionEnabled = true
        } else {
            self.layer.zPosition = -1
            self.isUserInteractionEnabled = false
        }
    }
}

E simplesmente use-o assim:

self.navigationController.navigationBar.toggle()
Hemang
fonte
1
solução perfeita .. !! Tentei tantas coisas e gastei muito tempo .. mas isso funciona bem .. !!
Dishant
8

Versão rápida da resposta de @Nicolas Bonnet:

    var popupWindow: UIWindow?

func showViewController(controller: UIViewController) {
    self.popupWindow = UIWindow(frame: UIScreen.mainScreen().bounds)
    controller.view.frame = self.popupWindow!.bounds
    self.popupWindow!.rootViewController = controller
    self.popupWindow!.makeKeyAndVisible()
}

func viewControllerDidRemove() {
    self.popupWindow?.removeFromSuperview()
    self.popupWindow = nil
}

Não esqueça que a janela deve ser uma propriedade forte, porque a resposta original leva a uma desalocação imediata da janela

Unidade iOS
fonte
6

Eu recomendo que você crie uma nova UIWindow:

UIWindow *window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
window.rootViewController = viewController;
window.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
window.opaque = NO;
window.windowLevel = UIWindowLevelCFShareCircle;
window.backgroundColor = [UIColor clearColor];

[window makeKeyAndVisible];

Em seguida, você pode gerenciar sua exibição em outro UIViewController. Para remover as janelas:

[window removeFromSuperview];
window = nil;

espero que ajude!

Nicolas Bonnet
fonte
3
Obrigado, mas acho que algo está faltando, porque nada aparece: /
Nicolas Roy
6

Há mais de uma maneira de fazer isso:

1- Adicione seu UIViewon em UIWindowvez de adicioná-lo UIViewController. Desta forma, estará em cima de tudo.

   [[(AppDelegate *)[UIApplication sharedApplication].delegate window] addSubview:view];

2- Use uma transição personalizada que manterá seu UIViewController aparecendo na parte de trás com um alfa de 0,5

Para isso, recomendo que você analise o seguinte: https://github.com/Citrrus/BlurryModalSegue

Dani A
fonte
4
[[UIApplication sharedApplication].windows.lastObject addSubview:myView];
jold
fonte
3

No Swift 4.2 e no Xcode 10

var spinnerView: UIView? //This is your view

spinnerView = UIView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height))
//Based on your requirement change width and height like self.view.bounds.size.width
spinnerView?.backgroundColor = UIColor.black.withAlphaComponent(0.6)
//        self.view.addSubview(spinnerView)
let currentWindow: UIWindow? = UIApplication.shared.keyWindow
currentWindow?.addSubview(spinnerView!)

No objetivo C

UIView * spinnerView; // Esta é a sua opinião

self.spinnerView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, UIScreen.mainScreen.bounds.size.width, UIScreen.mainScreen.bounds.size.height)];  
//Based on your requirement change width and height like self.view.bounds.size.width
self.spinnerView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.6];
// [self.view addSubview:self.spinnerView];
UIWindow *currentWindow = [UIApplication sharedApplication].keyWindow;
[currentWindow addSubview:self.spinnerView];

Isso pode funcionar apenas no modo Retrato ou Paisagem.

Mais um código simples é:

yourViewName.layer.zPosition = 1//Change you view name
iOS
fonte
2

Observe se você deseja adicionar a visualização em tela cheia, use apenas o código abaixo

Adicione esta extensão do UIViewController

public extension UIViewController {
   internal func makeViewAsFullScreen() {
      var viewFrame:CGRect = self.view.frame
      if viewFrame.origin.y > 0 || viewFrame.origin.x > 0 {
        self.view.frame = UIScreen.main.bounds
      }
   }
}

Continue como processo normal de adição de subvisão

Agora use na adição de viewDidAppear do UIViewController

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

     self.makeViewAsFullScreen()
}
Paresh Navadiya
fonte
1

Eu usaria uma subclasse UIViewController contendo uma "Exibição de contêiner" que incorpora seus outros controladores de exibição. Você poderá adicionar o controlador de navegação dentro da Exibição do contêiner (usando o relacionamento de incorporação segue, por exemplo).

Consulte Implementando um Container View Controller

dulgan
fonte
1
UIApplication.shared.keyWindow?.insertSubview(yourView, at: 1)

Este método funciona com xcode 9.4, iOS 11.4

Ahmed R.
fonte
0
[self.navigationController.navigationBar.layer setZPosition:-0.1];
UIView *view = [[UIView alloc]initWithFrame:CGRectMake(10, 20, 35, 35)];
[view setBackgroundColor:[UIColor redColor]];
[self.navigationController.view addSubview:view];
[self.navigationController.view bringSubviewToFront:view];
self.navigationController.view.clipsToBounds = NO;
[self.navigationController.navigationBar.layer setZPosition:0.0];

insira a descrição da imagem aqui

Fadi Abuzant
fonte
0

Você precisa adicionar uma subvisão à primeira janela com o tipo UITextEffectsWindow. Para o primeiro, porque os teclados personalizados adicionam seus UITextEffectsWindow e, se você adicionar uma subvisão, isso não funcionará corretamente. Além disso, você não pode adicionar uma subvisão à última janela porque o teclado, por exemplo, também é uma janela e você não pode apresentar a partir da janela do teclado. Portanto, a melhor solução que encontrei é adicionar subview (ou até mesmo empurrar o controlador de exibição) à primeira janela com o tipo UITextEffectsWindow, essa janela abrange a visualização acessória, a barra de navegação - tudo.

let myView = MyView()
myView.frame = UIScreen.main.bounds

guard let textEffectsWindow = NSClassFromString("UITextEffectsWindow") else { return }
let window = UIApplication.shared.windows.first { window in
    window.isKind(of: textEffectsWindow)
}
window?.rootViewController?.view.addSubview(myView)
Viktoria
fonte