การจัดการ UITableView ที่ว่างเปล่า พิมพ์ข้อความที่เป็นมิตร


125

ฉันมี UITableView ซึ่งในบางกรณีมันถูกกฎหมายที่จะว่างเปล่า ดังนั้นแทนที่จะแสดงภาพพื้นหลังของแอปฉันต้องการพิมพ์ข้อความที่เป็นมิตรในหน้าจอเช่น:

รายการนี้ว่างเปล่า

วิธีที่ง่ายที่สุดในการทำคืออะไร?


10
ตรวจสอบโครงการนี้: github.com/dzenbot/DZNEmptyDataSet
oleynikd

@oleynikd ขอบคุณ !!!!!
Luda

คำตอบ:


174

คุณสมบัติ backgroundView ของ UITableView คือเพื่อนของคุณ

ในviewDidLoadหรือที่ใดก็ได้ที่คุณreloadDataควรพิจารณาว่าตารางของคุณว่างหรือไม่และอัปเดตคุณสมบัติ backgroundView ของ UITableView ด้วย UIView ที่มี UILabel หรือเพียงแค่ตั้งค่าเป็นศูนย์ แค่นั้นแหละ.

แน่นอนว่าเป็นไปได้ที่จะทำให้แหล่งข้อมูลของ UITableView ทำหน้าที่สองครั้งและส่งคืนเซลล์พิเศษ "list is empty" มันทำให้ฉันกลายเป็นกากตะกอน ทันใดนั้นnumberOfRowsInSection:(NSInteger)sectionต้องคำนวณจำนวนแถวของส่วนอื่น ๆ ที่ไม่ได้ถามเพื่อให้แน่ใจว่าว่างเกินไป คุณต้องสร้างเซลล์พิเศษที่มีข้อความว่าง อย่าลืมว่าคุณอาจต้องเปลี่ยนความสูงของเซลล์เพื่อรองรับข้อความว่าง ทั้งหมดนี้ทำได้ แต่ดูเหมือนว่า band-aid จะอยู่ด้านบนของ band-aid


12
ฉันคิดว่า backgroundView เป็นทางออกที่ดีที่สุด ขอบคุณ!
Ferran Maylinch

1
ข้อเสียอย่างหนึ่งคือหากดึงมุมมองตารางลงข้อความจะยังคงอยู่ในตำแหน่ง ฉันอยากจะชอบในแอพร้านค้าแอพภายใต้การอัปเดต ข้อความว่างตรงนี้ไปพร้อมกับพฤติกรรมการเลื่อน ...
ทดสอบ

เห็นได้ชัดว่าการทดสอบ @ หากคุณต้องการข้อความว่างในการเลื่อนคุณไม่สามารถใช้มุมมองพื้นหลังได้เนื่องจากไม่ได้เป็นส่วนหนึ่งของลำดับชั้นการเลื่อน คุณอาจต้องการใช้ส่วนที่กำหนดเองและ UITableViewCell สำหรับสถานะว่าง
LightningStryk

สลับbackgroundViewคุณสมบัติที่ซ่อนอยู่เป็นวิธีที่จะไป ด้วยDZNEmptyDataSetเราต้องใช้มันemptyDataSetSource
onmyway133

หากคุณต้องการเพิ่มปุ่มคุณต้องทำ: tableView.backgroundView!.userInteraction = trueหลังบรรทัดที่คุณกำหนดtableView.backgroundView = constructMyViewWithButtons()หรือตามที่คุณตั้งไว้
kbpontius

90

เหมือนกับคำตอบของ Jhonston แต่ฉันชอบเป็นส่วนขยาย:

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

การใช้งาน:

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
}

ขอบคุณสำหรับคำแนะนำ
ssowri1

1
ต่อดีกว่า! ขอบคุณ
Ogulcan Orhan

Love the extension :)
Alix

1
หากคุณมีส่วนต่างๆคุณจะต้องย้ายตรรกะนี้ไปที่func numberOfSections(in tableView: UITableView) -> Intวิธีการ
ประดิษฐ์

87

จากคำตอบที่นี่นี่คือคลาสสั้น ๆ ที่ฉันสร้างขึ้นซึ่งคุณสามารถใช้ใน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/


ยังต้องการเพิ่มรูปภาพลงไปด้วย แต่เป็นวิธีแก้ปัญหาที่รวดเร็ว
AnBisw

10
ใช้ส่วนขยายแทนคลาส (ไม่ต้องผ่านตัวควบคุมมุมมอง)
Cesare

ฉันไม่สามารถรับรหัสด้านบนเพื่อใช้งานได้ แต่ฉันสามารถรับรหัสในคำตอบนี้ (ข้อแรก) เพื่อใช้งานได้ในกรณีที่คนอื่นมีปัญหาเดียวกัน นอกจากนี้ฉันคิดว่าคำตอบที่ 2 ก็ใช้ได้เช่นกัน (โดยใช้ท่าเรือฉาก) - stackoverflow.com/questions/28532926/…
Renee Olson

viewController.tableView.separatorStyle = .noneไม่จำเป็น
Dmitry

17

ฉันขอแนะนำไลบรารีต่อไปนี้: 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)
}

วิธีการเหล่านี้ไม่ได้บังคับ แต่ยังสามารถแสดงสถานะว่างเปล่าโดยไม่มีปุ่มเป็นต้น

สำหรับ 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)
}

ฉันมีปัญหากับ DZEmptyDataSet ไม่ได้จัดแนวตั้งอย่างถูกต้อง มีใครมีปัญหาเดียวกันนี้
amariduran

12

วิธีหนึ่งในการทำเช่นนี้คือการแก้ไขแหล่งข้อมูลของคุณเพื่อส่งคืน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ที่ได้รับการกำหนดค่าด้วยข้อความที่เหมาะสม


5
ฉันมีปัญหาในการทำเช่นนี้กับตารางที่มีการลบแถวdeleteRowsAtIndexPaths:withRowAnimation:เนื่องจากจำนวนที่ส่งคืนจากnumberOfRowsInSectionความต้องการตรงกับผลลัพธ์ของ $ numRows - $ rowDeleted
Animal451

4
ฉันขอแนะนำอย่างยิ่งต่อสิ่งนี้ มันไขรหัสของคุณด้วยกรณีขอบ
xtravar

2
@xtravar แทนที่จะลงคะแนนให้ลองโพสต์คำตอบของคุณเอง
dasblinkenlight

1
ฉันเคยไปตามเส้นทางนั้นและมันนำไปสู่ปัญหาต่างๆ จากประสบการณ์ของฉันการเพิ่ม Apple APIs มักจะดีกว่าการพยายามแทนที่
xtravar

1
โซลูชันนี้ใช้ไม่ได้กับ NSFetchedResultsController ฉันจะลองใช้วิธี backgroundView แทน
แซม

10

ฉันใช้ข้อความ 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;
}

2
เคล็ดลับที่ดีและดูเหมือนจะค่อนข้างสะอาดสำหรับฉัน นี่คือซับreturn tableView.numberOfRowsInSection(section) == 0 ? "This list is now empty" : nil
TruMan1

8

ดังนั้นเพื่อความปลอดภัยยิ่งขึ้น:

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

7

ฉันสามารถแนะนำให้ลากและวาง UITextView ภายใน TableView หลังเซลล์เท่านั้น ทำการเชื่อมต่อกับ ViewController และซ่อน / แสดงตามความเหมาะสม (เช่นเมื่อใดก็ตามที่ตารางโหลดซ้ำ)

ใส่คำอธิบายภาพที่นี่


นั่นเป็นวิธีที่ง่ายที่สุด)!
moonvader

ปวดหัวสุด ๆ แบบแอปเปิ้ล ขอบคุณสำหรับแนวคิดนี้
Eenvincible

5

การใช้ 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ที่จะได้รับกลับไปที่สีแยกเริ่มต้นคุณก็สามารถตั้งค่าให้


งานนี้สวย! แต่ถ้าคุณมีองค์ประกอบสำหรับดึงเพื่อรีเฟรชเช่นสิ่งนี้จะไม่เลื่อนไปด้วย ผมพบว่ามันดีกว่าที่จะตั้งค่าtableHeaderViewและให้แน่ใจว่ามันจะปรับขนาดพอดี
Hannele

4

การใช้ Container View Controller เป็นวิธีที่ถูกต้องตามที่Appleกำหนด

ฉันใส่มุมมองสถานะว่างเปล่าทั้งหมดไว้ในสตอรี่บอร์ดแยกต่างหาก แต่ละอันอยู่ภายใต้คลาสย่อย UIViewController ของตัวเอง ฉันเพิ่มเนื้อหาโดยตรงภายใต้มุมมองรูท หากจำเป็นต้องดำเนินการ / ปุ่มใด ๆ ตอนนี้คุณมีตัวควบคุมที่จะจัดการแล้ว
จากนั้นเป็นเพียงเรื่องของการสร้างอินสแตนซ์ตัวควบคุมมุมมองที่ต้องการจาก Storyboard นั้นเพิ่มเป็นตัวควบคุมมุมมองเด็กและเพิ่มมุมมองคอนเทนเนอร์ไปยังลำดับชั้นของ tableView (มุมมองย่อย) มุมมองสถานะว่างของคุณจะเลื่อนได้เช่นกันซึ่งให้ความรู้สึกดีและช่วยให้คุณสามารถใช้การดึงเพื่อรีเฟรชได้

อ่านบท'การเพิ่มตัวควบคุมมุมมองเด็กในเนื้อหาของคุณ'เพื่อขอความช่วยเหลือเกี่ยวกับวิธีการนำไปใช้

ตรวจสอบให้แน่ใจว่าคุณตั้งค่ากรอบมุมมองเด็กเป็น (0, 0, tableView.frame.width, tableView.frame.height)และสิ่งต่างๆจะอยู่กึ่งกลางและจัดตำแหน่งอย่างเหมาะสม


3

ประการแรกปัญหาเกี่ยวกับแนวทางยอดนิยมอื่น ๆ

BackgroundView

มุมมองพื้นหลังไม่ได้อยู่ตรงกลางหากคุณใช้กรณีง่ายๆในการตั้งค่าให้เป็น UILabel

เซลล์ส่วนหัวหรือส่วนท้ายเพื่อแสดงข้อความ

สิ่งนี้รบกวนรหัสการทำงานของคุณและแนะนำกรณีขอบแปลก ๆ หากคุณต้องการจัดกึ่งกลางข้อความของคุณอย่างสมบูรณ์แบบนั่นจะเพิ่มความซับซ้อนอีกระดับ

หมุนตัวควบคุมมุมมองตารางของคุณเอง

คุณสูญเสียฟังก์ชันการทำงานในตัวเช่น refreshControl และสร้างวงล้อใหม่ ยึดติดกับ UITableViewController เพื่อผลลัพธ์ที่ดีที่สุดในการบำรุงรักษา

การเพิ่ม UITableViewController เป็นตัวควบคุมมุมมองเด็ก

ฉันรู้สึกว่าคุณจะพบกับปัญหา contentInset ใน iOS 7+ - ทำไมสิ่งต่าง ๆ จึงซับซ้อน?

ทางออกของฉัน

ทางออกที่ดีที่สุดที่ฉันคิดขึ้นมา (และไม่เหมาะอย่างยิ่ง) คือการสร้างมุมมองพิเศษที่สามารถนั่งอยู่ด้านบนของมุมมองแบบเลื่อนและดำเนินการตามนั้น เห็นได้ชัดว่าสิ่งนี้มีความซับซ้อนใน iOS 7 ด้วย contentInset madness แต่ก็ทำได้

สิ่งที่คุณต้องระวัง:

  • ตัวคั่นตารางจะถูกนำไปข้างหน้าในบางช่วงเวลาที่โหลดข้อมูล - คุณต้องป้องกันสิ่งนั้น
  • contentInset / contentOffset - สังเกตคีย์เหล่านั้นในมุมมองพิเศษของคุณ
  • แป้นพิมพ์ - หากคุณไม่ต้องการให้แป้นพิมพ์ขัดข้องนั่นเป็นการคำนวณอีกวิธีหนึ่ง
  • การจัดวางอัตโนมัติ - คุณไม่สามารถพึ่งพาการเปลี่ยนแปลงเฟรมเพื่อวางตำแหน่งมุมมองของคุณได้

เมื่อคุณพบสิ่งนี้หนึ่งครั้งในคลาสย่อย UIView หนึ่งแล้วคุณสามารถใช้มันได้ทุกอย่างไม่ว่าจะเป็นการโหลดสปินเนอร์การปิดการใช้งานมุมมองการแสดงข้อความแสดงข้อผิดพลาด ฯลฯ


คุณสามารถอธิบายรายละเอียดในคำตอบของคุณ คุณจะทราบได้อย่างไรว่าโต๊ะว่าง? เพื่อ "ปฏิบัติตาม"
Michael Ozeryansky

คุณรู้ว่าโต๊ะของคุณว่างเปล่าเพราะคุณเป็นคนที่เติมข้อมูลในตารางของคุณ ดังนั้นในตัวควบคุมมุมมองของคุณคุณจะมีการเรียกกลับการโหลดแบบอะซิงโครนัส ในการโทรกลับนั้นถ้า (itemsToShow.count == 0) {เพิ่มมุมมองของคุณในมุมมองแบบเลื่อน} ส่วนที่ยุ่งยากคือทำให้มุมมองด้านบน ('มุมมองโล่ / มุมมองข้อความ') อยู่ในตำแหน่งเพื่อใช้ทั้งเฟรมของมุมมองแบบเลื่อนลบ contentInset ฯลฯ เพื่อให้ข้อความอยู่กึ่งกลางในแนวตั้ง
xtravar

คุณจะเพิ่มมุมมองที่ด้านบนของมุมมองตารางได้อย่างไร self.view คือมุมมองตารางและถ้าฉันใช้addSubViewมันแนบกับมุมมองตารางซึ่งมักทำให้เกิดปัญหากับการจัดวางอัตโนมัติ
ทดสอบ

มุมมองที่คุณวางไว้ในมุมมองตารางไม่ควรใช้การจัดวางอัตโนมัติและ tableview เองก็ไม่ได้ใช้การจัดวางอัตโนมัติ
xtravar

1
คุณพลาดแนวทางหนึ่งที่นั่น คุณสามารถใช้ UITableViewController และเพิ่มเป็นตัวควบคุมมุมมองเด็กไปยัง UIViewController ปกติ
user1169629

3

นี่เป็นทางออกที่ง่ายและดีที่สุด

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

แสดงข้อความสำหรับรายการที่ว่างเปล่า, อากาศของ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!")
}

ข้อควรจำ: อย่าลืมลบป้ายข้อความในกรณีที่ข้อมูลจะมาหลังจากรีเฟรช


1
ฉันจะเพิ่มเงื่อนไข if if messages.count! = 0 {show}
Eddwin Paz

1

เลือกฉากควบคุมตารางของคุณในสตอรีบอร์ด

ใส่คำอธิบายภาพที่นี่

ลากและวาง UIView เพิ่มป้ายกำกับด้วยข้อความของคุณ (เช่น: ไม่มีข้อมูล)

ใส่คำอธิบายภาพที่นี่

สร้างทางออกของ UIView (เช่น yournoDataView) บน TableViewController ของคุณ

และใน viewDidLoad

self.tableView.backgroundView = yourNoDataView


1

ใช้ 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

คุณสามารถเพิ่มสิ่งนี้ลงในคลาสพื้นฐานของคุณ

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

แสดงแบบนี้ในคลาสเกี่ยวกับการรับข้อมูลจาก api

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

ซ่อนไว้แบบนี้

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

func hideNoDataMessage(){
    messageLabel.removeFromSuperview()
}

เฮ้ @ Mudassir-Asghar ฟังก์ชัน hideNoDataMessage มีลักษณะอย่างไร
Saamer

1
สวัสดี @Saamer ฉันเพิ่งอัปเดตคำตอบด้านบน ขอบคุณที่ชี้ให้เห็นหวังว่านี่จะช่วยได้ :)
Mudassir Asghar

0

เวอร์ชัน Swift แต่รูปแบบที่ดีกว่าและเรียบง่ายกว่า ** 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
        }
    }
}

Helper Class พร้อมฟังก์ชั่น:

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

อาจไม่ใช่วิธีแก้ปัญหาที่ดีที่สุด แต่ฉันทำได้โดยเพียงแค่ใส่ป้ายกำกับที่ด้านล่างของตารางและถ้าแถว = 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 = ""
    }

คุณยังสามารถแทนที่ป้ายกำกับด้วยมุมมองภาพที่ว่างเปล่าเมื่อ count = 0 หากคุณต้องการ ..
Zach

0

วิธีที่ง่ายและรวดเร็วที่สุดคือลากป้ายไปที่แผงด้านข้างใต้ tableView สร้างเต้ารับสำหรับเลเบลและ tableView และเพิ่มคำสั่ง if เพื่อซ่อนและแสดงเลเบลและตารางตามต้องการ หรือคุณสามารถเพิ่ม tableView.tableFooterView = UIView (frame: CGRect.zero) ให้กับคุณ viewDidLoad () เพื่อให้ตารางว่างรับรู้ว่ามันถูกซ่อนไว้หากมุมมองตารางและพื้นหลังมีสีเดียวกัน


(ดูเหมือนว่าโพสต์นี้จะไม่ได้ให้คำตอบที่มีคุณภาพสำหรับคำถามโปรดแก้ไขคำตอบของคุณและกรอกข้อมูลโดยละเอียดเพิ่มเติมหรือเพียงแค่โพสต์เป็นความคิดเห็นสำหรับคำถาม)
sɐunıɔןɐqɐp

0

ฉันทำการเปลี่ยนแปลงเล็กน้อยเพื่อที่เราจะได้ไม่ต้องตรวจสอบการนับด้วยตนเองและฉันได้เพิ่มข้อ จำกัด สำหรับป้ายกำกับเพื่อไม่ให้มีอะไรผิดพลาดไม่ว่าข้อความจะใหญ่แค่ไหนตามที่แสดงด้านล่าง:

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

การใช้

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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.