视图被合并而不是分开显示 [英] views are merged instead of showing them separately

查看:70
本文介绍了视图被合并而不是分开显示的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个xib文件,一个显示登录视图,另一个显示成功登录后的操作步骤.我很难使它工作.我创建了不是iOS的macos项目,并使用了safariservices,以便它可以用于safari扩展.

I have two xib file, one which shows login view and another which shows the steps what to do after the login is successful. I am having hard time to make it work. I have created macos project not ios and using safariservices so that it will work for the safari extension either.

这就是我所做的

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的错误,我的文件结构看起来像这样.

This way i get error like Type Bool has no subscript members my file structure looks something like this.

SafariExtensionViewController.xib(最初显示的主要一个 登录屏幕)

SafariExtensionViewController.xib (main one which is shown initially with login screen)

SafariExtensionViewController.swift

SafariExtensionViewController.swift

ExtensionStepsViewController.xib(该视图应在用户 登录而不是登录屏幕

ExtensionStepsViewController.xib(this view should be shown when user is logged in instead of login screen)

ExtensionStepsViewController.swift

ExtensionStepsViewController.swift

我正在使用xcode 10,swift 4,所有新功能.

I am using xcode 10, swift 4, everything new.

更新

我在viewDidAppear中使用了以下代码块(如果localstorage中有电子邮件,则显示扩展步骤视图而不是登录屏幕),并且在登录成功但未导航至该ExtensionStepsView时在登录功能内部使用

I used the following block both in viewDidAppear(if there is email in localstorage then show extension steps view instead of login screen) and inside login function when the login is success but it does not navigate to that ExtensionStepsView

let controller = "ExtensionStepsViewController"
let subview = ExtensionStepsViewController(nibName: NSNib.Name(rawValue: controller), bundle: nil)
self.view.addSubview(subview.view)

用例是一开始显示登录名,但是如果用户登录,则显示另一个视图,但问题是现在合并了视图

Use case is show login at initial but if user is logged in then show another view but issue is now the view are merged

推荐答案

您收到错误"Type Bool没有下标成员",因为返回 Bool 结构,该结构没有下标成员,因此您不能像这样

You got the error "Type Bool has no subscript members" because loadNibNamed(_:owner:topLevelObjects:) method of Bundle returns Bool struct that has no subscript members so you can't write like

true[0]

如何正确使用此方法,请参见链接和那里的示例:

How to use this method correctly see the link and example from there:

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添加到同一超级视图中.

Views were merged because you didn't remove previous views from the superview and added view from ExtensionStepsViewController to the same superview.

您可以按照以下步骤完成问题:

You can do the following steps to complete your issue:

  1. 使SafariExtensionViewController继承自 SFSafariExtensionViewController (将成为容器(和父级),用于两个子视图控制器,例如LoginViewController和ExtensionStepsViewController,将用于在两个子视图控制器之间进行导航.
  2. 分别制作LoginViewController和ExtensionStepsViewController(两者均继承自简单的 NSViewController )及其xib .
  3. 在用户登录后立即从LoginViewController过渡到ExtensionStepsViewController li>
  1. Make SafariExtensionViewController inherited from SFSafariExtensionViewController that will be container (and parent) for two child view controllers such as LoginViewController and ExtensionStepsViewController and will be used to navigate between ones.
  2. Make separately LoginViewController and ExtensionStepsViewController (both inherited from simple NSViewController) and its xibs.
  3. Right after user logins transit from LoginViewController to ExtensionStepsViewController

作为一个示例,您必须使用实现SafariExtensionViewController而不是ParentViewController,正如我在第一步中上面解释的那样.

As an example but instead of ParentViewController you have to use your implementation SafariExtensionViewController as I explain above in the first step.

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 is a swift playground with this example.

UPD:

您可以通过几种方式实例化NSViewController:

You can instantiate NSViewController in several ways:

  1. 使用 NSStoryboard 允许从.storyboard文件加载NSViewController的视图:
  1. Use NSStoryboard that allows to load view of NSViewController from .storyboard file:

let storyboard = NSStoryboard(name: NSStoryboard.Name("NameOfStoryboard"), bundle: nil)
let viewController = storyboard.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier("NSViewControllerIdentifierInStoryboard"))

  1. 使用NSViewController的相应初始化程序从中加载视图.xib文件:
  1. Use appropriate initialiser of NSViewController to load view of it from .xib file:

let steps = ExtensionStepsViewController(nibName: NSNib.Name(rawValue: "ExtensionStepsViewController"), bundle: nil)

  1. 使用默认的初始化程序,但是您必须通过覆盖 loadView()直接加载视图方法,如果xib文件的名称与视图控制器类的名称不同:
  1. Use default initialiser but you have to load view directly by overriding loadView() method if name of xib file is different from name of view controller class:

let steps = ExtensionStepsViewController()
// Also you have to override loadView() method of ExtensionStepsViewController.

这篇关于视图被合并而不是分开显示的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆