iOS Swift 4 - 在 tableview didSelectRowAt 上显示 Toast(或 Activity 指示器)
iOS Swift 4 - Show Toast (or Activity Indicator) on tableview didSelectRowAt
我正在使用 this answer 的 ToastView class,但我在使用 activity 指示器时遇到了同样的问题。我在整个应用程序中都有 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 事件的加载任务。
如果您想知道为什么我不在显示单元格之前进行数据处理而不是在选择时进行数据处理,那是因为每行的处理量很大。如果这样做,tableview 将需要很长时间才能出现
这应该可以满足您的要求。
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.
}
}
}
几个不同的选项供您选择 -
- 在您的推送视图中,将您的
getData
方法放在 viewDidAppear
而不是 viewDidLoad
中。在 viewDidLoad
内完成所有操作之前,视图不会推送。然后您可以在推送视图上显示您的加载指示器。
- 在单元格内放置一个
UIActivityIndicator
并取决于是否 show/animate 它取决于一个变量,该变量保存按下的单元格的索引,例如 indexLoading
。然后将 indexLoading
设置为按下的单元格行,并在该索引路径上调用 reloadRowsAtIndexPaths
。 如果单元格的 indexPath.row
匹配 indexLoading
,则显示指示符
- 在
didSelectRow...
上发送将推送视图的通知。从您的 table 视图控制器收听该通知,并在您的 table 视图上显示加载指示器。
我正在使用 this answer 的 ToastView class,但我在使用 activity 指示器时遇到了同样的问题。我在整个应用程序中都有 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 事件的加载任务。
如果您想知道为什么我不在显示单元格之前进行数据处理而不是在选择时进行数据处理,那是因为每行的处理量很大。如果这样做,tableview 将需要很长时间才能出现
这应该可以满足您的要求。
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.
}
}
}
几个不同的选项供您选择 -
- 在您的推送视图中,将您的
getData
方法放在viewDidAppear
而不是viewDidLoad
中。在viewDidLoad
内完成所有操作之前,视图不会推送。然后您可以在推送视图上显示您的加载指示器。 - 在单元格内放置一个
UIActivityIndicator
并取决于是否 show/animate 它取决于一个变量,该变量保存按下的单元格的索引,例如indexLoading
。然后将indexLoading
设置为按下的单元格行,并在该索引路径上调用reloadRowsAtIndexPaths
。 如果单元格的indexPath.row
匹配indexLoading
,则显示指示符 - 在
didSelectRow...
上发送将推送视图的通知。从您的 table 视图控制器收听该通知,并在您的 table 视图上显示加载指示器。