我有一个UITableView,在某些情况下,它是合法的,是空的。 因此,而不是显示应用程序的背景图像,我宁愿在屏幕打印友好的消息,如:
这份名单现在是空的
什么是做到这一点的最简单的方法?
我有一个UITableView,在某些情况下,它是合法的,是空的。 因此,而不是显示应用程序的背景图像,我宁愿在屏幕打印友好的消息,如:
这份名单现在是空的
什么是做到这一点的最简单的方法?
UITableView中的backgroundView财产是你的朋友。
在viewDidLoad
或任何地方,你reloadData
你应该确定是否有你的表是空的或不并用含有一个UILabel一个UIView更新的UITableView的backgroundView财产或只是将其设置为nil。 而已。
当然,可能使UITableView中的数据源完成双重任务,并返回一个特殊的“列表为空”电池,它给我的印象是一个杂牌。 突然numberOfRowsInSection:(NSInteger)section
必须计算它没被问,以确保它们是空过其他部分的行数。 您还需要使具有空消息的特殊细胞。 也不要忘记,你需要可能更改单元格的高度,以适应空消息。 这是所有可行的,但它似乎像创可贴的顶部创可贴。
基于这里的答案,这里是一个快速的I类提出,你可以在你使用上UITableViewController
。
import Foundation
import UIKit
class TableViewHelper {
class func EmptyMessage(message:String, viewController:UITableViewController) {
let rect = CGRect(origin: CGPoint(x: 0,y :0), size: CGSize(width: self.view.bounds.size.width, height: self.view.bounds.size.height))
let messageLabel = UILabel(frame: rect)
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/
同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
}
我推荐以下库: DZNEmptyDataSet
添加在您的项目最简单的方法就是用像这样Cocaopods使用它: pod 'DZNEmptyDataSet'
在您的TableViewController添加以下import语句(SWIFT):
import DZNEmptyDataSet
然后确保你的类符合DNZEmptyDataSetSource
和DZNEmptyDataSetDelegate
像这样:
class MyTableViewController: UITableViewController, DZNEmptyDataSetSource, DZNEmptyDataSetDelegate
在您的viewDidLoad
添加以下代码行:
tableView.emptyDataSetSource = self
tableView.emptyDataSetDelegate = self
tableView.tableFooterView = UIView()
现在,所有你需要做的,以显示emptystate是:
//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)
}
这些方法是不是强制性的,它也可能只是表明空状态没有按钮等。
对于斯威夫特4
// MARK: - Deal with the empty data set
// Add title for empty dataset
func title(forEmptyDataSet _: UIScrollView!) -> NSAttributedString! {
let str = "Welcome"
let attrs = [NSAttributedStringKey.font: UIFont.preferredFont(forTextStyle: UIFontTextStyle.headline)]
return NSAttributedString(string: str, attributes: attrs)
}
// Add description/subtitle on empty dataset
func description(forEmptyDataSet _: UIScrollView!) -> NSAttributedString! {
let str = "Tap the button below to add your first grokkleglob."
let attrs = [NSAttributedStringKey.font: UIFont.preferredFont(forTextStyle: UIFontTextStyle.body)]
return NSAttributedString(string: str, attributes: attrs)
}
// Add your image
func image(forEmptyDataSet _: UIScrollView!) -> UIImage! {
return UIImage(named: "MYIMAGE")
}
// Add your button
func buttonTitle(forEmptyDataSet _: UIScrollView!, for _: UIControlState) -> NSAttributedString! {
let str = "Add Grokkleglob"
let attrs = [NSAttributedStringKey.font: UIFont.preferredFont(forTextStyle: UIFontTextStyle.callout), NSAttributedStringKey.foregroundColor: UIColor.white]
return NSAttributedString(string: str, attributes: attrs)
}
// Add action for button
func emptyDataSetDidTapButton(_: 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)
}
这样做会被修改数据源返回的一个方法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
...
}
这可能会有些复杂,如果你有,你需要维护多个表视图控制器,因为有人会忘记插入零检查。 更好的方法是创建一个单独实施的UITableViewDataSource
实现,总是返回单行有可配置消息(姑且称之为EmptyTableViewDataSource
)。 当由你的表视图控制器改变管理数据,管理的变化,如果数据为空,会检查代码。 如果不是空的,其定期的数据源设置你的表视图控制器; 否则,与所述的一个实例设置EmptyTableViewDataSource
已被配置为与相应的消息。
我一直在使用这个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;
}
我只能推荐拖动及细胞后掉落的TableView内一个UITextView。 使到ViewController的连接和隐藏/适当时显示它(例如每当表重新加载)。
因此,对于一个更安全的解决方案:
extension UITableView {
func setEmptyMessage(_ message: String) {
guard self.numberOfRows() == 0 else {
return
}
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.systemFont(ofSize: 14.0, weight: UIFontWeightMedium)
messageLabel.sizeToFit()
self.backgroundView = messageLabel;
self.separatorStyle = .none;
}
func restore() {
self.backgroundView = nil
self.separatorStyle = .singleLine
}
public func numberOfRows() -> Int {
var section = 0
var rowCount = 0
while section < numberOfSections {
rowCount += numberOfRows(inSection: section)
section += 1
}
return rowCount
}
}
和UICollectionView
还有:
extension UICollectionView {
func setEmptyMessage(_ message: String) {
guard self.numberOfItems() == 0 else {
return
}
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.systemFont(ofSize: 18.0, weight: UIFontWeightSemibold)
messageLabel.sizeToFit()
self.backgroundView = messageLabel;
}
func restore() {
self.backgroundView = nil
}
public func numberOfItems() -> Int {
var section = 0
var itemsCount = 0
while section < self.numberOfSections {
itemsCount += numberOfItems(inSection: section)
section += 1
}
return itemsCount
}
}
通用的解决方案:
protocol EmptyMessageViewType {
mutating func setEmptyMessage(_ message: String)
mutating func restore()
}
protocol ListViewType: EmptyMessageViewType where Self: UIView {
var backgroundView: UIView? { get set }
}
extension UITableView: ListViewType {}
extension UICollectionView: ListViewType {}
extension ListViewType {
mutating 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: 16)
messageLabel.sizeToFit()
backgroundView = messageLabel
}
mutating func restore() {
backgroundView = nil
}
}
使用backgroundView是好的,但它并不像Mail.app很好地滚动。
我做了类似的事如何xtravar一样。
我加入的视图层次之外的视图tableViewController
。
然后我用下面的代码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
。
使用容器视图控制器是根据做的正确方法苹果 。
我放在一个单独的故事板所有的空状态的看法。 在每一个它自己的UIViewController子类。 我直接在其根视图下添加内容。 如果需要采取任何行动/按钮,你现在已经有一个控制器来处理它。
然后,它只是实例从故事板所需的视图控制器的问题,将其添加为子视图控制器和容器视图添加到的tableView的层次结构(子视图)。 你的空状态视图会滚动的为好,这感觉很好,让你实现拉刷新。
阅读一章“将一个子视图控制器到您的内容”关于如何实现帮助。
只要确保你设置的子视图帧(0, 0, tableView.frame.width, tableView.frame.height)
和东西会为中心,正确对齐。
首先,与其他流行的方法的问题。
BackgroundView
如果你使用将其设定为一个UILabel的简单情况背景视图不能很好地中心。
细胞,页眉,页脚或显示该消息
这干扰了你的功能代码,并介绍了怪异的边缘情况。 如果你想完全居中你的消息,这增加了复杂性的另一个层面。
滚动自己的表视图控制器
你失去了内置功能,如refreshControl,并重新发明轮子。 坚持的UITableViewController最好维护的结果。
添加的UITableViewController作为一个子视图控制器
我有一种感觉,你会在iOS的7+ contentInset问题结束 - 加为什么事情复杂化?
我的解决办法
最好的解决办法,我想出了(和,当然,这是不理想)是使能坐在一个滚动视图的顶部,并采取相应的行动特别景致。 这显然变得复杂,在iOS的7 contentInset疯狂,但它是可行的。
事情你必须要注意:
一旦你有这样一个UIView子类一旦想通了,你可以用它的一切 - 装载纺纱,禁用的观点,显示错误信息,等等。
这是最好的和简单的解决方案。
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;
显示信息为空单,阉了的UITableView或UICollectionView。
extension UIScrollView {
func showEmptyListMessage(_ message:String) {
let rect = CGRect(origin: CGPoint(x: 0,y :0), size: CGSize(width: self.bounds.size.width, height: self.bounds.size.height))
let messageLabel = UILabel(frame: rect)
messageLabel.text = message
messageLabel.textColor = .black
messageLabel.numberOfLines = 0
messageLabel.textAlignment = .center
messageLabel.font = UIFont.systemFont(ofSize: 15)
messageLabel.sizeToFit()
if let `self` = self as? UITableView {
self.backgroundView = messageLabel
self.separatorStyle = .none
} else if let `self` = self as? UICollectionView {
self.backgroundView = messageLabel
}
}
}
用途:
if cellsViewModels.count == 0 {
self.tableView.showEmptyListMessage("No Product In List!")
}
要么:
if cellsViewModels.count == 0 {
self.collectionView?.showEmptyListMessage("No Product In List!")
}
记住:不要忘记删除消息标签的情况下,数据会刷新之后。
在故事板中选择您tableviewController场景
拖放的UIView添加标签与你的消息(如:无数据)
创建UIView的出口(说的如yournoDataView)在您的TableViewController。
在viewDidLoad中
self.tableView.backgroundView = yourNoDataView
斯威夫特的版本,但更好和更简单的形式。 ** 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
}
}
}
辅助类具有功能:
/* 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;
}
也许不是最好的解决办法,但我刚好把一个标签,在我的桌子的底部,如果行= 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 = ""
}
要做到这一点,最简单快捷的方法是拖动标签上侧板的tableView下。 创建标签和一个的tableView出口,并添加一个if语句来隐藏和显示标签和表需要。 或者,也可以添加tableView.tableFooterView = UIView的(帧:CGRect.zero)这对你viewDidLoad中(),得到一个空表的感知如果表和背景视图具有相同的颜色,它是隐藏的。
使用雨燕4.2
func numberOfSections(in tableView: UITableView) -> Int
{
var numOfSections: Int = 0
if self.medArray.count > 0
{
tableView.separatorStyle = .singleLine
numOfSections = 1
tableView.backgroundView = nil
}
else
{
let noDataLabel: UILabel = UILabel(frame: CGRect(x: 0, y: 0, width: tableView.bounds.size.width, height: tableView.bounds.size.height))
noDataLabel.text = "No Medicine available.Press + to add New Pills "
noDataLabel.textColor = UIColor.black
noDataLabel.textAlignment = .center
tableView.backgroundView = noDataLabel
tableView.separatorStyle = .none
}
return numOfSections
}