Как сделать всплывающее окно swift

Обновлено: 06.05.2024

Как использовать Modal Segue в Navigation Controller

И так, перед вами стоит проблема: клиенту не нравится стандартный переход Navigation Controller'а — «нахлест справа» — и он хочет, чтобы новый экран, например, появлялся «поворотом экрана снизу». Сразу видим вариант решения задачи: поменять вид Segue на Modal. Все было бы хорошо, да вот только логика Navigation Controller'a с его иерархией экранов нарушается; и как следствие, приложение вылетает. То есть теперь нам нужна Modal Segue, но с функциями Push Segue. Подозреваю, что есть способы попроще решить эту задачу, но я предлагаю просто написать подкласс UIStoryboardSegue. Единственное, что нам предстоит поменять, это .m файл нашего класса. А точнее, метод perform:

Вместо UIViewAnimationOptionTransitionFlipFromBottom можно поставить любой близкий сердцу вашего клиента стиль перехода.
Вот и все! Как просто, скажете вы. Теперь мы можем указать для любой Storyboard Segue стиль Custom, указать наш новый класс и заполучить Navigation Controller Segue со своим типом перехода.

Core Graphics

В один прекрасный момент вашему клиенту надоело пинать дизайнера каждый раз, когда нужно изменить ширину кнопки на 5 пикселов (ведь для каждой кнопочки дизайнер нарисовал отдельную картинку). Сделаем собственную кнопку с закругленными краями и и рамкой вокруг при помощи QuartzCore.framework. Опять же, как и с синглтоном, это скорее сниппет, ускоряющий работу над проектом.

Вообще-то данный подход можно использовать с любым подклассом UIView (UIButton как-раз им и является). Мы переписываем метод awakeFromNib у нашего UIView:


Все просто. Во-первых, при наследовании нам нужно выполнить наш код после того, как суперкласс закончит свою работу. Так что мы вызываем тот же метод, но у суперкласса. Во-вторых, мы задаем радиус закругления углов у слоя нашего вида и заставляем слой подчиняться указанной маске. В-третьих, мы задаем цвет рамки (CGColor, конечно) и ее толщину.
Я знаю, что некоторые ожидали глубокой работы с графическим контекстом, но на то они и быстрые шпаргалки фрилансера — когда появится новая задача с Core Graphics, тогда и будем писать статьи.

Работа с UIWebView и ScrollView

У нас уже есть UIWebView, давайте подгрузим в него контент:


Просто получили веб страничку с нашим стилем и html. А чтобы скрыть неприятные серые тени при оверскроле UIWebView мы применили следующий метод:


Мы прячем все дочерние виды у Scrollview, принадлежащего нашему UIWebView. А так же устанавливаем прозрачный задний фон.

О UIScrollView можно сказать только одно: никогда не забывайте устанавливать свойство contentSize, и будет вам счастье.

Собственные всплывающие окна (Popups)

Пришло время поговорить о гиганте этой статьи. В этот раз клиенту потребовалась возможность быстро и без вашего участия менять вид всплывающих окон. Что же, за дело!

Давайте поговорим немного о теории, о том, как мы все провернем.
В Storyboard у нас вряд ли получится реализовать полноценное всплывающее окно, а вот создать отдельный файл PopupView.xib мы можем!
А в качестве модели мы создадим три класса PopupView, PopupController, PopupControllerDelegate.

Сначала соберите макет своего всплывающего окна как на скриншоте. Учтите, что File's Owner в нашем случае будет объектом класса PopupController, а сам View будет объектом класса PopupView. Background View — это полупрозрачный светло-серый UIView.


Посмотрим сначала на реализацию PopupView.h:

Мы просто зацепили все элементы пользовательского интерфейса в код; PopupView.m мы не изменяли, оставили стандартный сгенерированный код.
У нас есть шаблон всплывающего окна, теперь нам нужно умело его использовать. Создаем PopupController.

PopupController.h:

Все что мы сделали — это установили нужные нам свойства и публичные методы инициализации, показа простенького всплывающего окна, закрытия всех всплывающих окон. А еще добавили небольшой Action для кнопочки внутри всплывающего окна в PopupController.

PopupController.m:

Во время инициализации мы сразу устанавливаем делегат нашего класса.
Код метода showHelloWorldPopup я разделил на три других метода для облегчения чтения: мы инициализируем всплывающее окно, настраиваем его и показываем.
Когда пользователь дотрагивается до кнопки на всплывающем окне, мы уведомляем об этом наш делегат.
Метод dismissAllPopups просто проходится по всем всплывающим окнам в общем массиве и закрывает каждое.
Допищем недостающие методы:

Все хитрости поочередно:

  1. Анимации при помощи UIView: все, что написано в блоке animations:, будет постепенно выполняться в течение установленного времени. Код из блока completion: выполнится мгновенно, сразу после блока animations:
  2. Когда пользователь нажимает на серое затемнение, всплывающее окно сразу исчезает
  3. Если просто установить текст кнопки для одного состояния, то для других текст не изменится, поэтому метод setTitle: forButton: меняет текст кнопки сразу для всех состояний

Ну, и на последок, покажу, как работает наш класс. Допишем PopupControllerDelegate.h:


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

Например, мы хотим показать HelloWorld окошко после загрузки нашего вида, который отвечает нужному протоколу и у которого уже есть инициализированный объект popupController. Добавим следующий код в viewDidAppear:


И добавим обработчик события всплывающего окна:

Заключение

Спасибо за то, что дочитали до конца!

Вторую часть статьи написал в аэропорту Домодедово перед вылетом в Ванкувер. Уже поздняя ночь, у меня кончается кофе. Прошу понять простить, и если нашли какую-либо опечатку\неточность в тексте\коде, пожалуйста, сообщите в мой хабрацентр, не спешите ставить минус или писать гневный комментарий.

В следующих статьях будут темы еще интереснее: расшаривание контента в социальных сетях, PSPDFKit, Push Notifications.

Итак, наша задача создать iOS приложение, в среде разработки Xcode, в котором будет всплывающее окно —Pop Up View, при этом все что сзади этого окна будет затемняться. Подобный прием использован во многих приложениях, но я не смог найти информацию как именно это сделать — насколько нужно затемнять, сколько времени должна идти анимация и пр.

После выполнения задачи у нас получится такое приложение:

В Xcode создайте новй проект, Single View Application и назовите его как нибудь — я назвал PopUpView. Из библиотеки объектов перетащите на имеющийся View Controller кнопку и установите текст кнопки «Показать». Установите ограничения для этой кнопки, чтобы она была размещена по центу контроллера. Это не обязательное условие, и вы можете разместить кнопку в Interface Builder Xcode как хотите. У меня получилось так:


Добавьте еще одни контроллер из библиотеки элементов Xcode. Сразу добавьте файл, в котором будет описан класс нашего нового контроллера.

Можете создать файл вручную, в этом случае укажите наименование нового класса и то что наследуется от UIVewController. Либо Xcode создаст этот файл автоматически.


Не забудьте в панели утилит справа присвоить контроллеру созданный клас

Добавление всплывающего окна

В редакторе интерфейса Xcode на вновь созданный контроллер добавьте View небольшого размера и разместите его по центру контроллера. Добавьте ограничения, измените цвет на ваш вкус. Я выбрал светло-светло-серый. На этот View следует добавить кнопку, изменить текст кнопки на «Закрыть». Я поклонник закругленных углов, поэтому я добавил outlet для View, назвал его MessageView. Вот как это выглядит у меня:


Обратите внимание, что в структуре View кнопка «Закрыть» внутри серого View. Также на скриншоте видна еще строка кода, которая закругляет углы, обращаясь через созданный на предыдущем шаге outlet. Как видите код я вызвал в методе viewDidLoad() контроллера PopUpVC.

Вывод на экран

Итак, все предварительные приготовления сделаны, теперь давайте попробуем отобразить все безобразие, которое мы насоздавали. И первое что нужно сделать, это создать Action, т.е. метод, который будет вызываться при нажатии на кнопку «Показать».


Далее следует добавить код, который покажет контролер PopUpViewController поверх корневого ViewController. Этот код нужно добавить во вновь созданый метод

Что тут у нас происходит:

  1. Мы получаем ссылку на PopUpViewController, причем получаем ссылку мы при помощи метода, который обращается к StoryBoard и находит контроллер, у которого идентификатор popUpVCid. ВНИМАНИЕ! Мы его еще не устанавливали, сделаем чуть ниже.
  2. Добавляем полученный контроллер PopUpViewController в качестве дочернего к ViewController.
  3. Размеры View нового контроллера мы устанавливаем равными размера View текущего контроллера.
  4. Непосредственно выводим на экран то, как отображается PopUpViewController. Т.е. добавляем ViewPopUpViewController в стек той кучи View, которые уже есть.
  5. Вызываем метод делегата, чтобы сообщить всем делегатам, о том, что контроллер мы отобразили.

И прежде чем в первый раз запустить проект, нужно добавить идентификатор, о котором мы говорили на предыдущем шаге в пункте 1.


Только после этого можно запускать проект и нажимать на кнопку «Показать». Если все сделано правильно и мы ничего не забыли, то в симуляторе вы увидите следующее:

Закрываем окно

Для того чтобы закрыть всплывающее окно прежде всего нужно добавить Action на кнопку «Закрыть». Добавляйте кому как удобно — провой кнопкой мыши, ctrl-перетягивание, или через панель утилит и вкладку связей. Это не имеет значение, Xcode заботливо соберет и скомпилирует все связи за нас.


Добавляем строку кода для удаления отображения контроллера PopUpVC во вновь сознанный Action.

Можно запустить и посмотреть что получится. Обе кнопки должны работать.

Детали

Всю программную логику отображения и закрытия всплывающего окна мы создали. Теперь нужно доработать детали отображения


Затемнение фона

Для этого просто установим цвет у фона PopUpViewController в темный цвет и добавим фону прозрачности. Это следует произвести в том же методе, в котором мы меняли углы у серого View.

Запустите проект и отобразите Pop Up контроллер:


Анимация

Для пущего эффекта добавим немного анимации. Необходимо добавить два метода, которые будут отвечать за появление окна и его убирание с экрана. Анимировать мы будем элементы PopUpViewController, поэтому добавлять методы мы будем именно ему. В Класс PopUpViewController после метода закрытия окна добавьте еще два метода:

Думаю, эти два метода не вызовут вопросов. Мы уже много раз разбирали принципы анимации. Но если необходимо, можно еще что нибудь новенькое санимировать.

Один из лучших способов освоить SwiftUI (как и большинство технологий) — это реализовать что-то небольшое и полезное. Всплывающее окно (поп-ап) является отличным вариантом — это один из самых популярных инструментов интерфейса, который часто нужно кастомизировать, если нативный вариант не устраивает по виду или функционалу.

В этом туториале мы создадим минимальный вариант всплывающего окна на SwiftUI с нуля. В итоге получим рабочий компонент пользовательского интерфейса, который можно внедрить в свое SwiftUI приложение или продолжить его настраивать и улучшать. Вот как это будет выглядеть:

Выбор API

Сначала определимся с функциональностью поп-апа, который мы хотим реализовать. Это будет элемент, который отображается при нажатии на кнопку. В нем будет отображен просто лейбл. Он будет появляться и исчезать анимированно. Нам нужна возможность определять внешний вид и стиль поп-апа, добавлять его в стек интерфейса и контролировать его состояние.

Мы начнем с написания примера использования поп-апа, как будто он уже существует, а самой реализацией займёмся чуть позже. Такой подход позволит сразу понять, как будет удобнее использовать компонент в своем коде.

Вот что делает этот простой пример:

Мы добавляем всплывающее окно в качестве модификатора нашего элемента, передавая @Binding showingPopup для управления состоянием внутри реализации самого элемента.Переменная @Statevar showingPopup будет управлять отображением поп-апа.

Отдельная кнопка на экране будет изменять состояние переменной showingPopup.

Мы добавляем всплывающее окно в качестве модификатора нашего элемента, передавая @BindingshowingPopup для управления состоянием внутри реализации самого элемента.

Дизайн и содержимое всплывающего окна также передаются в качестве параметра.

Сам поп-ап реализован как ViewModifier, как принято в SwiftUI.

Теперь, когда у нас есть представление о желаемом интерфейсе и внешнем виде поп-апа, давайте приступим к фактической реализации.

Реализация View Modifier

Этот фрагмент кода не требует пояснений - это определение модификатора поп-апа для View. Мы уже знаем, что нам нужны два параметра — isPresented, который представляет собой Binding Property Wrapper для управления состоянием всплывающего окна, и view, который отвечает за внешний вид поп-апа.

Теперь мы можем приступить к самой интересной части.

Реализация всплывающего элемента

Инициализатор и публичные переменные понятны — они уже были определены и объяснены, когда мы выбирали API:

Список приватных переменных расскажет больше о деталях реализации — поп-ап будет отображаться и скрываться путем изменения оффсета view, которое его содержит. Этот оффсет легко посчитать и анимировать, и он подходит для всех размеров экрана, поскольку прямым образом от него зависит.

Приватные переменные будут содержать данные фрейма, необходимые для показа и скрытия поп-апа — фреймы родительского контроллера и содержимого поп-апа, оффсеты для скрытого и показанного состояния, а также вспомогательные методы для получения размера экрана.

Само UI-наполнение поп-апа минимально: мы считываем фрейм основного контента, затем добавляем sheet оверлея, содержащий поп-ап. Сам sheet делает практически то же самое — считывает свой фрейм для позиционирования видимого UI поп-апа, а также добавляет обработчик для удаления показанного поп-апа по нажатию и простую анимацию. Тут же используется ранее вычисленный currentOffset:

Чтобы реализовать простую анимацию в SwiftUI, достаточно добавить однострочный модификатор, что мы и делаем в конце создания sheet. Естественно, его можно анимировать как вам угодно — просто заменив итоговый размер и положение на экране, можно получить другой тип UI элемента (например, верхний или нижний тост).

Скорее всего, вы обратили внимание на модификатор frameGetter. Это некрасивый, но необходимый в SwiftUI метод получения фрейма (по крайней мере, судя по документации, более удобного способа получить фрейм в SwiftUI у нас нет). Надеемся, что в будущем появится более удобный способ:

GeometryReader — это view в SwiftUI, который в качестве параметра принимает координатное пространство и предоставляет информацию о своем размере содержимому (иными словами, как раз то, что нужно для получения данных о фрейме).

Заключение

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

Можете также посмотреть на нашу библиотеку для поп-апа на SwiftUI. На самом деле, этот туториал — упрощенная версия кода в нашем репозитории. Он заметно более сложен из-за большего количества стилей для поп-апов, расширенных параметров и коллбэков, а также поддержкой нескольких платформ. Сам код отображения и добавления поп-апа идентичен приведённому выше. Библиотека предоставляет как простые поп-апы:

Привет, Хабр! Всем нравятся отзывчивые приложения. Ещё лучше, когда в них есть уместные анимации. В этой статье я расскажу и покажу со всем «мясом», как правильно показывать, скрывать, крутить, вертеть и делать всякое с всплывающими экранами.


Изначально я хотел написать статью о том, что на iOS 10 появился удобный UIViewPropertyAnimator , который решает проблему прерываемых анимаций. Теперь их можно будет остановить, инвертировать, продолжить или отменить. Эпл называет такой интерфейс Fluid.

Но потом я понял: сложно рассказывать о прерывании анимации контроллеров без описания того, как эти переходы правильно анимировать. Поэтому будет две статьи. В этой разберёмся, как правильно показывать и скрывать экран, а о прерывании — в следующей.

Как работают транзишены

У UIViewController есть проперти transitioningDelegate . Это протокол с разными функциями, каждая возвращает объект:

  • animationController за анимацию,
  • interactionController за прерывание анимаций,
  • presentationController за отображение: иерархию, frame и т.д.


На основе всего этого сделаем всплывающую панель:

Готовим контроллеры

Можно анимировать переход для модальных контроллеров и для UINavigationController (работает через UINavigationControllerDelegate ).
Мы будет рассматривать модальные переходы. Настройка контроллера перед показом немного необычная:

  1. Создаём объект, описывающий переход. transitioningDelegate помечен как weak , поэтому приходиться хранить transition отдельно по strong ссылке.
  2. Сетим наш переход в transitioningDelegate .
  3. Для того, чтобы управлять способом отображения в presentationController нужно указывать .custom для modalPresentationStyle. .

Показываемый контроллер вообще не знает о том, как его показывают. И это хорошо.

Показываем в пол-экрана

Начнём код для PanelTransition с presentationController . Вы с ним работали, если создавали всплывающие окна через UIPopoverController . PresentationController управляет отображением контроллера: фреймом, иерархией и т.д. Он решает, как показывать поповеры на айпаде: с каким фреймом, в какую сторону от кнопки показывать, добавляет размытие в фон окна и затемнение под него.


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


Для начала, в методе presentationController(forPresented:, presenting:, source:) вернём класс PresentationController :

Source – это тот контроллер, на котором мы вызвали анимацию показа. Но контроллер, который будет участвовать в транзишине — первый из иерархии, у которого установлено definesPresentationContext = true . Если контроллер сменится, то настоящий показывающий контроллер будет в параметре presenting.

Теперь можно реализовать класс PresentationController . Для начала, зададим фрейм будущему контроллеру. Для этого есть метод frameOfPresentedViewInContainerView . Пусть контроллер займёт нижнюю половину экрана:

Можно запустить проект и попробовать показать экран, но ничего не произойдёт. Это потому, что мы теперь сами управляем иерархией вьюшек и нам надо добавить вью контроллера вручную:

Ещё нужно поставить фрейм для presentedView . containerViewDidLayoutSubviews – лучшее место, потому что так мы сможем реагировать и на поворот экрана:

Теперь можно запускать. Анимация будет стандартной для UIModalTransitionStyle.coverVertical , но фрейм будет в два раза меньше.

Затемняем фон

Следующая задача – затемнить фоновый контроллер, чтобы сфокусироваться на показанном.

Унаследуемся от PresentationController и заменим на новый класс в файле PanelTransition . В новом классе будет только код для затемнения.

Создадим вьюшку, которую будем накладывать поверх:

Будем менять alpha вьюшки согласованно с анимацией перехода. Есть 4 метода:

  • presentationTransitionWillBegin
  • presentationTransitionDidEnd
  • dismissalTransitionWillBegin
  • dismissalTransitionDidEnd

Первый из них самый сложный. Надо добавить dimmView в иерархию, проставить фрейм и запустить анимацию:

Анимация запускается с помощью вспомогательной функции:

Фрейм для dimmView задаём в containerViewDidLayoutSubviews (как и в прошлый раз):

Анимация может быть прервана и отменена, и если отменили, то надо удалить dimmView из иерархии:

Обратный процесс запускается в методах скрытия. Но теперь нужно удалять dimmView , только если анимация завершилась.

Теперь фон затемняется.

Управляем анимацией

Показываем контроллер снизу

Теперь мы можем анимировать появление контроллера. В классе PanelTransition вернём класс, который будет управлять анимацией появления:

Реализовать протокол просто:

Ключевой код чуть сложнее:

Обойти довольно просто: нужно в коде animateTransition использовать не аниматор, а старое апи UIView.animate… Например, вот так:

Если вы не делаете прерываемый транзишен, то метод interruptibleAnimator можно не писать, но тогда надо вручную вызвать анимацию у PropertyAnimator.

Скрываем контроллер вниз

Всё то же самое, только в обратную сторону. В Panel Transition создадим класс DismissAnimation :

И реализуем его. Класс DismissAnimation целиком:



Додо Пицца, Перекус и Сейви

В следующий раз добавим интерактивное закрытие жестом, а потом сделаем его анимацию прерываемой. Если не терпится, то полный проект уже на гитхабе.

So I am working on a simple app, where I use a table view. This table view displays the name of "players". But in order for me to add players in the table view, I want a pop up window to be displayed with a text field where you provide the name.

Now I have been reading about creating a xib or nib file, but I am not sure how to "load" the pop up window.

What's the best approach to this?

Looks like this:

Pop up View

enter image description here

3 Answers 3

In storyboard

  • In storyboard create one UIViewController and design it according to your requirement.
  • Set custom class as anotherViewController and Storyboard_ID as another_view_sid
  • Create one new Cocoa Touch Class as anotherViewController and subclass of UIVIewController

In viewController

In anotherViewController

you'd create an custom UIView with all respected object needed, from your Controller's viewDidLoad() you'll hide it.

Whenever your user wants to perform some action or task, you unhide it and once the user finished then hide it again or remove from the superView.

Below there is some code to help you start

Check it out this github project, It's closed to be production ready, it gives you a better way to deal (present and dismiss) with UIViews

If you only want the player's name then use a UIAlertController containing a textfield

I've worked on that option, problem is that on the story board is kind of difficult to implement since I am working with a tableview and there is no where to place the "UIView". Or at least I don't know how to do that part. If I add a view to the top, it's a view for the header, or at the bottom is a view for the footer. I will add a screenshot to the original post of what I mean.

you dont need to drag the UIView on top of the tableview. you could create the UIView via code do you want to see an example ?

Perfect thank you.. I will try to do it this way. The hard part I see to this is that the design of my custom pop up, is kind of specific lol So I will have to play around a bit to figure it out. If you look at my screenshot, you will notice what I am saying. I want it to look like that, I guess I have to play with the UIView properties. Never done that, but there is always a first time. I also try to up vote your answer, but someone just down voted my question and it brought me down to 13 on reputation and won't let me up vote till i get to 15 again.

if you might have a question just go to the chat look for this room "CheckerHelp" just send a message

Читайте также: