视图被合并而不是单独显示
Posted
技术标签:
【中文标题】视图被合并而不是单独显示【英文标题】:views are merged instead of showing them separately 【发布时间】:2018-09-04 05:21:42 【问题描述】:我有两个 xib 文件,一个显示登录视图,另一个显示登录成功后的步骤。我很难让它发挥作用。我创建了 macos 项目而不是 ios 并使用 safariservices 以便它也适用于 safari 扩展。
这就是我所做的
import SafariServices
class SafariExtensionViewController: SFSafariExtensionViewController
@IBOutlet weak var passwordMessage: NSTextField!
@IBOutlet weak var emailMessage: NSTextField!
@IBOutlet weak var message: NSTextField!
@IBOutlet weak var email: NSTextField!
@IBOutlet weak var password: NSSecureTextField!
static let shared = SafariExtensionViewController()
override func viewDidLoad()
self.preferredContentSize = NSSize(width: 300, height: 250)
message.stringValue = ""
emailMessage.stringValue = ""
passwordMessage.stringValue = ""
override func viewDidAppear()
if let storedEmail = UserDefaults.standard.object(forKey: "email") as? String
if let stepView = Bundle.mainBundle.loadNibNamed(NSNib.Name(rawValue: "ExtensionStepsViewController"), owner: nil, topLevelObjects: nil)[0]
self.view.addSubview(stepView)
@IBAction func userLogin(_ sender: Any)
let providedEmailAddress = email.stringValue
let providedPassword = password.stringValue
let isEmailAddressValid = isValidEmailAddress(emailAddressString: providedEmailAddress)
self.message.stringValue = ""
emailMessage.stringValue = ""
passwordMessage.stringValue = ""
if isEmailAddressValid && providedPassword.count > 0
/* login process is handled here and store the email in local storage /*
/* TODO for now email is not stored in browser localstorage which has to be fixed */
let controller = "ExtensionStepsViewController"
let subview = ExtensionStepsViewController(nibName: NSNib.Name(rawValue: controller), bundle: nil)
self.view.addSubview(subview.view)
这样我会得到像Type Bool has no subscript members
这样的错误,我的文件结构看起来像这样。
SafariExtensionViewController.xib(最初显示的主要 带有登录屏幕)
SafariExtensionViewController.swift
ExtensionStepsViewController.xib(这个视图应该在用户使用时显示 已登录而不是登录屏幕)
ExtensionStepsViewController.swift
我正在使用 xcode 10、swift 4,一切都是新的。
更新
我在 viewDidAppear(如果本地存储中有电子邮件,则显示扩展步骤视图而不是登录屏幕)和登录功能内部都使用了以下块,当登录成功但它没有导航到该 ExtensionStepsView
let controller = "ExtensionStepsViewController"
let subview = ExtensionStepsViewController(nibName: NSNib.Name(rawValue: controller), bundle: nil)
self.view.addSubview(subview.view)
用例是在初始时显示登录,但如果用户已登录,则显示另一个视图,但问题是现在视图已合并
【问题讨论】:
nib 文件中有 UIView 或 UIView 控制器吗? 它来自使用 cocoa 的 NSViewController。 @TushantKhatiwada 你能和我分享你在谷歌驱动器上的例子吗?非常感谢你!!! 【参考方案1】:您收到错误“Bool 类型没有下标成员”,因为 Bundle 的 loadNibNamed(_:owner:topLevelObjects:) 方法返回没有 subscript 成员的 Bool 结构,因此您不能这样写
true[0]
如何正确使用此方法请参阅link 和那里的示例:
var topLevelObjects : NSArray?
if Bundle.main.loadNibNamed(NSNib.Name(rawValue: "ExtensionStepsViewController"), owner: self, topLevelObjects: &topLevelObjects)
let topLevelObjects!.first(where: $0 is NSView ) as? NSView
视图已合并,因为您没有从父视图中删除以前的视图,而是将 ExtensionStepsViewController 中的视图添加到同一个父视图中。
您可以执行以下步骤来完成您的问题:
-
使 SafariExtensionViewController 继承自 SFSafariExtensionViewController,它将成为两个子视图控制器(例如 LoginViewController 和 ExtensionStepsViewController)的容器(和父级),并将用于在它们之间导航。
分别制作 LoginViewController 和 ExtensionStepsViewController(均继承自简单的NSViewController)及其 xib。
就在用户从 LoginViewController 登录 transit 到 ExtensionStepsViewController 之后
作为示例,但您必须使用您的实现 SafariExtensionViewController 而不是 ParentViewController,正如我在第一步中解释的那样。
public protocol LoginViewControllerDelegate: class
func loginViewControllerDidLoginSuccessful(_ loginVC: LoginViewController)
public class LoginViewController: NSViewController
weak var delegate: LoginViewControllerDelegate?
@IBAction func login(_ sender: Any)
// login logic
let isLoginSuccessful = true
if isLoginSuccessful
self.delegate?.loginViewControllerDidLoginSuccessful(self)
public class ExtensionStepsViewController: NSViewController
public class ParentViewController: NSViewController, LoginViewControllerDelegate
weak var login: LoginViewController! // using of force unwrap is anti-pattern. consider other solutions
weak var steps: ExtensionStepsViewController!
public override func viewDidLoad()
let login = LoginViewController(nibName: NSNib.Name(rawValue: "LoginViewController"), bundle: nil)
login.delegate = self
// change login view frame if needed
login.view.frame = self.view.frame
self.view.addSubview(login.view)
// instead of setting login view frame you can add appropriate layout constraints
self.addChildViewController(login)
self.login = login
let steps = ExtensionStepsViewController(nibName: NSNib.Name(rawValue: "ExtensionStepsViewController"), bundle: nil)
steps.view.frame = self.view.frame
self.addChildViewController(steps)
self.steps = steps
// MARK: - LoginViewControllerDelegate
public func loginViewControllerDidLoginSuccessful(_ loginVC: LoginViewController)
self.transition(from: self.login, to: self.steps, options: .slideLeft)
// completion handler logic
print("transition is done successfully")
Here 是这个例子的快速游乐场。
UPD:
您可以通过多种方式实例化 NSViewController:
-
使用NSStoryboard 允许从 .storyboard 文件加载 NSViewController 的视图:
let storyboard = NSStoryboard(name: NSStoryboard.Name("NameOfStoryboard"), bundle: nil)
let viewController = storyboard.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier("NSViewControllerIdentifierInStoryboard"))
-
使用适当的initialiser NSViewController 从 .xib 文件加载它的视图:
let steps = ExtensionStepsViewController(nibName: NSNib.Name(rawValue: "ExtensionStepsViewController"), bundle: nil)
-
使用默认初始化程序,但如果 xib 文件的名称与视图控制器类的名称不同,则必须通过覆盖 loadView() 方法直接加载视图:
let steps = ExtensionStepsViewController()
// Also you have to override loadView() method of ExtensionStepsViewController.
【讨论】:
你能检查一下吗?我试着按照你的解释和代码做,但不明白 logindelegate 代码应该放在哪里gist.github.com/tushantOffice/46dd0c15434144fb42d23882b07b4f15 LoginViewControllerDelegate 是一种协议,类似于来自其他编程语言的接口。你的 SafariExtensionViewController(在第一步中解释)应该符合这个协议并实现它的所有方法。 LoginUIController & ExtensionStepsViewController 可能继承自简单的 NSViewController。 见Delegation pattern 我更新了要点,我这样做了,在login.delegate = self
行中出现错误,它说Cannot assign value of type 'SafariExtensionViewController' to type 'LoginViewControllerDelegate?'
以上是关于视图被合并而不是单独显示的主要内容,如果未能解决你的问题,请参考以下文章