如何使用表格视图不可用的内容

问题描述 投票:0回答:1

我正在尝试实现当表视图中没有项目时 uikit 内容不可用。配置看起来很简单,但我很困惑将其放置在哪里,因此它会显示表何时没有添加对象。

我尝试将配置放在有条件和无条件的 viewWillAppear 中。当放置在条件中时,添加时列表中不会出现任何对象。如果我删除条件,则会添加对象,但内容不可用信息仍然存在。

我也尝试在表视图中执行相同的操作,但得到了相同的结果。

这个应用程序非常简单,主要用于练习。我有两个视图控制器,第一个视图控制器应该有内容不可用。第二个视图控制器有一个表格视图中呈现的对象数组。如果用户增加步进器,这些对象将被传递到初始视图控制器,并且不可用的内容应该消失。对此的任何帮助表示赞赏。

第一个视图控制器

class KitViewController: UIViewController {
    
    let user = User()
    
    
    @IBOutlet weak var tableView: UITableView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        initializeTable()
        title = "Gear"
    }
    // initialize a new empty array of essential objects assigned to tableItems
    var tableItems = [Essential]()
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        if tableItems.count == 0 {
            var config = UIContentUnavailableConfiguration.empty()
            
            config.image = UIImage(systemName: "figure.hiking")
            config.text = "You don't have any gear"
            config.secondaryText = "Add items and get hiking"
            self.contentUnavailableConfiguration = config
        } else {
            // assign the users table items to table items
            tableItems = User.userTableItems(user: user)
            tableView.reloadData()
        }
  
    }
    
    @IBSegueAction func plusButtonTapped(_ coder: NSCoder) -> ListViewController? {
        return ListViewController(coder: coder, user: user)
    }
    
    func initializeTable() {
        tableView.delegate = self
        tableView.dataSource = self
    }
    
}


extension KitViewController: UITableViewDataSource, UITableViewDelegate {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        
        // if the no table items are in the essential array no table cells will appear
        return tableItems.count
        
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: K.categoryReuseID, for: indexPath)
        // setup the table cell
        
            let kitItem = tableItems[indexPath.row]
            var content = cell.defaultContentConfiguration()
            
            content.text = "\(kitItem.count) \(kitItem.itemName)"
            cell.contentConfiguration = content
            
            
        return cell
    }
    
}

第二个视图控制器


import UIKit

class ListViewController: UIViewController {
    
    @IBOutlet weak var tableView: UITableView!
    @IBOutlet weak var addCustomButton: UIBarButtonItem!
    // pass the user to the list view
    var user: User
    
    init(coder: NSCoder, user: User) {
        self.user = user
        
        super.init(coder: coder)!
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        tableView.dataSource = self
        tableView.delegate = self
        tableView.register(UINib(nibName: K.cellNibName, bundle: nil), forCellReuseIdentifier: K.categoryReuseID)
        title = "Select Gear"
    }

extension ListViewController: UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // returns the users datasource essential objects array
        return user.datasource.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: K.categoryReuseID, for: indexPath) as! MessageCell
        let item = user.datasource[indexPath.row]

        cell.item = item
        cell.cellLabel.text = item.itemName
        cell.cellStepper.value = Double(item.count)
        cell.countLabel.text = String(item.count)

        return cell
    }
    
    
}

swift configuration uikit contentplaceholder
1个回答
0
投票

使用

UIContentUnavailableConfiguration
的做法是正确的,但关键是每当数据发生变化时更新配置并重新加载表视图。以下是修改代码的方法:

第一个视图控制器(KitViewController)

class KitViewController: UIViewController {
    
    let user = User()
    @IBOutlet weak var tableView: UITableView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        initializeTable()
        title = "Gear"
    }

    var tableItems = [Essential]() {
        didSet { // This will be called whenever tableItems is changed
            updateContentUnavailableView()
        }
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        // Load data from User (assuming it's updated when you return from the second VC)
        tableItems = User.userTableItems(user: user)
        tableView.reloadData()
    }

    @IBSegueAction func plusButtonTapped(_ coder: NSCoder) -> ListViewController? {
        return ListViewController(coder: coder, user: user)
    }

    func initializeTable() {
        tableView.delegate = self
        tableView.dataSource = self
    }
    
    // Function to update the content unavailable view
    private func updateContentUnavailableView() {
        if tableItems.isEmpty {
            let config = UIContentUnavailableConfiguration.empty()
            config.image = UIImage(systemName: "figure.hiking")
            config.text = "You don't have any gear"
            config.secondaryText = "Add items and get hiking"
            tableView.backgroundView = nil // Remove any existing background view
            tableView.separatorStyle = .none // Hide separators
            tableView.backgroundView = UIView(frame: tableView.bounds) // Set up a background view
            tableView.backgroundView?.backgroundColor = .systemBackground // Set background color
            self.tableView.backgroundView?.addSubview(UILabel(text: "No Data", textColor: .label, font: .systemFont(ofSize: 20, weight: .bold), textAlignment: .center, numberOfLines: 0, adjustsFontSizeToFitWidth: true)) // Add a label
        } else {
            tableView.backgroundView = nil // Remove content unavailable view
            tableView.separatorStyle = .singleLine // Restore separators
        }
    }
}

extension KitViewController: UITableViewDataSource, UITableViewDelegate {

        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        
        // if the no table items are in the essential array no table cells will appear
        return tableItems.count
        
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: K.categoryReuseID, for: indexPath)
        // setup the table cell
        
            let kitItem = tableItems[indexPath.row]
            var content = cell.defaultContentConfiguration()
            
            content.text = "\(kitItem.count) \(kitItem.itemName)"
            cell.contentConfiguration = content
            
            
        return cell
    }
    
}

说明:

  1. tableItems
    didSet
    :
    我们在
    didSet
    上使用属性观察器 (
    tableItems
    ),而不是单独的变量。每当
    updateContentUnavailableView
    的值发生变化时,该观察者都会自动调用
    tableItems
  2. updateContentUnavailableView()
    :
    此函数检查
    tableItems
    是否为空。
    • 如果为空,则会在表格视图上配置并设置
      contentUnavailableConfiguration
    • 如果不为空,则会将
      contentUnavailableConfiguration
      设置为
      nil
      以删除占位符视图。
  3. 调用
    tableView.reloadData()
    我们在
    tableView.reloadData()
    中更新
    tableItems
    后调用
    viewWillAppear
    来刷新表格视图,并在需要时应用内容不可用配置。

第二个视图控制器(ListViewController)

  • 通知第一个视图控制器:用户递增步进器并更新
    user
    对象后,您需要通知第一个视图控制器更新其数据。 有几种常见的方法:
    • 委托模式:在第二个视图控制器中创建委托协议,并让第一个视图控制器遵循它。当数据发生变化时调用委托方法。
    • 闭包:将闭包从第一个视图控制器传递到第二个视图控制器,并在数据更改时调用闭包。
    • 通知中心:当数据发生变化时发布通知,并让第一个视图控制器观察该通知。

使用委托模式的示例:

// ListViewController.swift
protocol ListViewControllerDelegate: AnyObject {
    func didUpdateItems() 
}

class ListViewController: UIViewController {

    // ... your other code ...

    weak var delegate: ListViewControllerDelegate?

    // Call this method when the user updates the items
    func updateItems() {
        // ... your logic for updating items ...
        delegate?.didUpdateItems() 
    }
}
// KitViewController.swift
// ... (in your prepare(for segue:) method)
if let listVC = segue.destination as? ListViewController {
    listVC.user = user
    listVC.delegate = self
}

// ... (conform to ListViewControllerDelegate)
extension KitViewController: ListViewControllerDelegate {
    func didUpdateItems() {
        tableItems = User.userTableItems(user: user) // Update tableItems from the user object
        tableView.reloadData() 
    }
} 

通过实现其中一种通信模式,当数据更改时,第一个视图控制器将收到通知,从而允许其更新表视图并根据需要显示或隐藏内容不可用的视图。

© www.soinside.com 2019 - 2024. All rights reserved.