【问题标题】:iOS Swift 4 - Show Toast (or Activity Indicator) on tableview didSelectRowAtiOS Swift 4 - 在 tableview didSelectRowAt 上显示 Toast(或活动指示器)
【发布时间】:2017-09-28 19:24:17
【问题描述】:

我正在使用来自this answer 的 ToastView 类,但我在使用活动指示器时遇到了同样的问题。我在整个应用程序中都有 ToastViews,但如果它可以工作,我会毫不犹豫地切换到指示器

我的应用有一个显示选项的表格视图。选择一个选项后,需要加载很多关于该选项的信息,像这样

class TableController : UITableViewController
{
    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        index = (indexPath as NSIndexPath).row
        super.performSegue(withIdentifier: "cellSelectedSegue", sender: self)
    }
}

class cellSelectionView : UIViewController
{
    override func viewDidLoad() {
        super.viewDidLoad()

        if let data = parser.getData(...){
            // data processing
        }
    }
}

我想让用户知道当他们选择一个单元格时正在执行加载操作。否则,一个单元格被选中,呈现单元格选择的颜色,并且应用程序在 segue 发生之前静止一秒钟。

为此,我已经尝试过

// In the tableview:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    // Solution 1: ToastView.showInParent(parentView: self.view, text: "ayy lmao", duration: 1.0)
    // Solution 2: indicator.startAnimating()
   index = (indexPath as NSIndexPath).row
    super.performSegue(withIdentifier: "cellSelectedSegue", sender: self)
}

这两种解决方案都不起作用,因为在单元格选择 UI 事件完成之前不会触发 UI 事件,直到发生数据处理才会完成,这完全违背了这一点。我还尝试将 UI 调用移动到 willSelectRowAt 没有任何区别。 我想知道如何让用户知道涉及 UI 事件的加载任务。

如果您想知道为什么我不在显示单元格之前而不是在选择时进行数据处理,那是因为每行的处理量很大。如果这样做,表格视图将需要很长时间才能出现

【问题讨论】:

  • 我不知道您何时要加载大量数据,以及为什么要加载。例如,您想加载大量数据来填充表格视图吗?还是选择行后要加载大量数据?
  • 你好,达尼洛。它是在选择行之后。该过程是显示表格视图,让用户选择一个单元格,加载有关用户选择的数据,然后在下一个视图中显示选择及其信息

标签: ios swift uitableview uiactivityindicatorview swift4


【解决方案1】:

为您提供一些不同的选择 -

  1. 在推送视图中,将 getData 方法放在 viewDidAppear 中,而不是 viewDidLoad。在viewDidLoad 内完成所有操作之前,视图不会推送。然后您可以在推送的视图上显示加载指示器。
  2. 将UIActivityIndicator 放在单元格内,并决定是否在保存按下单元格索引的变量上显示/动画它,例如indexLoading。然后将indexLoading 设置为按下的单元格的行,并在该索引路径上调用reloadRowsAtIndexPaths。 如果单元格的 indexPath.row 与 indexLoading 匹配,则显示指示符
  3. 在didSelectRow... 上发送通知,将推送视图。收听来自表格视图控制器的通知,并在表格视图上显示加载指示器。

【讨论】:

  • 是的。我将 ToastView 调用从 tableview didSelectRowAt 移到 cellSelectionView viewDidLoad 中。我还将 getData 从 viewDidLoad 中移出,并为 viewDidAppear 添加了一个覆盖。然后我将 getData 放入 viewDidAppear 并添加了保存数据的相关 UI 组件的刷新
  • 结果:单元格被选中,segue 发生(UI 被移交!!),视图控制器将 Toast 扔到它的 UI 堆栈上,视图出现,Toast 被绘制,viewDidAppear 被调用。在 viewDidAppear 内部,数据被处理,然后调用新页面的空白标签来设置/刷新它们的数据。他们被重画了,砰!谢谢
【解决方案2】:

这应该做你想做的。

import UIKit

class ExampleTableViewController: UITableViewController {

    var names : [String] = []
    var activityIndicator : UIActivityIndicatorView?

    override func viewDidLoad() {
        super.viewDidLoad()
        configureActivityIndicator()
        retrieveTableViewData()
    }

    func configureActivityIndicator(){
        activityIndicator = UIActivityIndicatorView(activityIndicatorStyle: .gray)
        activityIndicator?.hidesWhenStopped = true
        activityIndicator?.center = self.view.center
        self.view.addSubview(activityIndicator!)
    }

    func retrieveTableViewData(){
        names = ["John", "Will", "Ana"]
        self.tableView.reloadData()
    }

    func retrieveLoadsOfDataAfterSelectingRow(indexPath: IndexPath){
        // Example of slow code. You would replace this by some background processing.
        // Then when it is finished you would call the next screen.
        activityIndicator?.startAnimating()
        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 5) {
            self.activityIndicator?.stopAnimating()
        }
    }


    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return names.count
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cellIdentifier = "cell"
        var cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier)

        if cell == nil {
            cell = UITableViewCell(style: .default, reuseIdentifier: cellIdentifier)
        }
        cell!.textLabel?.text = names[indexPath.row]
        return cell!
    }

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        retrieveLoadsOfDataAfterSelectingRow(indexPath: indexPath)
    }
}

替换这部分:

 func retrieveLoadsOfDataAfterSelectingRow(indexPath: IndexPath){
        // Example of slow code. You would replace this by some background processing.
        // Then when it is finished you would call the next screen.
        activityIndicator?.startAnimating()
        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 5) {
            self.activityIndicator?.stopAnimating()
        }
    }

通过类似的方式:

func retrieveLoadsOfDataAfterSelectingRow(indexPath: IndexPath){

        activityIndicator?.startAnimating()

        DispatchQueue.global(qos: .background).async {

            // Heavy processing here.
            if let data = parser.getData(...){
                // data processing
            }

            DispatchQueue.main.async {
                self.activityIndicator?.stopAnimating()
               // Call what you want here, to open details screen.
            }


        }

    }

【讨论】:

  • 这只是一个例子。任何繁重的处理都应该在后台线程中进行,以免阻塞 ui。
  • 我已编辑帖子以符合您的需要。不要使用计时器,这只是一个例子。使用第二部分。如果这解决了您的问题,请检查作为解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多