iphone - insetscontentviewstosafearea - safe area layout guide programmatically



Behandeln eines leeren UITableView. Drucken Sie eine freundliche Nachricht (11)

Also für eine sicherere Lösung:

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
  }
}

und auch für 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
  }
}

Ich habe eine UITableView, dass es in einigen Fällen legal ist, leer zu sein. Anstatt also das Hintergrundbild der App zu zeigen, würde ich lieber eine freundliche Nachricht auf dem Bildschirm ausgeben, zum Beispiel:

Diese Liste ist jetzt leer

Was ist der einfachste Weg?


Basierend auf den Antworten hier, hier ist eine UITableViewController Klasse, die ich gemacht habe, die Sie in Ihrem 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;
    }
}

In Ihrem UITableViewController Sie dies in 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
    }
}

Mit ein wenig Hilfe von http://www.appcoda.com/pull-to-refresh-uitableview-empty/


Die Verwendung eines Container View Controllers ist laut Apple der richtige Weg.

Ich lege alle meine leeren Zustandsansichten in ein separates Storyboard. Jeder unter seiner eigenen UIViewController-Unterklasse. Ich füge Inhalte direkt unter ihrer Stammansicht hinzu. Wenn eine Aktion / Schaltfläche benötigt wird, haben Sie jetzt bereits einen Controller, um damit umzugehen.
Dann kommt es darauf an, den gewünschten View-Controller aus dem Storyboard zu instantiieren, ihn als Child-View-Controller hinzuzufügen und die Container-Ansicht der Hierarchie des TableViews (Unteransicht) hinzuzufügen. Ihre leere Statusansicht wird ebenfalls gescrollt, was sich gut anfühlt und es Ihnen ermöglicht, Pull zum Aktualisieren zu implementieren.

Apple Kapitel 'Hinzufügen eines Child View-Controllers zu Ihrem Inhalt', um Hilfe zur Implementierung zu erhalten.

(0, 0, tableView.frame.width, tableView.frame.height) Sie nur sicher, dass Sie den (0, 0, tableView.frame.width, tableView.frame.height) Ansichtsrahmen als (0, 0, tableView.frame.width, tableView.frame.height) richtig zentriert und ausgerichtet werden.


Dies ist die beste und einfachste Lösung.

    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;

Erstens, die Probleme mit anderen populären Ansätzen.

Hintergrundansicht

Die Hintergrundansicht ist nicht gut zentriert, wenn Sie den einfachen Fall verwenden, sie als UILabel festzulegen.

Zellen, Kopfzeilen oder Fußzeilen zum Anzeigen der Nachricht

Dies stört Ihren Funktionscode und führt seltsame Randfälle ein. Wenn Sie Ihre Botschaft perfekt zentrieren möchten, ist das eine weitere Stufe der Komplexität.

Rollieren Sie Ihren eigenen Tabellenansicht-Controller

Sie verlieren integrierte Funktionen wie refreshControl und erfinden das Rad neu. Bleiben Sie bei UITableViewController für die besten wartbaren Ergebnisse.

Hinzufügen von UITableViewController als untergeordneten Ansichtscontroller

Ich habe das Gefühl, dass Sie mit ContentInset-Problemen in iOS 7+ enden werden - und warum die Dinge komplizierter werden?

Meine Lösung

Die beste Lösung, die ich mir ausgedacht habe (und, natürlich, das ist nicht ideal), besteht darin, eine spezielle Ansicht zu erstellen, die auf einer Bildlaufansicht sitzt und entsprechend agiert. Dies wird offensichtlich in iOS 7 mit ContentInset Wahnsinn kompliziert, aber es ist machbar.

Dinge, auf die Sie achten müssen:

  • Tabellen-Separatoren werden irgendwann während reloadData nach vorne gebracht - davor müssen Sie sich schützen
  • contentInset / contentOffset - beobachten Sie diese Schlüssel in Ihrer speziellen Ansicht
  • Tastatur - wenn Sie nicht wollen, dass die Tastatur in die Quere kommt, ist das eine andere Berechnung
  • Autolayout - Sie können sich nicht auf Rahmenänderungen verlassen, um Ihre Ansicht zu positionieren

Sobald Sie dies einmal in einer UIView-Unterklasse herausgefunden haben, können Sie es für alles verwenden - Laden von Spinnereien, Deaktivieren von Ansichten, Anzeigen von Fehlermeldungen usw.


Genau wie Jhonstons Antwort, aber ich zog es als Erweiterung vor:

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
    }
}

Verwendung:

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
}

Ich habe die titleForFooterInSection-Nachricht dafür verwendet. Ich weiß nicht, ob das suboptimal ist oder nicht, aber es funktioniert.

-(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;
}

Ich kann nur empfehlen, ein UITextView innerhalb der TableView nach den Zellen zu ziehen. Stellen Sie eine Verbindung zum ViewController her und blenden / zeigen Sie sie gegebenenfalls an (z. B. wenn die Tabelle neu geladen wird).


Wählen Sie Ihre tableviewController-Szene im Storyboard aus

Drag & Drop UIView Hinzufügen Label mit Ihrer Nachricht (zB: keine Daten)

Erstellen Sie outlet von UIView auf Ihrem TableViewController (z. B. für yournoDataView).

und in viewDidLoad

self.tableView.backgroundView = yourNoDataView


Wahrscheinlich nicht die beste Lösung, aber ich tat dies, indem ich einfach eine Beschriftung an den unteren Rand meines Tisches legte und wenn die Zeilen = 0 waren, dann ordnete ich ihr etwas Text zu. Ziemlich einfach, und erreicht, was Sie versuchen, mit ein paar Zeilen Code zu tun.

Ich habe zwei Abschnitte in meinem Tisch (Jobs und Schulen)

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

    if (jobs.count == 0 && schools.count == 0) {
        emptyLbl.text = "No jobs or schools"
    } else {
        emptyLbl.text = ""
    }

Schnelle Version, aber bessere und einfachere Form. ** 3.0

Ich hoffe, dass es deinen Zweck erfüllt ...

In Ihrem 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
        }
    }
}

Helferklasse mit Funktion:

 /* 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;
        }