Добавьте UIView прежде всего, даже панель навигации


181

Я хочу отобразить поверх любых других видов, даже панели навигации, своего рода «всплывающее» представление, которое выглядит следующим образом:

  • полноэкранный черный фон с 0,5 альфа, чтобы увидеть другой UIViewControllerснизу.
  • UIViewокно в середине с некоторой информацией (календарь , если вы хотите , чтобы все знать).

Для этого я создал UIViewController, который содержит два элемента UIViews(фон и окно), и я пытаюсь его отобразить. Я попробовал простой [mySuperVC addSubview:myPopUpVC.view], но у меня все еще есть панель навигации выше.

Я пытался представить его как модальный, но UIViewControllerнижний слой исчезает, и я теряю эффект прозрачности.

Любая идея сделать это, я уверен, что это довольно просто ...

Спасибо!


Добавьте подпредставление в окне вашего приложения. Обработка изменений ориентации может быть сложной задачей: stackoverflow.com/questions/8774495/…
— Amar

Ответы:


197

Вы можете сделать это, добавив свой вид непосредственно в keyWindow:

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

ОБНОВЛЕНИЕ - Для Swift 4.1 и выше

let currentWindow: UIWindow? = UIApplication.shared.keyWindow
currentWindow?.addSubview(myView)

2
Спасибо :) К сожалению, если вы находитесь в ландшафтном режиме, вам нужно повернуть вид. Я не уверен, что знаю, как сделать это правильно.
— Николас Рой

Да, я работаю только в ландшафтном режиме, и myView отображается с поворотом на 90 градусов. Похоже, они говорят об этом здесь: stackoverflow.com/questions/8774495/…
— Николас Рой

Проблема ориентации возникает на устройствах до iOS8, для которых это решение, к сожалению, не работает.
— thgc

@NicolasRoy Autolayout поможет
— Дармен Аманбаев

4
это не покрывает панель вкладок. Любое решение для этого?
— Маниша

134

[self.navigationController.view addSubview:overlayView]; это то, что вы действительно хотите


5
Вам нужно установить рамку
— Габриэль Гонсалвес

1
Очень хорошее решение, особенно, когда вы добавляете представление в качестве «дочернего контроллера представления»
— Ричард Топчий

2
Это не работает с дочерним представлением контроллера представления. Изменение z-уровня панели навигации (как предполагает Nam) работает также с контроллерами дочерних представлений.
— Тапани

Это выглядит как более элегантное решение, чем добавление вида в окно Key. Поскольку это обеспечивает добавленное представление, перемещается вдоль анимации основного представления. Потому что, если представление добавлено в ключевое окно, оно не сопровождается анимацией и должно быть удалено отдельно, если вы хотите отключить контроллер.
— Соан Сайни

это не слишком всплывающее окно, но это как раз то, что нужно для моего случая. Спасибо))
— Дилшод Зопиров

112

Вот простое элегантное решение, которое работает для меня. Вы можете установить z положение навигационной панели ниже вида:

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

Просто не забудьте установить его обратно на 0, когда закончите.


1
Это работает намного лучше, чем добавление вида наложения в качестве подпредставления к представлению контроллера навигации (что, кстати, вызывает сбой). Такое решение по z-позиции, вероятно, намного надежнее и в будущем вызывает меньше проблем.
— Тапани

Это прекрасно работает при работе с раскадровками. Вы можете добавить представление внутри раскадровки!
— Йос Коомен

Прекрасно работает для меня тоже. Было бы здорово упомянуть, что zPosition должно быть установлено обратно в значение 0 (вы просто отметили, что оно должно быть установлено обратно, когда закончите). И у меня есть tabBar (из TabBarController на моем экране тоже. Я пытался установить zPosition, но при возврате в 0 значение tabBar все еще не было видно. Поэтому для tabBar лучше использовать свойство isHidden.
— Libor

1
Не работайте с доступностью. Панорамирование по виду не будет фокусировать его.
— antonjn

Я тебя люблю!! <3
— chr0x

57

Версии 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)

6
Могу ли я сделать эту обложку для всего текущего вида (контроллера вида), но оставить над ним новый отображаемый контроллер вида?
— Михал Зиобро

24

Добавьте свой вид как подпредставление NavigationController.

[self.navigationController.navigationBar addSubview: overlayView)]

Вы также можете добавить его через окно:

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

Надеюсь это поможет.. :)


Over view идет, но, когда добавить кнопку не удалось получить действие кнопки или установить пользовательский текст метки на overView
— Vineesh TP

У меня отлично работает:let navigationBar = viewController.navigationController!.navigationBar navigationBar.addSubview(coverView)
— Артур Клеменс


11

Ответ @ Nam отлично работает, если вы просто хотите отобразить свой пользовательский вид, но если ваш пользовательский вид требует взаимодействия с пользователем, вам нужно отключить взаимодействие дляnavigationBar .

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

Как сказано в ответе Нэма, не забудьте отменить эти изменения:

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


Вы можете сделать это лучше с расширением:

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

И просто используйте это так:

self.navigationController.navigationBar.toggle()

1
идеальное решение .. !! Перепробовал так много всего и потратил так много времени .. но это отлично работает .. !!
— Блюдо

8

Быстрая версия ответа @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
}

Не забывайте, что окно должно быть сильным свойством, потому что оригинальный ответ приводит к немедленному освобождению окна


6

Я рекомендую вам создать новое окно 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];

Затем вы можете управлять своим представлением в другом UIViewController. Чтобы удалить окна:

[window removeFromSuperview];
window = nil;

надеюсь, что это поможет!


3
Спасибо, но я думаю, что чего-то не хватает, потому что ничего не появляется: /
— Николас Рой

6

Существует несколько способов сделать это:

1- Добавьте свой UIViewна UIWindowвместо добавления его UIViewController. Таким образом, это будет на вершине всего.

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

2- Используйте пользовательский переход, который будет показывать ваш UIViewController сзади с альфа 0,5

Для этого я рекомендую вам взглянуть на это: https://github.com/Citrrus/BlurryModalSegue



3

В Swift 4.2 и 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!)

В цели C

UIView * spinnerView; // Это ваш взгляд

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];

Это может работать только в портретном или ландшафтном режиме.

Еще один простой код:

yourViewName.layer.zPosition = 1//Change you view name

2

Обратите внимание, если вы хотите добавить вид в полноэкранном режиме, используйте только код ниже

Добавьте эти расширения в 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
      }
   }
}

Продолжайте как обычно добавляя процесс subview

Теперь используйте при добавлении viewDidAppear UIViewController

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

     self.makeViewAsFullScreen()
}

1

Я бы использовал подкласс UIViewController, содержащий «представление контейнера», которое встраивает ваши контроллеры представления других. После этого вы сможете добавить контроллер навигации в представление «Контейнер» (например, с помощью перехода «вставка»).

См. Реализация контроллера представления контейнера


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

Этот метод работает с xcode 9.4, iOS 11.4


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];

введите описание изображения здесь


0

Вам необходимо добавить подпредставление в первое окно с типом UITextEffectsWindow. Во-первых, потому что пользовательские клавиатуры добавляют свой UITextEffectsWindow, и если вы добавите в него подпредставление, это не будет работать правильно. Кроме того, вы не можете добавить подпредставление к последнему окну, потому что клавиатура, например, также является окном, и вы не можете представить ее из окна клавиатуры. Поэтому лучшее решение, которое я нашел, - это добавить подпредставление (или даже контроллер push-представления) в первое окно с типом UITextEffectsWindow, это окно охватывает вспомогательный вид, панель навигации - все.

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)
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.