Как программно представить контроллер представления из UIVIew
Я использую класс, который является подклассом MessageView
( Swift Message Library), которая наследуется от UIView
, Внутри у меня есть UIButton
и я хочу представить программно другой ViewController
через это.
Вот мой код ниже:
import Foundation
import SwiftMessages
import UIKit
class MyClass: MessageView {
var hideBanner: (() -> Void)?
@IBAction func helpButtonPressed(_ sender: UIButton) {
let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let newViewController = storyBoard.instantiateViewController(withIdentifier: "newViewController") as! NewViewController
self.present(newViewController, animated: true, completion: nil)
@IBAction func tryAgainButtonPressed(_ sender: UIButton) {
hideBanner?()
}
open override func awakeFromNib() {
}
}
Я пробовал это, но это не работает, так как UIView
нет настоящего метода.
7 ответов
Сначала получить верх ViewController
используя это. Тогда вы можете представить свой viewController
,
if var topController = UIApplication.sharedApplication().keyWindow?.rootViewController {
while let presentedViewController = topController.presentedViewController {
topController = presentedViewController
}
// topController now can use for present.
let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let newViewController = storyBoard.instantiateViewController(withIdentifier: "newViewController") as! NewViewController
topController.present(newViewController, animated: true, completion: nil)
}
.present
это метод в UIViewController
класс, это причина, по которой вы не можете представить контроллер представления UIView
учебный класс.
Чтобы добиться этого, получите контроллер корневого представления и представьте контроллер следующим образом:
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let viewController = appDelegate.window!.rootViewController as! YourViewController
let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let newViewController = storyBoard.instantiateViewController(withIdentifier: "newViewController") as! NewViewController
viewController .present(newViewController, animated: true, completion: nil)
Соглашение iOS заключается в том, что только ViewController
S представляет другой ViewController
,
Так что ответы выше - где View
находит текущий ViewController
с помощью UIApplication.sharedApplication().keyWindow?....
будет работать, но это очень анти-шаблон.
Предпочтительным способом будет:
- Ваш
MyClass
представление имеет только код презентации - Вы должны иметь ViewController, который имеет ссылку на это
MyClass
Посмотреть - Этот ViewController имеет
@IBAction func tryAgainButtonPressed
- Оттуда вы можете представить следующий ViewController
Попробуйте этот простой код.
import Foundation
import SwiftMessages
import UIKit
class MyClass: MessageView {
var hideBanner: (() -> Void)?
@IBAction func helpButtonPressed(_ sender: UIButton) {
let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let newViewController = storyBoard.instantiateViewController(withIdentifier: "newViewController") as! NewViewController
UIApplication.shared.keyWindow?.rootViewController?.present(newViewController, animated: true, completion: nil)
}
@IBAction func tryAgainButtonPressed(_ sender: UIButton) {
hideBanner?()
}
open override func awakeFromNib() {
}
}
Извините за задержку с ответом. MessageView
уже обеспечивает buttonTapHandler
Обратный звонок для вас:
/// An optional button tap handler. The `button` is automatically
/// configured to call this tap handler on `.TouchUpInside`.
open var buttonTapHandler: ((_ button: UIButton) -> Void)?
@objc func buttonTapped(_ button: UIButton) {
buttonTapHandler?(button)
}
/// An optional button. This buttons' `.TouchUpInside` event will automatically
/// invoke the optional `buttonTapHandler`, but its fine to add other target
/// action handlers can be added.
@IBOutlet open var button: UIButton? {
didSet {
if let old = oldValue {
old.removeTarget(self, action: #selector(MessageView.buttonTapped(_:)), for: .touchUpInside)
}
if let button = button {
button.addTarget(self, action: #selector(MessageView.buttonTapped(_:)), for: .touchUpInside)
}
}
}
который автоматически вызывается для любой кнопки, которую вы подключаете к button
выход. Таким образом, рекомендуемый метод представления другого контроллера представления должен иметь контроллер представления, конфигурирующий логику представления в этом обратном вызове:
messageView.tapHandler = { [weak self] in
guard let strongSelf = self else { return }
let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let newViewController = storyBoard.instantiateViewController(withIdentifier: "newViewController") as! NewViewController
strongSelf.present(newViewController, animated: true, completion: nil)
}
Если ваш вид имеет более одной кнопки, вы можете обрабатывать их все через buttonTapHandler
так как это занимает button
аргумент. Вам просто нужно настроить механизм целевого действия для каждой кнопки:
otherButton.addTarget(self, action: #selector(MessageView.buttonTapped(_:)), for: .touchUpInside)
Или вы можете добавить один обратный вызов для каждой кнопки, дублируя вышеупомянутый шаблон.
Вот пример кода с использованием шаблона делегирования.
class YourViewController: UIViewController {
var yourView: MyClass // may be outlet
override func viewDidLoad() {
super.viewDidLoad()
yourView.delegate = self
}
}
protocol MyClassDelegate:class {
func tryAgainButtonDidPressed(sender: UIButton)
}
class MyClass: MessageView {
weak var delegate: MyClassDelegate?
@IBAction func tryAgainButtonPressed(_ sender: UIButton) {
delegate?.tryAgainButtonDidPressed(sender: sender)
}
}
Вы можете достичь этого двумя способами
- протокол
- Дав ссылку на этот контроллер представления на представление при инициализации представления