Swift:带有建议标签列表的 NSTextfield 和 popover

Swift: NSTextfield and popover with suggested list of tags

我正在尝试做这样的事情:

这是我现在拥有的:

我现在是怎么做的:

我有 MainViewController 输入字段:NSTextField。 使用 controlTextDidChange 我正在检查输入字段是否包含 # 字符。

如果是 - 我将使用 PopoverViewController 打开弹出框。 在 PopoverViewController 中,我有 NSTableView 显示可用标签列表。

通过单击该行,它应该将选定的标签添加到输入字段并关闭弹出窗口。 所以在这里我什至必须在 2 个视图控制器之间实现 2 种通信方式。

问题:

  1. 我觉得我做错了什么。这个 tags-popover 的逻辑对我来说看起来太复杂了。也许存在更简单的解决方案,但我只是不知道该怎么做。
  2. NSTextField 中显示可用标签列表的最佳方式是什么?我应该将弹出窗口与另一个视图控制器一起使用吗?
  3. 在这种情况下,如何在 2 个不同的视图控制器之间进行最佳通信? (我必须将 InputField 值发送到 PopoverViewController,在那里过滤结果并显示它们。然后,我必须发送回 MainViewController 选定的标签)

我的代码:

如果您想更详细地查看代码,这里是我的部分代码:

主视图控制器:

class ViewController: NSViewController, NSTextFieldDelegate {

@IBOutlet weak var InputField: NSTextField!

override func viewDidLoad() {
    super.viewDidLoad()

    table.delegate = self
    table.dataSource = self
    InputField.delegate = self
}

func controlTextDidChange(_ sender: Notification) {

    if InputField.stringValue.contains("#") {

        let controller = ToolTipVC.Controller()
         let popover = NSPopover()

         popover.contentViewController = controller
         popover.behavior = .transient
         popover.animates = true

         popover.show(relativeTo: InputField.bounds, of: InputField!, preferredEdge: NSRectEdge.maxY)
    } 
}

ToolTipViewController:

import Cocoa
import EventKit


class ToolTipVC: NSViewController, NSTableViewDataSource, NSTableViewDelegate {

    @IBOutlet weak var ToolTipTable: NSTableView!

    override func viewDidLoad() {
        super.viewDidLoad()
        ToolTipTable.delegate = self
        ToolTipTable.dataSource = self
    }

    func numberOfRows(in tableView: NSTableView) -> Int {
        return ReminderLists.count
    }

    func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {

        guard let cell = tableView.makeView(withIdentifier: tableColumn!.identifier, owner: self) as? NSTableCellView else { return nil }

        cell.textField?.stringValue = "Row #\(row): " + ReminderLists[row].title
        return cell
    }
}

extension ToolTipVC {
  static func Controller() -> ToolTipVC {

    let storyboard = NSStoryboard(name: "Main", bundle: nil)
    let identifier = NSStoryboard.SceneIdentifier("ToolTipId")
    guard let viewcontroller = storyboard.instantiateController(withIdentifier: identifier) as? ToolTipVC else {
      fatalError("Why cant i find viewcontroller? - Check Main.storyboard")
    }

    return viewcontroller
  }
}

感谢您的反馈和建议。 提前致谢!

P.S.: 我不是开发人员,我是产品经理。这是我的宠物项目,所以我知道我的代码很糟糕并且有很多错误。 请不要苛刻地评判我:)

乍一看,当您调用此行时:

popover.show(relativeTo: InputField.bounds, of: InputField!, preferredEdge: NSRectEdge.maxY)

preferredEdge 设置为 NSRectEdge.maxY

尝试将其从 Y 更改为 X

popover.show(relativeTo: InputField.bounds, of: InputField!, preferredEdge: NSRectEdge.maxX)

您使用 NSPopover 有什么原因吗?

如果这不起作用试试这个:

   let controller = MyPopViewController()
   controller.modalPresentationStyle = UIModalPresentationStyle.popover
   let popController = controller.popoverPresentationController
   popController?.permittedArrowDirections = .any
   popController?.delegate = self
   popController?.sourceRect = //set the frame here
   popController?.sourceView = //set the source view here
   self.present(controller, animated: true, completion: nil)

这是另一种方法,它会将弹出窗口置于按钮上方的中心。我假设没有向上箭头,你想做什么?那是对的吗? 所以你可以点击右侧的过滤器按钮,这个弹出窗口将显示在中心。

@IBAction func buttonTap(sender: UIButton) {

    // get a reference to the view controller for the popover
    let popController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "popoverId")

    // set the presentation style
    popController.modalPresentationStyle = UIModalPresentationStyle.popover

    // set up the popover presentation controller
    popController.popoverPresentationController?.permittedArrowDirections = UIPopoverArrowDirection.up
    popController.popoverPresentationController?.delegate = self
    popController.popoverPresentationController?.sourceView = sender // button
    popController.popoverPresentationController?.sourceRect = sender.bounds

    // present the popover
    self.present(popController, animated: true, completion: nil)
}