Xử lý một UITableView trống. In một tin nhắn thân thiện


124

Tôi có một UITableView rằng trong một số trường hợp, nó là hợp pháp để trống. Vì vậy, thay vì hiển thị hình nền của ứng dụng, tôi thích in một tin nhắn thân thiện trên màn hình, chẳng hạn như:

Danh sách này hiện đang trống

Cách đơn giản nhất để làm điều đó là gì?


10
Kiểm tra dự án này: github.com/dzenbot/DZNEmptyDataSet
oleynikd

@oleynikd Cảm ơn bạn !!!!!
Luda

Câu trả lời:


173

Thuộc tính nềnView của UITableView là bạn của bạn.

Trong viewDidLoadhoặc bất cứ nơi nào reloadDatabạn nên xác định xem bảng của mình có trống hay không và cập nhật thuộc tính nềnView của UITableView với một UIView có chứa UILabel hoặc chỉ đặt nó thành không. Đó là nó.

Tất nhiên có thể làm cho nguồn dữ liệu của UITableView thực hiện nhiệm vụ kép và trả về một ô "danh sách trống" đặc biệt, nó tấn công tôi như một loại bùn. Đột nhiên numberOfRowsInSection:(NSInteger)sectionphải tính toán số lượng hàng của các phần khác mà nó không được hỏi về để đảm bảo chúng cũng trống. Bạn cũng cần tạo một ô đặc biệt có thông báo trống. Cũng đừng quên rằng bạn có thể cần thay đổi chiều cao của ô để phù hợp với thông báo trống. Đây là tất cả có thể làm được nhưng có vẻ như hỗ trợ ban nhạc trên đầu trang của ban nhạc.


12
Bối cảnh là giải pháp tốt nhất, tôi nghĩ vậy. Cảm ơn bạn!
Ferran Maylinch

1
Một nhược điểm là nếu chế độ xem bảng được kéo xuống, thông báo vẫn ở vị trí của nó. Tôi muốn có thích trong ứng dụng cửa hàng ứng dụng theo cập nhật. Ở đây, thông báo trống đi với hành vi cuộn ...
thử nghiệm vào

@testing rõ ràng nếu bạn cần tin nhắn trống để cuộn, bạn không thể sử dụng chế độ xem nền vì đó không phải là một phần của hệ thống phân cấp cuộn. Bạn có thể muốn sử dụng một phần tùy chỉnh và UITableViewCell cho trạng thái trống.
LightningStryk

Chuyển đổi backgroundViewtài sản ẩn là con đường để đi. Với DZNEmptyDataSet, chúng tôi phải sử dụng nóemptyDataSetSource
onmyway133

Nếu bạn muốn thêm các nút, bạn phải làm: tableView.backgroundView!.userInteraction = truesau dòng bạn đặt tableView.backgroundView = constructMyViewWithButtons(), hoặc tuy nhiên bạn đặt nó.
kbpontius

90

Giống như câu trả lời của Jhonston, nhưng tôi thích nó như một phần mở rộng:

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

Sử dụng:

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
}

Cảm ơn bạn đã gợi ý.
ssowri1

1
Gia hạn thì tốt hơn! Cảm ơn.
Ogulcan Orhan

Yêu phần mở rộng :)
Alix

1
Nếu bạn có các phần, thì bạn sẽ cần chuyển logic này sang func numberOfSections(in tableView: UITableView) -> Intphương thức
craft

87

Dựa trên các câu trả lời ở đây, đây là một lớp học nhanh mà tôi đã thực hiện mà bạn có thể sử dụng trong của bạn 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;
    }
}

Trong của UITableViewControllerbạn, bạn có thể gọi này trongnumberOfSectionsInTableView(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
    }
}

nhập mô tả hình ảnh ở đây

Với một chút giúp đỡ từ http://www.appcoda.com/pull-to-refresh-uitableview-empty/


Mặc dù vậy, cũng muốn thêm hình ảnh vào nó. Nhưng một giải pháp nhanh chóng tuyệt vời.
AnBisw

10
sử dụng tiện ích mở rộng thay vì lớp (không vượt qua trình điều khiển chế độ xem)
Cesare

Tôi không thể lấy mã ở trên để làm việc cho tôi, nhưng tôi đã có thể lấy mã trong câu trả lời này (câu đầu tiên) để làm việc, trong trường hợp những người khác có cùng vấn đề. Ngoài ra tôi nghĩ rằng câu trả lời thứ 2 cũng sẽ hoạt động tốt (sử dụng dock cảnh) - stackoverflow.com/questions/28532926/ Kẻ
Renee Olson

viewController.tableView.separatorStyle = .nonekhông bắt buộc.
Dmitry

17

Tôi đề nghị thư viện sau: DZNEmptyDataSet

Cách dễ nhất để thêm nó vào dự án của bạn là sử dụng nó với Cocaopod như vậy: pod 'DZNEmptyDataSet'

Trong TableViewControll của bạn, thêm câu lệnh nhập sau (Swift):

import DZNEmptyDataSet

Sau đó, đảm bảo rằng lớp của bạn phù hợp với DNZEmptyDataSetSourceDZNEmptyDataSetDelegatenhư vậy:

class MyTableViewController: UITableViewController, DZNEmptyDataSetSource, DZNEmptyDataSetDelegate

Trong bạn viewDidLoadthêm các dòng mã sau:

tableView.emptyDataSetSource = self
tableView.emptyDataSetDelegate = self
tableView.tableFooterView = UIView()

Bây giờ tất cả những gì bạn phải làm để hiển thị khoảng trống là:

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

Các phương thức này không bắt buộc, cũng có thể chỉ hiển thị trạng thái trống mà không có nút, v.v.

Dành cho 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)
}

Tôi đang gặp vấn đề với DZEmptyDataset không được căn chỉnh theo chiều dọc. Có ai có vấn đề tương tự?
amariduran

12

Một cách để làm điều đó là sửa đổi nguồn dữ liệu của bạn để trả về 1khi số lượng hàng bằng 0 và để tạo một ô có mục đích đặc biệt (có lẽ với một mã định danh ô khác) trong tableView:cellForRowAtIndexPath:phương thức.

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

Điều này có thể trở nên hơi phức tạp nếu bạn có nhiều bộ điều khiển xem bảng mà bạn cần duy trì, bởi vì cuối cùng ai đó sẽ quên chèn một kiểm tra số không. Một cách tiếp cận tốt hơn là tạo ra một triển khai riêng biệt của một UITableViewDataSourcetriển khai luôn trả về một hàng duy nhất với một thông báo có thể định cấu hình (hãy gọi nó EmptyTableViewDataSource). Khi dữ liệu được quản lý bởi trình điều khiển xem bảng của bạn thay đổi, mã quản lý thay đổi sẽ kiểm tra xem dữ liệu có trống không. Nếu nó không trống, hãy đặt bộ điều khiển xem bảng của bạn với nguồn dữ liệu thông thường; mặt khác, đặt nó với một thể hiện của thông EmptyTableViewDataSourcebáo đã được cấu hình với thông báo phù hợp.


5
Tôi đã gặp vấn đề khi làm điều này với các bảng có các hàng bị xóa deleteRowsAtIndexPaths:withRowAnimation:vì số được trả về từ numberOfRowsInSectionnhu cầu khớp với kết quả của $ numRows - $ rowsDelatted.
Động vật

4
Tôi rất, rất khuyến khích chống lại điều này. Nó đánh đố mã của bạn với các trường hợp cạnh.
xtravar

2
@xtravar Thay vì tải xuống, hãy xem xét đăng câu trả lời của riêng bạn.
dasblinkenlight 16/03 '

1
Tôi đã đi theo con đường đó, và nó dẫn đến một loạt vấn đề của riêng nó. Theo kinh nghiệm của tôi, hầu như luôn luôn tốt hơn để tăng cường API của Apple hơn là cố gắng thay thế chúng.
xtravar 17/03/2016

1
Giải pháp này sẽ không hoạt động với NSFetchedResultsControll. Thay vào đó, tôi sẽ thử phương pháp nền.
Sam

10

Tôi đã sử dụng thông điệp titleForFooterInSection cho việc này. Tôi không biết điều này có tối ưu hay không, nhưng nó hoạt động.

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

2
Thủ thuật hay và có vẻ khá sạch sẽ đối với tôi. Đây là một lớp lót:return tableView.numberOfRowsInSection(section) == 0 ? "This list is now empty" : nil
TruMan1 24/07/2015

8

Vì vậy, để có một giải pháp an toàn hơn:

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

UICollectionViewcũng vậy:

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

Giải pháp chung hơn:

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

7

Tôi chỉ có thể khuyên bạn nên kéo và thả UITextView bên trong TableView sau các ô. Tạo kết nối với ViewContoder và ẩn / hiển thị nó khi thích hợp (ví dụ: bất cứ khi nào bảng tải lại).

nhập mô tả hình ảnh ở đây


Đó là cách dễ nhất)!
moonvader

Như một cơn đau đầu đau đầu; cảm ơn vì ý tưởng này
Eenvincible

5

Sử dụng nền ViewView là tốt, nhưng nó không cuộn độc đáo như trong Mail.app.

Tôi đã làm một cái gì đó tương tự như những gì xtravar đã làm.

Tôi đã thêm một khung nhìn bên ngoài hệ thống phân cấp xem của tableViewController. hệ thống cấp bậc

Sau đó, tôi đã sử dụng mã sau đây trong 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

Về cơ bản tôi đã thêm vào emptyStateViewnhư là một khung nhìn của tableViewđối tượng. Vì các dải phân cách sẽ chồng lên khung nhìn, tôi đặt màu của chúng thành clearColor. Để quay lại màu phân cách mặc định, bạn chỉ cần đặt nó thành nil.


Điều này hoạt động khá tốt! Nhưng nếu bạn có các yếu tố để kéo để làm mới, ví dụ, điều này không cuộn với chúng. Tôi thấy tốt hơn để đặt tableHeaderViewvà đảm bảo nó thay đổi kích thước cho phù hợp .
Hannele

4

Sử dụng Bộ điều khiển Chế độ xem Container là cách phù hợp để thực hiện theo Apple .

Tôi đặt tất cả các chế độ xem trạng thái trống của mình vào một Storyboard riêng. Mỗi lớp dưới lớp con UIViewControll của riêng nó. Tôi thêm nội dung trực tiếp dưới chế độ xem gốc của họ. Nếu cần bất kỳ hành động / nút nào, thì bây giờ bạn đã có bộ điều khiển để xử lý nó.
Sau đó, vấn đề chỉ là khởi tạo trình điều khiển khung nhìn mong muốn từ Storyboard đó, thêm nó dưới dạng trình điều khiển khung nhìn con và thêm khung nhìn container vào hệ thống phân cấp của khung nhìn (khung nhìn phụ). Chế độ xem trạng thái trống của bạn cũng sẽ có thể cuộn, điều này cảm thấy tốt và cho phép bạn thực hiện kéo để làm mới.

Đọc chương 'Thêm Trình điều khiển Chế độ xem Trẻ em vào Nội dung của bạn' để được trợ giúp về cách triển khai.

Chỉ cần đảm bảo rằng bạn đặt khung nhìn con vì (0, 0, tableView.frame.width, tableView.frame.height)mọi thứ sẽ được căn giữa và căn chỉnh chính xác.


3

Đầu tiên, các vấn đề với các phương pháp phổ biến khác.

Bối cảnh

Chế độ xem nền không phải là trung tâm độc đáo nếu bạn sử dụng trường hợp đơn giản là đặt nó thành UILabel.

Các ô, tiêu đề hoặc chân trang để hiển thị thông báo

Điều này can thiệp vào mã chức năng của bạn và giới thiệu các trường hợp cạnh kỳ lạ. Nếu bạn muốn tập trung hoàn hảo vào thông điệp của mình, điều đó sẽ thêm một mức độ phức tạp khác.

Cán bộ điều khiển xem bảng của riêng bạn

Bạn mất chức năng tích hợp, chẳng hạn như refreshControl và phát minh lại bánh xe. Bám sát UITableViewCont kiểm soát để có kết quả duy trì tốt nhất.

Thêm UITableViewContaptor làm trình điều khiển xem con

Tôi có cảm giác bạn sẽ kết thúc với các vấn đề về nội dung trong iOS 7+ - cộng với lý do tại sao mọi thứ lại phức tạp?

Giải pháp của tôi

Giải pháp tốt nhất mà tôi đã đưa ra (và, được cho là, điều này không lý tưởng) là tạo một chế độ xem đặc biệt có thể ngồi trên đầu của chế độ xem cuộn và hành động tương ứng. Điều này rõ ràng trở nên phức tạp trong iOS 7 với sự điên rồ của nội dung, nhưng nó có thể thực hiện được.

Những điều bạn phải coi chừng:

  • dấu tách bảng được đưa ra phía trước tại một số điểm trong quá trình tải lại - bạn cần đề phòng điều đó
  • contentInset / content Offerset - quan sát các phím đó trên chế độ xem đặc biệt của bạn
  • bàn phím - nếu bạn không muốn bàn phím cản trở, đó là một phép tính khác
  • tự động thanh toán - bạn không thể phụ thuộc vào thay đổi khung để định vị chế độ xem của bạn

Khi bạn đã tìm ra điều này một lần trong một lớp con UIView, bạn có thể sử dụng nó cho mọi thứ - tải spinners, vô hiệu hóa chế độ xem, hiển thị thông báo lỗi, v.v.


Bạn có thể giải thích trong câu trả lời của bạn. Làm thế nào để bạn biết nếu bảng trống? Để sau đó "hành động phù hợp".
Michael Ozeryansky

Bạn biết bảng của bạn trống vì bạn là người điền vào bảng của bạn. Vì vậy, trong trình điều khiển chế độ xem của bạn, bạn sẽ có một cuộc gọi lại tải không đồng bộ. Trong cuộc gọi lại đó, if (itemsToShow.count == 0) {thêm chế độ xem của bạn vào chế độ xem cuộn}. Phần khó khăn là làm cho chế độ xem trên cùng ('khiên / chế độ xem tin nhắn') được định vị để chiếm toàn bộ khung của chế độ xem cuộn, trừ nội dung, v.v., để thông điệp được căn giữa theo chiều dọc.
xtravar

Làm thế nào để bạn thêm một khung nhìn trên đầu của bảng xem? self.view là chế độ xem bảng và nếu tôi sử dụng, addSubViewnó được gắn vào chế độ xem bảng luôn gây ra sự cố với bố cục tự động.
thử nghiệm

Chế độ xem bạn đặt trong chế độ xem bảng không nên sử dụng tự động thanh toán và bản thân chế độ xem bảng không sử dụng tự động thanh toán.
xtravar

1
Bạn đã bỏ lỡ một cách tiếp cận ở đó; Bạn có thể sử dụng UITableViewContaptor và thêm nó làm trình điều khiển chế độ xem con vào UIViewControll thông thường
user1169629

3

Đây là giải pháp tốt nhất và đơn giản.

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;

2

Hiển thị tin nhắn cho danh sách trống, Wether của nó UITableView hoặc 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
        }
    }
}

Tập quán:

if cellsViewModels.count == 0 {
    self.tableView.showEmptyListMessage("No Product In List!")
}

HOẶC LÀ:

if cellsViewModels.count == 0 {
    self.collectionView?.showEmptyListMessage("No Product In List!")
}

Ghi nhớ: Đừng quên xóa nhãn tin trong trường hợp dữ liệu sẽ đến sau khi làm mới.


1
Tôi sẽ thêm một điều kiện if nếu
message.count

1

Chọn cảnh viewviewControll của bạn trong bảng phân cảnh

nhập mô tả hình ảnh ở đây

Kéo và thả nhãn UIView Thêm vào tin nhắn của bạn (ví dụ: Không có dữ liệu)

nhập mô tả hình ảnh ở đây

tạo ổ cắm của UIView (ví dụ: yournoDataView) trên TableViewControll của bạn.

và trong viewDidLoad

self.tableView.backgroundView = yourNoDataView


1

Sử dụng 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
}

1

Bạn có thể thêm nó vào lớp Base của bạn.

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

Hiển thị nó như thế này trong lớp về việc lấy dữ liệu từ api.

func populateData(dataSource : [PRNJobDataSource]){
    self.dataSource = dataSource
    self.tblView.reloadData()
    if self.dataSource.count == 0 {self.showNoDataMessage(msg: "No data found.")}
}

Giấu nó như thế này.

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    if self.dataSource.count > 0 {self.hideNoDataMessage()}
    return dataSource.count
}

func hideNoDataMessage(){
    messageLabel.removeFromSuperview()
}

Hey @ Mudassir-Asghar Hàm ẩnNoDataMessage trông như thế nào?
Saamer

1
Xin chào, @Saamer tôi vừa cập nhật câu trả lời ở trên. cảm ơn vì đã chỉ ra, hy vọng điều này có ích :)
Mudassir Asghar

0

Phiên bản Swift nhưng hình thức tốt hơn và đơn giản hơn. ** 3.0

Tôi hy vọng nó phục vụ mục đích của bạn ......

Trong UITableViewControll của bạn.

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

Lớp trợ giúp với chức năng:

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

Có lẽ không phải là giải pháp tốt nhất, nhưng tôi đã làm điều này bằng cách chỉ đặt một nhãn ở cuối bảng của tôi và nếu các hàng = 0 thì tôi gán cho nó một số văn bản. Khá dễ dàng và đạt được những gì bạn đang cố gắng thực hiện với một vài dòng mã.

Tôi có hai phần trong bảng của mình (công việc và trường học)

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

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

Bạn cũng có thể thay thế nhãn bằng số lần xem hình ảnh trống khi đếm = 0 nếu bạn muốn ..
Zach

0

Cách dễ nhất và nhanh nhất để làm điều này là kéo nhãn trên bảng điều khiển bên dưới bảngView. Tạo một lối thoát cho nhãn và bảngView và thêm một câu lệnh if để ẩn và hiển thị nhãn và bảng khi cần. Ngoài ra, bạn có thể thêm tableView.tableFooterView = UIView (frame: CGRect.zero) này cho bạn viewDidLoad () để cung cấp cho một bảng trống nhận thức rằng nó bị ẩn nếu bảng và chế độ xem nền có cùng màu.


(Bài đăng này dường như không cung cấp câu trả lời chất lượng cho câu hỏi. Vui lòng chỉnh sửa câu trả lời của bạn và hoàn thành nó với thông tin chi tiết hơn, hoặc chỉ đăng nó dưới dạng nhận xét cho câu hỏi).
sɐunıɔ qɐp

0

Tôi đã thực hiện một vài thay đổi để chúng tôi không cần kiểm tra số lượng theo cách thủ công, tôi cũng đã thêm các ràng buộc cho nhãn để không có gì sai dù thông báo có lớn như thế nào dưới đây:

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

Sử dụng

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        let message: String = "The list is empty."
        ticketsTableView.setEmptyMessage(message, tickets.isEmpty)
        return self.tickets.count
    }

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.