处理一个空的UITableView。 打印一个友好的信息
我有一个UITableView,在某些情况下是空的是合法的。 所以我不想显示应用程序的背景图片,而是喜欢在屏幕上打印一个友好的消息,比如:
这个清单现在是空的
什么是最简单的方法呢?
UITableView的backgroundView属性是你的朋友。
在viewDidLoad
或你reloadData
任何地方,你应该确定你的表是否为空,并用包含UILabel的UIView更新UITableView的backgroundView属性,或者只设置为nil。 而已。
当然可以让UITableView的数据源执行双重任务,并返回一个特殊的“列表是空的”单元格,它使我觉得它是一个混乱。 突然之间numberOfRowsInSection:(NSInteger)section
必须计算其他部分的行数没有被要求确保他们也是空的。 您还需要制作一个具有空信息的特殊单元格。 另外不要忘记,你可能需要改变你的单元格的高度来容纳空的消息。 这一切都是可行的,但似乎是创可贴上的创可贴。
基于这里的答案,这里是一个快速的类,我可以在你的UITableViewController
。
import Foundation import UIKit class TableViewHelper { class func EmptyMessage(message:String, viewController:UITableViewController) { let messageLabel = UILabel(frame: CGRectMake(0,0,viewController.view.bounds.size.width, viewController.view.bounds.size.height)) messageLabel.text = message messageLabel.textColor = UIColor.blackColor() messageLabel.numberOfLines = 0; messageLabel.textAlignment = .Center; messageLabel.font = UIFont(name: "TrebuchetMS", size: 15) messageLabel.sizeToFit() viewController.tableView.backgroundView = messageLabel; viewController.tableView.separatorStyle = .None; } }
在你的UITableViewController
你可以在numberOfSectionsInTableView(tableView: UITableView) -> Int
override func numberOfSectionsInTableView(tableView: UITableView) -> Int { if projects.count > 0 { return 1 } else { TableViewHelper.EmptyMessage("You don't have any projects yet.\nYou can create up to 10.", viewController: self) return 0 } }
从http://www.appcoda.com/pull-to-refresh-uitableview-empty/获得一些帮助;
一种做法是修改数据源,当行数为零时返回1
,并在tableView:cellForRowAtIndexPath:
方法中生成一个特殊用途的单元格(可能具有不同的单元格标识符)。
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { NSInteger actualNumberOfRows = <calculate the actual number of rows>; return (actualNumberOfRows == 0) ? 1 : actualNumberOfRows; } -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { NSInteger actualNumberOfRows = <calculate the actual number of rows>; if (actualNumberOfRows == 0) { // Produce a special cell with the "list is now empty" message } // Produce the correct cell the usual way ... }
如果您有多个需要维护的表视图控制器,这可能会有点复杂,因为有些人最终会忘记插入一个零检查。 一个更好的方法是创build一个UITableViewDataSource
实现的单独实现,该实现总是返回带有可configuration消息的单个行(我们称之为EmptyTableViewDataSource
)。 当由表视图控制器pipe理的数据发生变化时,pipe理更改的代码将检查数据是否为空。 如果它不是空的,请使用常规数据源来设置表视图控制器; 否则,将其设置为已使用相应消息configuration的EmptyTableViewDataSource
实例。
我推荐以下库: DZNEmptyDataSet
将其添加到您的项目中最简单的方法就是像Cocaopods一样使用它: pod 'DZNEmptyDataSet'
在你的TableViewController中添加下面的导入语句(Swift):
import DZNEmptyDataSet
然后确保你的类符合DNZEmptyDataSetSource
和DZNEmptyDataSetDelegate
如下所示:
class MyTableViewController: UITableViewController, DZNEmptyDataSetSource, DZNEmptyDataSetDelegate
在你的viewDidLoad
添加下面几行代码:
tableView.emptyDataSetSource = self tableView.emptyDataSetDelegate = self tableView.tableFooterView = UIView()
现在,您只需显示空白状态即可:
//Add title for empty dataset func titleForEmptyDataSet(scrollView: UIScrollView!) -> NSAttributedString! { let str = "Welcome" let attrs = [NSFontAttributeName: UIFont.preferredFontForTextStyle(UIFontTextStyleHeadline)] return NSAttributedString(string: str, attributes: attrs) } //Add description/subtitle on empty dataset func descriptionForEmptyDataSet(scrollView: UIScrollView!) -> NSAttributedString! { let str = "Tap the button below to add your first grokkleglob." let attrs = [NSFontAttributeName: UIFont.preferredFontForTextStyle(UIFontTextStyleBody)] return NSAttributedString(string: str, attributes: attrs) } //Add your image func imageForEmptyDataSet(scrollView: UIScrollView!) -> UIImage! { return UIImage(named: "MYIMAGE") } //Add your button func buttonTitleForEmptyDataSet(scrollView: UIScrollView!, forState state: UIControlState) -> NSAttributedString! { let str = "Add Grokkleglob" let attrs = [NSFontAttributeName: UIFont.preferredFontForTextStyle(UIFontTextStyleCallout)] return NSAttributedString(string: str, attributes: attrs) } //Add action for button func emptyDataSetDidTapButton(scrollView: UIScrollView!) { let ac = UIAlertController(title: "Button tapped!", message: nil, preferredStyle: .Alert) ac.addAction(UIAlertAction(title: "Hurray", style: .Default, handler: nil)) presentViewController(ac, animated: true, completion: nil) }
这些方法不是强制性的,也可以只显示没有button的空状态。
对于Swift 3
// MARK: - Deal with the empty data set //Add title for empty dataset func title(forEmptyDataSet scrollView: UIScrollView!) -> NSAttributedString! { let str = "Welcome" let attrs = [NSFontAttributeName: UIFont.preferredFont(forTextStyle: UIFontTextStyle.headline)] return NSAttributedString(string: str, attributes: attrs) } //Add description/subtitle on empty dataset func description(forEmptyDataSet scrollView: UIScrollView!) -> NSAttributedString! { let str = "Tap the button below to add your first grokkleglob." let attrs = [NSFontAttributeName: UIFont.preferredFont(forTextStyle: UIFontTextStyle.body)] return NSAttributedString(string: str, attributes: attrs) } //Add your image func image(forEmptyDataSet scrollView: UIScrollView!) -> UIImage! { return UIImage(named: "MYIMAGE") } //Add your button func buttonTitle(forEmptyDataSet scrollView: UIScrollView!, for state: UIControlState) -> NSAttributedString! { let str = "Add Grokkleglob" let attrs = [NSFontAttributeName: UIFont.preferredFont(forTextStyle: UIFontTextStyle.callout)] return NSAttributedString(string: str, attributes: attrs) } //Add action for button func emptyDataSetDidTapButton(_ scrollView: UIScrollView!) { let ac = UIAlertController(title: "Button tapped!", message: nil, preferredStyle: .alert) ac.addAction(UIAlertAction(title: "Hurray", style: .default, handler: nil)) present(ac, animated: true, completion: nil) }
我一直在使用titleForFooterInSection消息。 我不知道这是不是最理想的,但它的作品。
-(NSString*)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section { NSString *message = @""; NSInteger numberOfRowsInSection = [self tableView:self.tableView numberOfRowsInSection:section ]; if (numberOfRowsInSection == 0) { message = @"This list is now empty"; } return message; }
我只能推荐在单元格后拖放一个UITextView到TableView中。 build立与ViewController的连接,并在适当的时候隐藏/显示它(例如,当表重新加载时)。
使用backgroundView是好的,但它不像在Mail.app中很好地滚动。
我做了类似于xtravar的一些事情。
我在tableViewController
的视图层次之外添加了一个视图。
然后我在tableView:numberOfRowsInSection:
使用下面的代码tableView:numberOfRowsInSection:
::
if someArray.count == 0 { // Show Empty State View self.tableView.addSubview(self.emptyStateView) self.emptyStateView.center = self.view.center self.emptyStateView.center.y -= 60 // rough calculation here self.tableView.separatorColor = UIColor.clear } else if self.emptyStateView.superview != nil { // Empty State View is currently visible, but shouldn't self.emptyStateView.removeFromSuperview() self.tableView.separatorColor = nil } return someArray.count
基本上我添加emptyStateView
作为tableView
对象的子视图。 由于分隔符会重叠视图,我将它们的颜色设置为clearColor
。 要回到默认的分隔符颜色,可以将其设置nil
。
首先,其他stream行的方法的问题。
BackgroundView
如果您使用将其设置为UILabel的简单情况,背景视图不会很好地居中。
单元格,页眉或页脚显示消息
这干扰你的function代码,并引入奇怪的边缘情况。 如果你想完美地把你的信息中心,这增加了另一个层次的复杂性。
滚动你自己的表格视图控制器
你失去了内置的function,如refreshControl,并重新发明车轮。 坚持到UITableViewController的最佳可维护的结果。
将UITableViewController添加为子视图控制器
我有一种感觉,你会最终在iOS 7 + contentInset问题 – 加上为什么复杂的东西?
我的解决scheme
我提出的最好的解决scheme(并且,理所当然,这不是理想的)是制作一个可以坐在滚动视图之上的特殊视图,并相应地采取行动。 在iOS 7中,这显然变得复杂了,但是它是可行的。
你必须注意的事情:
- 表分隔符会在reloadData的某个时候被带到前面 – 你需要防范这一点
- contentInset / contentOffset – 在特殊视图中观察这些键
- 键盘 – 如果你不想让键盘挡道,那是另外一个计算
- 自动布局 – 您不能依赖框架更改来定位您的视图
一旦你在一个UIView子类中find了一次,你可以使用它来加载spinners,禁用视图,显示错误消息等等。
和Jhonston的答案一样,但是我更喜欢它作为扩展:
extension UITableView { func setEmptyMessage(_ message: String) { let messageLabel = UILabel(frame: CGRect(x: 0, y: 0, width: self.bounds.size.width, height: self.bounds.size.height)) messageLabel.text = message messageLabel.textColor = .black messageLabel.numberOfLines = 0; messageLabel.textAlignment = .center; messageLabel.font = UIFont(name: "TrebuchetMS", size: 15) messageLabel.sizeToFit() self.backgroundView = messageLabel; self.separatorStyle = .none; } func restore() { self.backgroundView = nil self.separatorStyle = .singleLine } }
用法:
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { if things.count == 0 { self.tableView.setEmptyMessage("My Message") } else { self.tableView.restore() } return things.count }
使用容器视图控制器是正确的方式来执行它根据苹果 。
我把所有空的状态视图放在一个单独的Storyboard中。 每个都有它自己的UIViewController子类。 我直接在他们的根视图下添加内容。 如果需要任何动作/button,您现在已经有一个控制器来处理它。
然后,它只是从该Storyboard实例化所需的视图控制器,将其添加为子视图控制器,并将容器视图添加到tableView的层次结构(子视图)中。 你的空状态视图也可以滚动,这感觉很好,并允许你实现拉刷新。
阅读 “添加子视图控制器到您的内容”一章,了解如何实现的帮助。
只要确保您将子视图框设置为(0, 0, tableView.frame.width, tableView.frame.height)
,事情将居中并正确alignment。
这是最好的和简单的解决scheme。
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 60)]; UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 60)]; label.text = @"This list is empty"; label.center = self.view.center; label.textAlignment = NSTextAlignmentCenter; [view addSubview:label]; self.tableView.backgroundView = view;
Swift版本,但更好,更简单的forms。 ** 3.0
我希望它服务你的目的……
在你的UITableViewController。
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { if searchController.isActive && searchController.searchBar.text != "" { if filteredContacts.count > 0 { self.tableView.backgroundView = .none; return filteredContacts.count } else { Helper.EmptyMessage(message: ConstantMap.NO_CONTACT_FOUND, viewController: self) return 0 } } else { if contacts.count > 0 { self.tableView.backgroundView = .none; return contacts.count } else { Helper.EmptyMessage(message: ConstantMap.NO_CONTACT_FOUND, viewController: self) return 0 } } }
助手类与function:
/* Description: This function generate alert dialog for empty message by passing message and associated viewcontroller for that function - Parameters: - message: message that require for empty alert message - viewController: selected viewcontroller at that time */ static func EmptyMessage(message:String, viewController:UITableViewController) { let messageLabel = UILabel(frame: CGRect(x: 0, y: 0, width: viewController.view.bounds.size.width, height: viewController.view.bounds.size.height)) messageLabel.text = message let bubbleColor = UIColor(red: CGFloat(57)/255, green: CGFloat(81)/255, blue: CGFloat(104)/255, alpha :1) messageLabel.textColor = bubbleColor messageLabel.numberOfLines = 0; messageLabel.textAlignment = .center; messageLabel.font = UIFont(name: "TrebuchetMS", size: 18) messageLabel.sizeToFit() viewController.tableView.backgroundView = messageLabel; viewController.tableView.separatorStyle = .none; }
可能不是最好的解决scheme,但我只是在我的表底部添加一个标签,如果行= 0,那么我将它分配一些文本。 相当容易,并实现你正在尝试用几行代码。
我的桌子上有两个部分(工作和学校)
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { if (jobs.count == 0 && schools.count == 0) { emptyLbl.text = "No jobs or schools" } else { emptyLbl.text = "" }
在故事板中select你的tableviewController场景
拖放UIView添加标签与您的消息(例如:无数据)
在你的TableViewController上创buildUIView(例如yournoDataView)的出口。
并在viewDidLoad
self.tableView.backgroundView = yourNoDataView