Пользовательское оповещение (UIAlertView) с быстрым
Как создать пользовательское оповещение с помощью Swift? Я пытаюсь перевести руководство из Objective c, но загружает полноэкранный макет
для этого легко я могу загрузить новый макет с прозрачным фоном, я пробую это:
listaalertviewcontroller.view.backgroundColor = UIColor.clearColor()
let purple = UIColor.purpleColor() // 1.0 alpha
let semi = purple.colorWithAlphaComponent(0.5)
listaalertviewcontroller.view.backgroundColor = semi
presentingViewController.modalPresentationStyle = UIModalPresentationStyle.CurrentContext
self.presentViewController(listaalertviewcontroller, animated: true, completion: nil)
в анимации он прозрачный, но когда анимация заканчивается, он непрозрачен... и я отключу непрозрачный вариант в представлении... что я делаю неправильно?
Ответы
Ответ 1
Код, протестированный в Swift 5 и Xcode 10
Как сделать собственное оповещение
Я хотел сделать что-то подобное. Прежде всего, UIAlertView
устарела в пользу UIAlertController
. Посмотрите этот ответ для стандартного способа отображения предупреждения:
И UIAlertView
, и UIAlertController
на самом деле не допускают особых настроек. Одним из вариантов является использование стороннего кода. Однако я обнаружил, что создать собственное оповещение не так сложно, отобразив другой контроллер вида.
Пример здесь - только подтверждение концепции. Вы можете создать свое оповещение любым удобным для вас способом.
![enter image description here]()
Раскадровка
У вас должно быть два контроллера просмотра. Ваш второй контроллер представления будет вашим предупреждением. Установите имя класса на AlertViewContoller
и идентификатор раскадровки на alert
. (Оба эти имени мы определили сами в приведенном ниже коде, ничего особенного в них нет. Сначала вы можете добавить код, если хотите. Возможно, будет проще, если вы сначала добавите код.)
![enter image description here]()
Установите цвет фона для корневого представления (в контроллере представления предупреждений), чтобы очистить (или полупрозрачный черный цвет подходит для оповещения). Добавьте еще один UIView
и отцентрируйте его с ограничениями. Используйте это в качестве фона оповещения и поместите все, что вы хотите внутри. Для моего примера я добавил UIButton
.
![enter image description here]()
Код
ViewController.swift
import UIKit
class ViewController: UIViewController {
@IBAction func showAlertButtonTapped(_ sender: UIButton) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let myAlert = storyboard.instantiateViewController(withIdentifier: "alert")
myAlert.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext
myAlert.modalTransitionStyle = UIModalTransitionStyle.crossDissolve
self.present(myAlert, animated: true, completion: nil)
}
}
AlertViewController.swift
import UIKit
class AlertViewController: UIViewController {
@IBAction func dismissButtonTapped(_ sender: UIButton) {
self.dismiss(animated: true, completion: nil)
}
}
Не забудьте подключить розетки.
Вы можете добавить прослушиватель событий onTouchUp
в фоновом режиме, чтобы закрыть всплывающее окно, когда пользователь нажимает за его пределами.
Это. Вы должны быть в состоянии сделать любое предупреждение, которое вы можете себе представить сейчас. Нет необходимости в стороннем коде.
Вот еще одно пользовательское предупреждение, которое я сделал. Все еще безобразно, но показывает больше вещей, которые вы можете сделать.
![enter image description here]()
Другие варианты
Однако иногда нет необходимости изобретать велосипед. Я впечатлен сторонним проектом SDCAlertView (лицензия MIT). Он написан на Swift, но вы можете использовать его и в проектах Objective-C. Он предлагает широкий спектр удобного использования.
Ответ 2
Вот код Swift 3. Большое спасибо @Suragch за удивительный подход к созданию пользовательского AlertView.
ViewController.swift
import UIKit
class ViewController: UIViewController {
@IBAction func showAlertButtonTapped(sender: UIButton) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let myAlert = storyboard.instantiateViewController(withIdentifier: "storyboardID")
myAlert.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext
myAlert.modalTransitionStyle = UIModalTransitionStyle.crossDissolve
self.present(myAlert, animated: true, completion: nil)
}
AlertViewController.swift
import UIKit
class AlertViewController: UIViewController {
@IBAction func dismissButtonTapped(sender: UIButton) {
self.dismiss(animated: true, completion: nil)
}
}
Чтобы сделать это немного интереснее или сделать эффект по умолчанию в iOS, вы можете добавить либо VisualEffectView, либо изменить цвет основного UIView на темный цвет и установить его альфа до 70%. Я предпочитаю второй подход, так как эффект размытия не такой гладкий, как тот, который имеет вид с 70 альфа.
Эффект с VisualEffectView:
![введите описание изображения здесь]()
Эффект с использованием UIView с 70 Alpha:
![введите описание изображения здесь]()
Ответ 3
Используйте https://github.com/shantaramk/Custom-Alert-View
Это легко реализовать. просто следуйте ниже шагов:
-
Перетащите папку AlertView в каталог проекта
-
Показать всплывающее окно AlertView
func showUpdateProfilePopup(_ message: String) {
let alertView = AlertView(title: AlertMessage.success, message: message, okButtonText: LocalizedStrings.okay, cancelButtonText: "") { (_, button) in
if button == .other {
self.navigationController?.popViewController(animated: true)
}
}
alertView.show(animated: true)
}
Ответ 4
В настоящее время предупреждение - это просто представленный контроллер представления. Вы можете написать представленный контроллер представления, который ведет себя подобно предупреждению - то есть он всплывает на экран и затемняет все, что за ним - но это ваш контроллер представления, и вы можете предоставить ему любой интерфейс, который вам нравится.
Для начала я написал проект github, который вы можете загрузить и запустить, а также изменить в соответствии с вашими потребностями.
Я покажу ключевую часть кода. Контроллер представления "alert" в своих инициализаторах устанавливает свой собственный стиль модального представления как custom
и устанавливает переходящий делегат:
class CustomAlertViewController : UIViewController {
let transitioner = CAVTransitioner()
override init(nibName: String?, bundle: Bundle?) {
super.init(nibName: nibName, bundle: bundle)
self.modalPresentationStyle = .custom
self.transitioningDelegate = self.transitioner
}
convenience init() {
self.init(nibName:nil, bundle:nil)
}
required init?(coder: NSCoder) {
fatalError("NSCoding not supported")
}
}
Вся работа выполняется переходным делегатом:
class CAVTransitioner : NSObject, UIViewControllerTransitioningDelegate {
func presentationController(
forPresented presented: UIViewController,
presenting: UIViewController?,
source: UIViewController)
-> UIPresentationController? {
return MyPresentationController(
presentedViewController: presented, presenting: presenting)
}
}
class MyPresentationController : UIPresentationController {
func decorateView(_ v:UIView) {
// iOS 8 doesn't have this
// v.layer.borderColor = UIColor.blue.cgColor
// v.layer.borderWidth = 2
v.layer.cornerRadius = 8
let m1 = UIInterpolatingMotionEffect(
keyPath:"center.x", type:.tiltAlongHorizontalAxis)
m1.maximumRelativeValue = 10.0
m1.minimumRelativeValue = -10.0
let m2 = UIInterpolatingMotionEffect(
keyPath:"center.y", type:.tiltAlongVerticalAxis)
m2.maximumRelativeValue = 10.0
m2.minimumRelativeValue = -10.0
let g = UIMotionEffectGroup()
g.motionEffects = [m1,m2]
v.addMotionEffect(g)
}
override func presentationTransitionWillBegin() {
self.decorateView(self.presentedView!)
let vc = self.presentingViewController
let v = vc.view!
let con = self.containerView!
let shadow = UIView(frame:con.bounds)
shadow.backgroundColor = UIColor(white:0, alpha:0.4)
shadow.alpha = 0
con.insertSubview(shadow, at: 0)
shadow.autoresizingMask = [.flexibleWidth, .flexibleHeight]
let tc = vc.transitionCoordinator!
tc.animate(alongsideTransition: { _ in
shadow.alpha = 1
}) { _ in
v.tintAdjustmentMode = .dimmed
}
}
override func dismissalTransitionWillBegin() {
let vc = self.presentingViewController
let v = vc.view!
let con = self.containerView!
let shadow = con.subviews[0]
let tc = vc.transitionCoordinator!
tc.animate(alongsideTransition: { _ in
shadow.alpha = 0
}) { _ in
v.tintAdjustmentMode = .automatic
}
}
override var frameOfPresentedViewInContainerView : CGRect {
// we want to center the presented view at its "native" size
// I can think of a lot of ways to do this,
// but here we just assume that it *is* its native size
let v = self.presentedView!
let con = self.containerView!
v.center = CGPoint(x: con.bounds.midX, y: con.bounds.midY)
return v.frame.integral
}
override func containerViewWillLayoutSubviews() {
// deal with future rotation
// again, I can think of more than one approach
let v = self.presentedView!
v.autoresizingMask = [
.flexibleTopMargin, .flexibleBottomMargin,
.flexibleLeftMargin, .flexibleRightMargin
]
v.translatesAutoresizingMaskIntoConstraints = true
}
}
extension CAVTransitioner { // UIViewControllerTransitioningDelegate
func animationController(
forPresented presented:UIViewController,
presenting: UIViewController,
source: UIViewController)
-> UIViewControllerAnimatedTransitioning? {
return self
}
func animationController(
forDismissed dismissed: UIViewController)
-> UIViewControllerAnimatedTransitioning? {
return self
}
}
extension CAVTransitioner : UIViewControllerAnimatedTransitioning {
func transitionDuration(
using transitionContext: UIViewControllerContextTransitioning?)
-> TimeInterval {
return 0.25
}
func animateTransition(
using transitionContext: UIViewControllerContextTransitioning) {
let con = transitionContext.containerView
let v1 = transitionContext.view(forKey: .from)
let v2 = transitionContext.view(forKey: .to)
// we are using the same object (self) as animation controller
// for both presentation and dismissal
// so we have to distinguish the two cases
if let v2 = v2 { // presenting
con.addSubview(v2)
let scale = CGAffineTransform(scaleX: 1.6, y: 1.6)
v2.transform = scale
v2.alpha = 0
UIView.animate(withDuration: 0.25, animations: {
v2.alpha = 1
v2.transform = .identity
}) { _ in
transitionContext.completeTransition(true)
}
} else if let v1 = v1 { // dismissing
UIView.animate(withDuration: 0.25, animations: {
v1.alpha = 0
}) { _ in
transitionContext.completeTransition(true)
}
}
}
}
Выглядит как много кода, и я полагаю, что так оно и есть, но он почти полностью ограничен одним классом, который является полностью стандартным; просто скопируйте и вставьте. Все, что вам нужно сделать, это написать внутренний интерфейс и поведение вашего "предупреждающего" контроллера представления, предоставляя ему кнопки и текст, и все, что вы хотите, так же, как вы делали бы это для любого другого контроллера представления.
Ответ 5
Вы можете использовать для его следующего фреймворка:
https://github.com/bananaRanger/SheetViewController
Это настраиваемый нативный контроллер уведомлений о листах.
Он имеет три типа действий: отдельно, внутренний, нет.
пример
Ответ 6
**## custom Alert UIView Class in swift 4**
import UIKit
class Dialouge: UIView {
@IBOutlet weak var lblTitle: UILabel!
@IBOutlet weak var lblDescription: UILabel!
@IBOutlet weak var btnLeft: UIButton!
@IBOutlet weak var btnRight: UIButton!
@IBOutlet weak var viewBg: UIButton!
var leftAction = {}
var rightAction = {}
override func draw(_ rect: CGRect)
{
self.btnRight.layer.cornerRadius = self.btnRight.frame.height/2
self.btnLeft.layer.cornerRadius = self.btnLeft.frame.height/2
self.btnLeft.layer.borderWidth = 1.0
self.btnLeft.layer.borderColor = #colorLiteral(red: 0.267678082, green: 0.2990377247, blue: 0.7881471515, alpha: 1)
}
@IBAction func leftAction(_ sender: Any) {
leftAction()
}
@IBAction func rightAction(_ sender: Any) {
rightAction()
}
@IBAction func bgTapped(_ sender: Any) {
self.removeFromSuperview()
}
}
сильный текст
## Использование настраиваемого оповещения с помощью вкладки.
let custView = Bundle.main.loadNibNamed("Dialouge", owner: self, options:
nil)![0] as? Dialouge
custView?.lblDescription.text = "Are you sure you want to delete post?"
custView?.lblTitle.text = "Delete Post"
custView?.btnLeft.setTitle("Yes", for: .normal)
custView?.btnRight.setTitle("No", for: .normal)
custView?.leftAction = {
self.deletePost(postId: self.curr_post.id,completion: {
custView?.removeFromSuperview()
})
}
custView?.rightAction = {
custView?.removeFromSuperview()
}
if let tbc = self.parentt?.tabBarController {
custView?.frame = tbc.view.frame
DispatchQueue.main.async {
tbc.view.addSubview(custView!)
}
}else if let tbc = self.parView?.parenttprof {
custView?.frame = tbc.view.frame
DispatchQueue.main.async {
tbc.view.addSubview(custView!)
}
}
else
{
custView?.frame = self.parView?.view.frame ?? CGRect.zero
DispatchQueue.main.async {
self.parView?.view.addSubview(custView!)
}
}