草庐IT

ios - Swift 3.1 UITableViewController 作为 subview 或弹出窗口

coder 2024-01-17 原文

我有一个棘手的任务。我有带有两个 tableView、按钮等的 TableUIViewController(父 UIViewController)。此 UIViewController 显示有关咖啡馆中表的信息。

我还有另一个名为 MenuTableViewController 的 Controller (父级是 UITableViewController),它是显示菜单项列表的单独 View 。只有三个 UI 项目 - 每个单元格中有两个标签和按钮。

想法: 我想以两种不同的方式使用这个 MenuTableViewController。

  1. 如果从主菜单转到此 View - 只显示菜单并允许用户编辑每个单元格。 Button.title = "打开"。

  2. 如果 View 是从 TableUIViewController 打开的 - 将按钮标题更改为“选择”,如果按下按钮创建订单等则返回 MenuTableViewController。

我发现 perform segue + prepare for segue 对我有用,但如果我使用 segue,我会遇到导航 Controller 的问题 - 我完全失去了“后退”按钮,无法返回主菜单。

所以我认为我可以使用 AddSubView 或一些弹出窗口执行以下步骤:

  1. 在 TableUIViewController 中点击按钮

  2. 显示 MenuTableViewController

  3. 点击某个按钮

  4. 返回 TableUIViewController - 理想情况下无需任何重新初始化,以保持所有变量及其值。

但我不明白如何在这里使用 AddSubview。有人可以指导我一下吗?或者提供一些例子。在这里没找到什么好东西。

这是我的类(class):

TableUIViewController

import UIKit
import CoreData

class TableUIViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, GuestAtTableTableViewCellDelegate, OrderInTableTableViewCellDelegate {
    //MARK: variables:
    //The following three variables will be set before segue to this view.
    fileprivate let myGenericFunctions = MyGenericFunctions()
    var tableName: String? = nil
    var currentTable: TablesTable? = nil
    var currentTableSession: TableSessionTable? = nil
    let tableSessionTable = TableSessionTable()
    let guestsTable = GuestsTable()
    fileprivate var countOfGuests: Int {
        get {
            guard currentTableSession != nil else {return 0}
            return guestsTable.getActiveGuestsForTable(tableSession: currentTableSession!)!.count
        }
    }
    fileprivate var guestsTableFetchedResultsController: NSFetchedResultsController<GuestsTable>?
    fileprivate var ordersTableFetchedResultsController: NSFetchedResultsController<OrdersTable>?


    //MARK: IBOutlets
    @IBOutlet weak var tableCapacityLabel: UILabel!
    @IBOutlet weak var tableCountOfGuestsLabel: UILabel!
    @IBOutlet weak var tableOpenTimeLabel: UILabel!
    @IBOutlet weak var tableDescriptionTextView: UITextView!
    @IBAction func closeTableButtonPressed(_ sender: UIButton) {
        guard currentTableSession != nil else {return}
        guestsTable.removeAllGuestsForTable(tableSession: currentTableSession!)
        updateGuestsTableView()
        updateOrdersTableView()
        tableSessionTable.removeTableSession(tableSession: currentTableSession!)
        currentTableSession = nil
        updateLabels()
    }
    @IBOutlet weak var guestsTableView: UITableView!
    @IBOutlet weak var ordersTableView: UITableView!

    @IBAction func addGuestButtonPressed(_ sender: UIButton) {
        if currentTableSession == nil {
            currentTableSession = tableSessionTable.createTableSession(table: currentTable!)
        }
        if let capacity = Int(tableCapacityLabel.text!) {
            guard capacity > countOfGuests else {return}
        }

        let guestsTable = GuestsTable()
        guestsTable.addNewGuest(tableSession: currentTableSession!)
        updateGuestsTableView()
        updateLabels()
    }
    @IBAction func addOrderButtonPressed(_ sender: UIButton) {
        guard currentTableSession != nil else {return}



    }


    //MARK: functions:
    override func viewDidLoad() {
        super.viewDidLoad()
        guestsTableView.dataSource = self
        guestsTableView.delegate = self
        ordersTableView.dataSource = self
        ordersTableView.delegate = self

        updateGuestsTableView()
        updateLabels()
    }


    private func updateLabels() {
        tableCapacityLabel.text = String(describing: currentTable!.tableCapacity)
        tableCountOfGuestsLabel.text = String(describing: countOfGuests)
        if currentTableSession != nil {
            tableOpenTimeLabel.text = String(describing: myGenericFunctions.convertDate(inputDate: currentTableSession!.openTime!))
        } else {
            tableOpenTimeLabel.text = " - "
        }
        if currentTable!.tableDescription != nil {
            tableDescriptionTextView.text = currentTable!.tableDescription
        }
    }

    //MARK: Delegates of cell buttons
    func didPressGuestCellButton(guest: GuestsTable) {
        guestsTable.closeGuest(guest: guest)
        updateLabels()
        updateGuestsTableView()
    }

    func didPressOrderCellButton(order: OrdersTable) {

    }

    //MARK: Functions for tableViews update
    private func updateGuestsTableView () {
        guard currentTableSession != nil else {return}
        let tableView = guestsTableView
        let context = AppDelegate.viewContext
        let request : NSFetchRequest<GuestsTable> = GuestsTable.fetchRequest()
        request.predicate = NSPredicate(format: "table= %@", currentTableSession!)
        request.sortDescriptors = [NSSortDescriptor(key: "openTime", ascending: true, selector: #selector(NSString.localizedCaseInsensitiveCompare(_:)))]
        guestsTableFetchedResultsController = NSFetchedResultsController<GuestsTable>(fetchRequest: request, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil)
        try? guestsTableFetchedResultsController?.performFetch()
        tableView?.reloadData()
    }

    private func updateOrdersTableView () {
        let tableView = ordersTableView
        let context = AppDelegate.viewContext
        let request : NSFetchRequest<OrdersTable> = OrdersTable.fetchRequest()
        request.sortDescriptors = [NSSortDescriptor(key: "menuItem", ascending: true, selector: #selector(NSString.localizedCaseInsensitiveCompare(_:)))]
        ordersTableFetchedResultsController = NSFetchedResultsController<OrdersTable>(fetchRequest: request, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil)
        try? ordersTableFetchedResultsController?.performFetch()
        tableView?.reloadData()
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        if tableView == self.guestsTableView {
            let cell = tableView.dequeueReusableCell(withIdentifier: "guestCell", for: indexPath) as! GuestAtTableTableViewCell
            if let guest = guestsTableFetchedResultsController?.object(at: indexPath) {
                cell.guestNameLabel.text = guest.guestName
                cell.openTimeLabel.text = "Пришел: " + myGenericFunctions.convertDate(inputDate: guest.openTime!)
                if let closeTime = guest.closeTime {
                    cell.closeTimeLabel.text = "Ушел: " + myGenericFunctions.convertDate(inputDate: closeTime)
                    cell.closeGuestButton.isEnabled = false
                    cell.guestNameLabel.textColor = UIColor.darkGray
                    cell.openTimeLabel.textColor = UIColor.darkGray
                    cell.closeTimeLabel.textColor = UIColor.darkGray
                }
                cell.cellDelegate = self
                cell.guest = guest
            }
            return cell
        }
        else {
            let cell = tableView.dequeueReusableCell(withIdentifier: "orderCell", for: indexPath)
            return cell
        }
    }

    func numberOfSections(in tableView: UITableView) -> Int {
        if tableView == self.guestsTableView {
            return guestsTableFetchedResultsController?.sections?.count ?? 1
        }
        else if tableView == self.ordersTableView {
            return ordersTableFetchedResultsController?.sections?.count ?? 1
        }
        else {return 1}
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if tableView == self.guestsTableView {
            if let sections = guestsTableFetchedResultsController?.sections, sections.count > 0 {
                return sections[section].numberOfObjects
            }
            else {
                return 0
            }
        }
        else if tableView == self.ordersTableView {
            if let sections = ordersTableFetchedResultsController?.sections, sections.count > 0 {
                return sections[section].numberOfObjects
            }
            else {
                return 0
            }
        }
        else {return 0}
    }

    func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        if tableView == self.guestsTableView {
            if let sections = guestsTableFetchedResultsController?.sections, sections.count > 0 {
                return sections[section].name
            }
            else {
                return nil
            }
        }
        else if tableView == self.ordersTableView {
            if let sections = ordersTableFetchedResultsController?.sections, sections.count > 0 {
                return sections[section].name
            }
            else {
                return nil
            }
        }
        else {return nil}

    }

    func sectionIndexTitles(for tableView: UITableView) -> [String]? {
        if tableView == guestsTableView {
            return guestsTableFetchedResultsController?.sectionIndexTitles
        }
        else {
            return ordersTableFetchedResultsController?.sectionIndexTitles
        }
    }

    func tableView(_ tableView: UITableView, sectionForSectionIndexTitle title: String, at index: Int) -> Int {
        if tableView == guestsTableView {
            return guestsTableFetchedResultsController?.section(forSectionIndexTitle: title, at: index) ?? 0
        }
        else if tableView == ordersTableView {
            return ordersTableFetchedResultsController?.section(forSectionIndexTitle: title, at: index) ?? 0
        }
        else {return 0}
    }

    //Prepare for segues
    /*override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "openMenuToAddOrder" {
            if let menuTVC = segue.destination as? MenuTableViewController {
                menuTVC.isOpenedFromTable = true
                menuTVC.currentTableSession = currentTableSession
                menuTVC.currentTable = currentTable
            }
        }
    }*/
}

ManuTableViewController:

class MenuTableViewController: FetchedResultsTableViewController, MenuTableViewCellDelegate {
    var tableName: String? = nil
    var currentTable: TablesTable? = nil
    var currentTableSession: TableSessionTable? = nil
    var isOpenedFromTable: Bool = false
    let ordersTable = OrdersTable()
    fileprivate var fetchedResultsController: NSFetchedResultsController<MenuTable>?

    override func viewDidLoad() {
        updateMenuTableView()
        self.navigationItem.rightBarButtonItem = self.editButtonItem
    }

    //MARK: delegate of table cell
    func didPressMenuItemCellButton (menuItem: MenuTable) {
        if isOpenedFromTable {
            ordersTable.addOrUpdateOrderForTableSession(tableSession: currentTableSession!, menuItem: menuItem)
            performSegue(withIdentifier: "returnToTableView", sender: self)
        } else {
            //here will be code for editing menu item
        }
    }

    //MARK: Functioms for table view update
    private func updateMenuTableView () {
        let context = AppDelegate.viewContext
        let request : NSFetchRequest<MenuTable> = MenuTable.fetchRequest()
        request.sortDescriptors = [NSSortDescriptor(key: "itemName", ascending: true, selector: #selector(NSString.localizedCaseInsensitiveCompare(_:)))]
        fetchedResultsController = NSFetchedResultsController<MenuTable>(fetchRequest: request, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil)
        fetchedResultsController?.delegate = self
        try? fetchedResultsController?.performFetch()
        tableView.reloadData()
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "menuCell", for: indexPath) as! MenuTableViewCell
        if let menuTable = fetchedResultsController?.object(at: indexPath) {
            cell.menuItemNameLabel.text = menuTable.itemName
            cell.menuItemDescriptionLabel.text = menuTable.itemDescription
            cell.menuItemPriceLabel.text = String(describing: menuTable.itemPrice)
            if isOpenedFromTable == true {
                cell.button.setTitle("Выбрать", for: UIControlState.normal)
            } else {
                cell.button.setTitle("Открыть", for: UIControlState.normal)
            }
            cell.menuItem = menuTable
            cell.cellDelegate = self
        }
        return cell
    }
    //Prepare for segues
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "returnToTableView" {
            if let tableTVC = segue.destination as? TableUIViewController {
                tableTVC.currentTableSession = currentTableSession
                tableTVC.currentTable = currentTable
                tableTVC.tableName = currentTable?.tableName
            }
        }
    }
}

extension MenuTableViewController {
    override func numberOfSections(in tableView: UITableView) -> Int {
        return fetchedResultsController?.sections?.count ?? 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if let sections = fetchedResultsController?.sections, sections.count > 0 {
            return sections[section].numberOfObjects
        }
        else {
            return 0
        }
    }

    override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        if let sections = fetchedResultsController?.sections, sections.count > 0 {
            return sections[section].name
        }
        else {
            return nil
        }
    }

    override func sectionIndexTitles(for tableView: UITableView) -> [String]? {
        return fetchedResultsController?.sectionIndexTitles
    }

    override func tableView(_ tableView: UITableView, sectionForSectionIndexTitle title: String, at index: Int) -> Int {
        return fetchedResultsController?.section(forSectionIndexTitle: title, at: index) ?? 0
    }
}

更新: 这是我的 Storyboard。我有一种感觉,我没有正确使用导航 Controller 。但是在 View 之间没有一些 Controller - 后退按钮不会出现。对不起图片中的俄语文字。

标记为已解决后更新:

我已经删除了 performSegue 并将 controller 中的 segues 放到按钮本身。现在 Navigation controller 保留了 Back 按钮。 还将 Update UI 函数移动到 viewWillAppear 以在 segues 之后保持表更新。

override func viewWillAppear(_ animated: Bool) {
    updateGuestsTableView()
    updateOrdersTableView()
    updateLabels()
    updateOrdersTableView()
}

另一个更新,现在它完全符合我的要求。 我已经添加到由 Menu Cell Button 调用的函数以返回到之前的 ViewController(与 Back 按钮一样):

    //MARK: delegate of table cell
    func didPressMenuItemCellButton (menuItem: MenuTable) {
        if isOpenedFromTable {
            ordersTable.addOrUpdateOrderForTableSession(tableSession: currentTableSession!, 

menuItem: menuItem)
            _ = navigationController?.popViewController(animated: true)
        } else {
            //here will be code for editing menu item
        }
    }

最佳答案

听起来你想要这样的结构:

如果您从主菜单中选择“编辑食物菜单”,您将直接进入“食物菜单”。如果您选择“接单”,您将看到“表格列表”。

如果您选择“编辑食物菜单”,那么您的食物菜单代码应显示“编辑”作为表格中每一行的按钮标题。点击“编辑”将带您进入“编辑菜单项” View 。

如果您选择“接受订单”,然后从列表中选择一张 table ,会将您带到“食物菜单”,但在这种情况下,您的食物菜单代码应显示“订单"作为按钮标题。点击“订购”会将食品添加到您的数据结构中,或者可能会显示确认警报,或者在此时执行任何其他需要的操作。

因为所有 View 都是同一导航 Controller 结构的一部分,所以您始终可以通过选择导航栏上的标准“<>

希望这是有道理的:)

关于ios - Swift 3.1 UITableViewController 作为 subview 或弹出窗口,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44309653/

有关ios - Swift 3.1 UITableViewController 作为 subview 或弹出窗口的更多相关文章

  1. ruby - RSpec - 使用测试替身作为 block 参数 - 2

    我有一些Ruby代码,如下所示:Something.createdo|x|x.foo=barend我想编写一个测试,它使用double代替block参数x,这样我就可以调用:x_double.should_receive(:foo).with("whatever").这可能吗? 最佳答案 specify'something'dox=doublex.should_receive(:foo=).with("whatever")Something.should_receive(:create).and_yield(x)#callthere

  2. ruby - 如何验证 IO.copy_stream 是否成功 - 2

    这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下

  3. Ruby 文件 IO 定界符? - 2

    我正在尝试解析一个文本文件,该文件每行包含可变数量的单词和数字,如下所示:foo4.500bar3.001.33foobar如何读取由空格而不是换行符分隔的文件?有什么方法可以设置File("file.txt").foreach方法以使用空格而不是换行符作为分隔符? 最佳答案 接受的答案将slurp文件,这可能是大文本文件的问题。更好的解决方案是IO.foreach.它是惯用的,将按字符流式传输文件:File.foreach(filename,""){|string|putsstring}包含“thisisanexample”结果的

  4. ruby - 字符串文字中的转义状态作为 `String#tr` 的参数 - 2

    对于作为String#tr参数的单引号字符串文字中反斜杠的转义状态,我觉得有些神秘。你能解释一下下面三个例子之间的对比吗?我特别不明白第二个。为了避免复杂化,我在这里使用了'd',在双引号中转义时不会改变含义("\d"="d")。'\\'.tr('\\','x')#=>"x"'\\'.tr('\\d','x')#=>"\\"'\\'.tr('\\\d','x')#=>"x" 最佳答案 在tr中转义tr的第一个参数非常类似于正则表达式中的括号字符分组。您可以在表达式的开头使用^来否定匹配(替换任何不匹配的内容)并使用例如a-f来匹配一

  5. ruby-on-rails - Rails 3.1 中具有相同形式的多个模型? - 2

    我正在使用Rails3.1并在一个论坛上工作。我有一个名为Topic的模型,每个模型都有许多Post。当用户创建新主题时,他们也应该创建第一个Post。但是,我不确定如何以相同的形式执行此操作。这是我的代码:classTopic:destroyaccepts_nested_attributes_for:postsvalidates_presence_of:titleendclassPost...但这似乎不起作用。有什么想法吗?谢谢! 最佳答案 @Pablo的回答似乎有你需要的一切。但更具体地说...首先改变你View中的这一行对此#

  6. Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting - 2

    1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里

  7. ruby-on-rails - 应用程序的名称是否可以作为变量使用? - 2

    当我创建一个Rails应用程序时,控制台:railsnewfoo我的代码可以使用字符串“foo”吗?puts"Yourapp'snameis"+app_name_bar 最佳答案 Rails.application.class将为您提供应用程序的全名(例如YourAppName::Application)。从那里您可以使用Rails.application.class.parent获取模块名称。 关于ruby-on-rails-应用程序的名称是否可以作为变量使用?,我们在StackOve

  8. ruby-on-rails - 带有 Zeus 的 RSpec 3.1,我应该在 spec_helper 中要求 'rspec/rails' 吗? - 2

    使用rspec-rails3.0+,测试设置分为spec_helper和rails_helper我注意到生成的spec_helper不需要'rspec/rails'。这会导致zeus崩溃:spec_helper.rb:5:in`':undefinedmethod`configure'forRSpec:Module(NoMethodError)对thisissue最常见的回应是需要'rspec/rails'。但这是否会破坏仅使用spec_helper拆分rails规范和PORO规范的全部目的?或者这无关紧要,因为Zeus无论如何都会预加载Rails?我应该在我的spec_helper中做

  9. ruby-on-rails - 使用作为方法的值在 ruby​​ 中搜索哈希 - 2

    我在搜索我的值是方法的散列时遇到问题。我只是不想运行plan_type与键匹配的方法。defmethod(plan_type,plan,user){foo:plan_is_foo(plan,user),bar:plan_is_bar(plan,user),waa:plan_is_waa(plan,user),har:plan_is_har(user)}[plan_type]end目前如果我传入“bar”作为plan_type,所有方法都会运行,我怎么能只运行plan_is_bar方法呢? 最佳答案 这个变体怎么样?defmethod

  10. ruby - 无法在 Ruby 中将 ffmpeg 作为子进程运行 - 2

    我正在尝试使用以下代码通过将ffmpeg实用程序作为子进程运行并获取其输出并解析它来确定视频分辨率:IO.popen'ffmpeg-i'+path_to_filedo|ffmpegIO|#myparsegoeshereend...但是ffmpeg输出仍然连接到标准输出并且ffmepgIO.readlines是空的。ffmpeg实用程序是否需要一些特殊处理?或者还有其他方法可以获得ffmpeg输出吗?我在WinXP和FedoraLinux下测试了这段代码-结果是一样的。 最佳答案 要跟进mouviciel的评论,您需要使用类似pope

随机推荐