Mam UITableView, który w niektórych przypadkach może być pusty. Zamiast więc wyświetlać obraz tła aplikacji, wolałbym wydrukować przyjazny komunikat na ekranie, taki jak:
Ta lista jest teraz pusta
Jaki jest najprostszy sposób na zrobienie tego?
Mam UITableView, który w niektórych przypadkach może być pusty. Zamiast więc wyświetlać obraz tła aplikacji, wolałbym wydrukować przyjazny komunikat na ekranie, taki jak:
Ta lista jest teraz pusta
Jaki jest najprostszy sposób na zrobienie tego?
Odpowiedzi:
Właściwość backgroundView UITableView jest Twoim przyjacielem.
W viewDidLoad
lub w dowolnym miejscu, w którym reloadData
powinieneś określić, czy twoja tabela jest pusta, czy nie, i zaktualizuj właściwość backgroundView UITableView za pomocą UIView zawierającego UILabel lub po prostu ustaw ją na zero. Otóż to.
Jest oczywiście możliwe, aby źródło danych UITableView pełniło podwójną funkcję i zwracało specjalną komórkę „lista jest pusta”, co wydaje mi się niezdarne. Nagle numberOfRowsInSection:(NSInteger)section
musi obliczyć liczbę wierszy innych sekcji, o które nie pytano, aby upewnić się, że są również puste. Musisz także utworzyć specjalną komórkę, która ma pustą wiadomość. Nie zapominaj również, że prawdopodobnie musisz zmienić wysokość komórki, aby pomieścić pustą wiadomość. To wszystko jest wykonalne, ale wydaje się, że oprócz pomocy bandażowej.
backgroundView
ukrytą właściwość jest drogą do zrobienia. Z DZNEmptyDataSet
, musimy użyć jegoemptyDataSetSource
tableView.backgroundView!.userInteraction = true
po ustawieniu linii tableView.backgroundView = constructMyViewWithButtons()
lub w inny sposób.
To samo, co odpowiedź Jhonstona, ale wolałem to jako rozszerzenie:
import UIKit
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
}
}
Stosowanie:
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
}
func numberOfSections(in tableView: UITableView) -> Int
metody
W oparciu o odpowiedzi tutaj, oto krótkie zajęcia, które stworzyłem, z których możesz korzystać w swoim 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;
}
}
W swoim UITableViewController
możesz to wywołać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
}
}
Z niewielką pomocą http://www.appcoda.com/pull-to-refresh-uitableview-empty/
viewController.tableView.separatorStyle = .none
nie jest wymagane.
Polecam bibliotekę: DZNEmptyDataSet
Najłatwiejszym sposobem dodania go do projektu jest użycie go z Cocaopodami w następujący sposób: pod 'DZNEmptyDataSet'
W swoim TableViewController dodaj następującą instrukcję importu (Swift):
import DZNEmptyDataSet
Następnie upewnij się, że klasa jest zgodna ze DNZEmptyDataSetSource
i DZNEmptyDataSetDelegate
tak:
class MyTableViewController: UITableViewController, DZNEmptyDataSetSource, DZNEmptyDataSetDelegate
W twojej viewDidLoad
dodać następujące wiersze kodu:
tableView.emptyDataSetSource = self
tableView.emptyDataSetDelegate = self
tableView.tableFooterView = UIView()
Teraz wszystko, co musisz zrobić, aby wyświetlić pusty stan, to:
//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)
}
Te metody nie są obowiązkowe, można też po prostu pokazać stan pusty bez przycisku itp.
Dla Swift 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)
}
Jednym ze sposobów byłoby zmodyfikowanie źródła danych tak, aby zwracało się, 1
gdy liczba wierszy wynosi zero, i utworzenie w tableView:cellForRowAtIndexPath:
metodzie komórki specjalnego przeznaczenia (być może z innym identyfikatorem komórki) .
-(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
...
}
Może się to nieco skomplikować, jeśli masz wiele kontrolerów widoku tabeli, które musisz utrzymywać, ponieważ ktoś w końcu zapomni wstawić zerową kontrolę. Lepszym podejściem jest utworzenie osobnej implementacji UITableViewDataSource
implementacji, która zawsze zwraca pojedynczy wiersz z konfigurowalnym komunikatem (nazwijmy to EmptyTableViewDataSource
). Gdy dane zarządzane przez kontroler widoku tabeli ulegną zmianie, kod zarządzający zmianą sprawdzi, czy dane są puste. Jeśli nie jest pusty, ustaw kontroler widoku tabeli na jego zwykłe źródło danych; w przeciwnym razie ustaw go za pomocą instancji EmptyTableViewDataSource
, która została skonfigurowana za pomocą odpowiedniego komunikatu.
deleteRowsAtIndexPaths:withRowAnimation:
ponieważ liczba zwrócona z numberOfRowsInSection
musi pasować do wyniku $ numRows - $ rowsDeleted.
W tym celu używam wiadomości titleForFooterInSection. Nie wiem, czy jest to nieoptymalne, czy nie, ale działa.
-(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;
}
return tableView.numberOfRowsInSection(section) == 0 ? "This list is now empty" : nil
Więc dla bezpieczniejszego rozwiązania:
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
}
}
a UICollectionView
także:
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
}
}
Bardziej ogólne rozwiązanie:
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
}
}
Mogę tylko polecić przeciągnięcie i upuszczenie UITextView wewnątrz TableView po komórkach. Nawiąż połączenie z ViewController i ukryj / wyświetl go w razie potrzeby (np. Za każdym razem, gdy tabela zostanie ponownie załadowana).
Korzystanie z backgroundView jest w porządku, ale nie przewija się tak dobrze, jak w Mail.app.
Zrobiłem coś podobnego do tego, co zrobił xtravar .
Dodałem widok poza hierarchią widoków tableViewController
.
Następnie użyłem następującego kodu w 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
Zasadniczo dodałem emptyStateView
jako podwidok tableView
obiektu. Ponieważ separatory zachodziłyby na widok, ustawiłem ich kolor na clearColor
. Aby powrócić do domyślnego koloru separatora, możesz po prostu ustawić go na nil
.
tableHeaderView
i upewnić się, że dopasowuje się do rozmiaru .
Według Apple używanie kontrolera widoku kontenera jest właściwym sposobem na zrobienie tego .
Umieściłem wszystkie moje puste widoki stanu w oddzielnym Storyboard. Każdy w swojej własnej podklasie UIViewController. Treść dodaję bezpośrednio pod ich głównym widokiem. Jeśli potrzebna jest jakakolwiek akcja / przycisk, masz już kontroler do jej obsługi.
Następnie wystarczy utworzyć wystąpienie żądanego kontrolera widoku z tego Storyboard, dodać go jako kontroler widoku podrzędnego i dodać widok kontenera do hierarchii tableView (widok podrzędny). Twój pusty widok stanu będzie również przewijalny, co jest przyjemne i pozwala na zaimplementowanie przeciągania w celu odświeżenia.
Przeczytaj rozdział „Dodawanie kontrolera widoku podrzędnego do treści”, aby uzyskać pomoc dotyczącą implementacji.
Po prostu upewnij się, że podrzędna ramka widoku jest ustawiona jako,
(0, 0, tableView.frame.width, tableView.frame.height)
a elementy zostaną odpowiednio wyśrodkowane i wyrównane.
Po pierwsze, problemy z innymi popularnymi podejściami.
BackgroundView
Widok tła nie jest ładnie wyśrodkowany, jeśli użyjesz prostego przypadku ustawienia go jako UILabel.
Komórki, nagłówki lub stopki do wyświetlenia wiadomości
To zakłóca twój kod funkcjonalny i wprowadza dziwne przypadki skrajne. Jeśli chcesz idealnie wyśrodkować swój przekaz, dodaje to kolejnego poziomu złożoności.
Rolling własnego kontrolera widoku tabeli
Tracisz wbudowane funkcje, takie jak refreshControl, i ponownie wymyślasz koło. Trzymaj się UITableViewController, aby uzyskać najlepsze możliwe do utrzymania wyniki.
Dodawanie UITableViewController jako kontrolera widoku podrzędnego
Mam przeczucie, że skończysz z problemami z zawartością w iOS 7+ - plus po co komplikować sprawy?
Moje rozwiązanie
Najlepszym rozwiązaniem, które wymyśliłem (i oczywiście nie jest to idealne rozwiązanie) jest utworzenie specjalnego widoku, który można umieścić na widoku przewijania i odpowiednio działać. To oczywiście komplikuje się w iOS 7 z szaleństwem contentInset, ale jest to wykonalne.
Na co musisz uważać:
Gdy już raz to zrozumiesz w jednej podklasie UIView, możesz jej użyć do wszystkiego - ładowania spinnerów, wyłączania widoków, wyświetlania komunikatów o błędach itp.
addSubView
, jest dołączony do widoku tabeli, co zawsze powoduje problemy z automatycznym układem.
To najlepsze i najprostsze rozwiązanie.
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;
Pokaż wiadomość dla pustej listy, Wether jej UITableView lub 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
}
}
}
Zastosowania:
if cellsViewModels.count == 0 {
self.tableView.showEmptyListMessage("No Product In List!")
}
LUB:
if cellsViewModels.count == 0 {
self.collectionView?.showEmptyListMessage("No Product In List!")
}
Pamiętaj: nie zapomnij usunąć etykiety wiadomości na wypadek, gdyby dane pojawiały się po odświeżeniu.
Wybierz scenę tableviewController w serii ujęć
Przeciągnij i upuść UIView Dodaj etykietę wraz z wiadomością (np .: Brak danych)
utwórz wylot UIView (powiedzmy na przykład yournoDataView) na swoim TableViewController.
i in viewDidLoad
self.tableView.backgroundView = yourNoDataView
Korzystanie ze Swift 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
}
Możesz dodać to do swojej klasy podstawowej.
var messageLabel = UILabel()
func showNoDataMessage(msg: String) {
let rect = CGRect(origin: CGPoint(x: 0, y :self.view.center.y), size: CGSize(width: self.view.bounds.width - 16, height: 50.0))
messageLabel = UILabel(frame: rect)
messageLabel.center = self.view.center
messageLabel.text = msg
messageLabel.numberOfLines = 0
messageLabel.textColor = Colors.grayText
messageLabel.textAlignment = .center;
messageLabel.font = UIFont(name: "Lato-Regular", size: 17)
self.view.addSubview(messageLabel)
self.view.bringSubviewToFront(messageLabel)
}
Pokaż to w ten sposób w klasie na temat pobierania danych z interfejsu API.
func populateData(dataSource : [PRNJobDataSource]){
self.dataSource = dataSource
self.tblView.reloadData()
if self.dataSource.count == 0 {self.showNoDataMessage(msg: "No data found.")}
}
Ukryj to w ten sposób.
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if self.dataSource.count > 0 {self.hideNoDataMessage()}
return dataSource.count
}
func hideNoDataMessage(){
messageLabel.removeFromSuperview()
}
Szybka wersja, ale lepsza i prostsza forma. ** 3.0
Mam nadzieję, że spełni Twoje cele ......
W Twoim 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
}
}
}
Klasa pomocnicza z funkcją:
/* 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;
}
Prawdopodobnie nie jest to najlepsze rozwiązanie, ale zrobiłem to, po prostu umieszczając etykietę na dole mojej tabeli i jeśli wiersze = 0, przypisuję jej jakiś tekst. Całkiem proste i osiąga to, co próbujesz zrobić, za pomocą kilku wierszy kodu.
Mam dwie sekcje w mojej tabeli (praca i szkoły)
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if (jobs.count == 0 && schools.count == 0) {
emptyLbl.text = "No jobs or schools"
} else {
emptyLbl.text = ""
}
Najłatwiejszym i najszybszym sposobem na to jest przeciągnięcie etykiety na panel boczny pod tableView. Utwórz wylot dla etykiety i tableView i dodaj instrukcję if, aby ukryć i wyświetlić etykietę i tabelę w razie potrzeby. Alternatywnie możesz dodać tableView.tableFooterView = UIView (frame: CGRect.zero) to do ciebie viewDidLoad (), aby nadać pustej tabeli wrażenie, że jest ona ukryta, jeśli tabela i widok tła mają ten sam kolor.
Zrobiłem kilka zmian, żebyśmy nie musieli ręcznie sprawdzać licznika, dodałem również ograniczenia dla etykiety, aby nic nie poszło źle, niezależnie od tego, jak duży jest komunikat, jak pokazano poniżej:
extension UITableView {
fileprivate func configureLabelLayout(_ messageLabel: UILabel) {
messageLabel.translatesAutoresizingMaskIntoConstraints = false
let labelTop: CGFloat = CGFloat(UIDevice.current.userInterfaceIdiom == .pad ? 25:15)
messageLabel.topAnchor.constraint(equalTo: backgroundView?.topAnchor ?? NSLayoutAnchor(), constant: labelTop).isActive = true
messageLabel.widthAnchor.constraint(equalTo: backgroundView?.widthAnchor ?? NSLayoutAnchor(), constant: -20).isActive = true
messageLabel.centerXAnchor.constraint(equalTo: backgroundView?.centerXAnchor ?? NSLayoutAnchor(), constant: 0).isActive = true
}
fileprivate func configureLabel(_ message: String) {
let messageLabel = UILabel(frame: CGRect(x: 0, y: 0, width: self.bounds.size.width, height: self.bounds.size.height))
messageLabel.textColor = .black
messageLabel.numberOfLines = 0
messageLabel.textAlignment = .center
let fontSize = CGFloat(UIDevice.current.userInterfaceIdiom == .pad ? 25:15)
let font: UIFont = UIFont(name: "MyriadPro-Regular", size: fontSize) ?? UIFont()
messageLabel.font = font
messageLabel.text = message
self.backgroundView = UIView()
self.backgroundView?.addSubview(messageLabel)
configureLabelLayout(messageLabel)
self.separatorStyle = .none
}
func setEmptyMessage(_ message: String, _ isEmpty: Bool) {
if isEmpty { // instead of making the check in every TableView DataSource in the project
configureLabel(message)
}
else {
restore()
}
}
func restore() {
self.backgroundView = nil
self.separatorStyle = .singleLine
}
}
Stosowanie
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let message: String = "The list is empty."
ticketsTableView.setEmptyMessage(message, tickets.isEmpty)
return self.tickets.count
}
Lub alternatywnie możesz użyć nieco konfigurowalnej, lekkiej biblioteki