【问题标题】:If no Table View results, display "No Results" on screen如果没有 Table View 结果,则在屏幕上显示“No Results”
【发布时间】:2015-04-16 11:05:30
【问题描述】:

我有一个tableview,有时可能没有任何结果要列出,所以我想在没有结果的情况下提出“无结果”(无论是标签还是一个表格视图单元格?)。

有没有最简单的方法来做到这一点?

我会在tableview 后面尝试label,然后根据结果隐藏两者之一,但由于我使用的是TableViewController 而不是普通的ViewController,所以我不确定这有多聪明或可行。

我也在使用Parse 并将子类化为PFQueryTableViewController

@interface TableViewController : PFQueryTableViewController

我可以提供所需的任何其他详细信息,请告诉我!

TableViewController情节提要中的场景:

编辑: Per Midhun MP,这是我正在使用的代码

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    NSInteger numOfSections = 0;
    if ([self.stringArray count] > 0)
    {
        self.tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine;
        numOfSections                 = 1;
        //yourTableView.backgroundView   = nil;
        self.tableView.backgroundView = nil;
    }
    else
    {
        UILabel *noDataLabel         = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, self.tableView.bounds.size.width, self.tableView.bounds.size.height)];
        noDataLabel.text             = @"No data available";
        noDataLabel.textColor        = [UIColor blackColor];
        noDataLabel.textAlignment    = NSTextAlignmentCenter;
        //yourTableView.backgroundView = noDataLabel;
        //yourTableView.separatorStyle = UITableViewCellSeparatorStyleNone;
        self.tableView.backgroundView = noDataLabel;
        self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
    }

    return numOfSections;
}

这是我得到的视图,它仍然有分隔线。我觉得这是一些小的变化,但我不确定为什么会出现分隔线?

【问题讨论】:

  • 我认为诀窍是在 tableview 上设置空的 footerView 以消除线条。
  • @Andy 你这是什么意思?
  • 不要使用添加到这个问题的解决方案。表视图数据源方法绝不能做超出它们应该做的事情。 numberOfSections 应该返回一个计数,就是这样。 numberOfRowsInSection 也一样。这些可以随时多次调用。永远不要更新视图或更新数据或做任何事情,除非返回一个计数。更新视图的逻辑绝不能在这些方法中。

标签: ios objective-c uitableview parse-platform


【解决方案1】:

如果 tableview 没有结果,我将展示一个具有您想要的外观和消息的覆盖视图。您可以在 ViewDidAppear 中执行此操作,因此您可以在显示/不显示视图之前获得结果。

【讨论】:

    【解决方案2】:

    你可以试试这个控件。它非常整洁。 DZNEmptyDataSet

    或者如果我是你,我会做的就是

    • 检查您的数据数组是否为空
    • 如果为空,则添加一个名为@"No Data" 的对象
    • 在 cell.textLabel.text 中显示该字符串

    简单易懂

    【讨论】:

      【解决方案3】:

      我认为解决您的问题最优雅的方法是从 UITableViewController 切换到包含 UITableViewUIViewController。这样你就可以添加任何你想要的UIView作为主视图的子视图。

      我不建议使用 UITableViewCell 来执行此操作,您将来可能需要添加其他内容,并且事情很快就会变得丑陋。

      你也可以这样做,但这也不是最好的解决方案。

      UIWindow* window = [[UIApplication sharedApplication] keyWindow];
      [window addSubview: OverlayView];
      

      【讨论】:

      • 感谢颜色是最优雅的实现方式,始终是思考它的好方法。我可能会尝试更改我的故事板以使用包含UITableViewUIViewController
      • 这是最面向未来的方式。我自己从未使用过UITableViewController,因为使用它并不比使用其他方式更容易,但它限制了你在未来改变事物的能力。
      • 如果你有半透明条,这不是面向未来的。我强烈反对。至少,制作一个包含 UITableViewController 并适当调整内容的 UIViewController。
      【解决方案4】:

      您可以通过使用UITableViewbackgroundView 属性轻松实现这一目标。

      目标 C:

      - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
      {
          NSInteger numOfSections = 0;
          if (youHaveData)
          {
              yourTableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine;
              numOfSections                = 1;
              yourTableView.backgroundView = nil;
          }
          else
          {   
              UILabel *noDataLabel         = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, yourTableView.bounds.size.width, yourTableView.bounds.size.height)];
              noDataLabel.text             = @"No data available";
              noDataLabel.textColor        = [UIColor blackColor];
              noDataLabel.textAlignment    = NSTextAlignmentCenter;
              yourTableView.backgroundView = noDataLabel;
              yourTableView.separatorStyle = UITableViewCellSeparatorStyleNone;
          }
      
          return numOfSections;
      }
      

      斯威夫特:

      func numberOfSections(in tableView: UITableView) -> Int
      {
          var numOfSections: Int = 0
          if youHaveData
          {
              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 data available"
              noDataLabel.textColor     = UIColor.black
              noDataLabel.textAlignment = .center
              tableView.backgroundView  = noDataLabel
              tableView.separatorStyle  = .none
          }
          return numOfSections
      }
      

      参考UITableView Class Reference

      backgroundView 属性

      表格视图的背景视图。

      声明

      斯威夫特

      var backgroundView: UIView?

      Objective-C

      @property(nonatomic, readwrite, retain) UIView *backgroundView

      讨论

      表格视图的背景视图会自动调整大小以匹配 表视图的大小。此视图作为表格的子视图放置 在所有单元格、页眉视图和页脚视图后面查看。

      您必须将此属性设置为 nil 才能设置 表格视图。

      【讨论】:

      • 感谢您的回答!这是否意味着我需要一个tableView 插座才能做到yourTableView.backgroundView?我正在使用TableViewController,所以我现在没有出口,这就是我想知道的原因。
      • UITableViewController 已经有一个名为 tableView 的属性,所以你不需要创建一个
      • 知道了,使用self.tableView
      • 更正。经过进一步测试,我实际上不得不让我提到的那条线返回相同的值。 numOfSections = 1。如果我将其设为零并且我的表格视图为空,它可以工作,但是当我创建一个单元格然后删除它时,它没有删除并显示消息,而是崩溃并出现以下错误。 *** 由于未捕获的异常“NSInternalInconsistencyException”而终止应用程序,原因:“UITableView 内部错误:无法生成具有旧节数:1 和新节数:0 的新节图”。我不知道为什么返回相同的值会起作用,但它确实如此,而且它应该以它应该的方式工作。
      • 不要使用此解决方案。表视图数据源方法绝不能做超出它们应该做的事情。 numberOfSections 应该返回一个计数,就是这样。 numberOfRowsInSection 也一样。这些可以随时多次调用。永远不要更新视图或更新数据或做任何事情,除非返回一个计数。更新视图的逻辑绝不能在这些方法中。
      【解决方案5】:

      在您的numberOfSectionsInTableView 方法中使用此代码:-

      if ([array count]==0
      {
      
          UILabel *fromLabel = [[UILabel alloc]initWithFrame:CGRectMake(50, self.view.frame.size.height/2, 300, 60)];                                                                                        
          fromLabel.text =@"No Result";
          fromLabel.baselineAdjustment = UIBaselineAdjustmentAlignBaselines;
          fromLabel.backgroundColor = [UIColor clearColor];
          fromLabel.textColor = [UIColor lightGrayColor];
          fromLabel.textAlignment = NSTextAlignmentLeft;
          [fromLabel setFont:[UIFont fontWithName:Embrima size:30.0f]];
          [self.view addSubview:fromLabel];
          [self.tblView setHidden:YES];
      }
      

      【讨论】:

      • 不要使用此解决方案。表视图数据源方法绝不能做超出它们应该做的事情。 numberOfSections 应该返回一个计数,就是这样。 numberOfRowsInSection 也一样。这些可以随时多次调用。永远不要更新视图或更新数据或做任何事情,除非返回一个计数。更新视图的逻辑绝不能在这些方法中。
      【解决方案6】:

      上述代码的 Swift 版本:-

      func numberOfSectionsInTableView(tableView: UITableView) -> Int {
      
          var numOfSection: NSInteger = 0
      
          if CCompanyLogoImage.count > 0 {
      
              self.tableView.backgroundView = nil
              numOfSection = 1
      
      
          } else {
      
              var noDataLabel: UILabel = UILabel(frame: CGRectMake(0, 0, self.tableView.bounds.size.width, self.tableView.bounds.size.height))
              noDataLabel.text = "No Data Available"
              noDataLabel.textColor = UIColor(red: 22.0/255.0, green: 106.0/255.0, blue: 176.0/255.0, alpha: 1.0)
              noDataLabel.textAlignment = NSTextAlignment.Center
              self.tableView.backgroundView = noDataLabel
      
          }
          return numOfSection
      }
      

      但是如果您从 JSON 加载信息,则需要检查 JSON 是否为空,因此如果您输入这样的代码,它最初会显示“无数据”消息然后消失。因为在表重新加载数据后消息隐藏。因此,您可以将此代码放在将 JSON 数据加载到数组的位置。所以:-

      func numberOfSectionsInTableView(tableView: UITableView) -> Int {
      
          return 1
      }
      
      func extract_json(data:NSData) {
      
      
          var error: NSError?
      
          let jsonData: AnyObject? = NSJSONSerialization.JSONObjectWithData(data, options:NSJSONReadingOptions.MutableContainers , error: &error)
          if (error == nil) {
              if let jobs_list = jsonData as? NSArray
              {
                  if jobs_list.count == 0 {
      
                      var noDataLabel: UILabel = UILabel(frame: CGRectMake(0, 0, self.tableView.bounds.size.width, self.tableView.bounds.size.height))
                      noDataLabel.text = "No Jobs Available"
                      noDataLabel.textColor = UIColor(red: 22.0/255.0, green: 106.0/255.0, blue: 176.0/255.0, alpha: 1.0)
                      noDataLabel.textAlignment = NSTextAlignment.Center
                      self.tableView.backgroundView = noDataLabel
      
                  }
      
                  for (var i = 0; i < jobs_list.count ; i++ )
                  {
                      if let jobs_obj = jobs_list[i] as? NSDictionary
                      {
                          if let vacancy_title = jobs_obj["VacancyTitle"] as? String
                          {
                              CJobTitle.append(vacancy_title)
      
                              if let vacancy_job_type = jobs_obj["VacancyJobType"] as? String
                              {
                                  CJobType.append(vacancy_job_type)
      
                                  if let company_name = jobs_obj["EmployerCompanyName"] as? String
                                  {
                                      CCompany.append(company_name)
      
                                          if let company_logo_url = jobs_obj["EmployerCompanyLogo"] as? String
                                          {
                                              //CCompanyLogo.append("http://google.com" + company_logo_url)
      
                                              let url = NSURL(string: "http://google.com" + company_logo_url )
                                              let data = NSData(contentsOfURL:url!)
                                              if data != nil {
                                                  CCompanyLogoImage.append(UIImage(data: data!)!)
                                              }
      
                                              if let vacancy_id = jobs_obj["VacancyID"] as? String
                                              {
                                                  CVacancyId.append(vacancy_id)
      
                                              }
      
                                          }
      
                                  }
      
                              }
                          }
                      }
                  }
              }
          }
          do_table_refresh();
      
      
      }
      
      func do_table_refresh() {
      
          dispatch_async(dispatch_get_main_queue(), {
              self.tableView.reloadData()
              return
          })
      }
      

      【讨论】:

      • 这对于在行中没有数据时显示标签非常有效。但是,当数据确实进入并调用self.tableView.reloadData() 时,最好的处理方法是什么?我发现它正在添加我的新行,但noDataLabel 仍显示在它们下方。
      • 如果你的数组有项目,只需设置 self.tableView.backgroundView = nil
      • if jobs_list.count == 0 { // 添加上面给定的代码 } else { self.tableView.backgroundView = nil }
      • 完美。在 return jobs_list.count 之前的 if 语句中添加 self.tableView.backgroundView = nil 效果很好。谢谢
      • 不要在这个答案中使用第一个解决方案。表视图数据源方法绝不能做超出它们应该做的事情。 numberOfSections 应该返回一个计数,就是这样。 numberOfRowsInSection 也一样。这些可以随时多次调用。永远不要更新视图或更新数据或做任何事情,除非返回一个计数。更新视图的逻辑绝不能在这些方法中。
      【解决方案7】:

      Swift3.0

      我希望它能达到你的目的...... 在你的 UITableViewController 中。

      override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
          if searchController.isActive && searchController.searchBar.text != "" {
              if filteredContacts.count > 0 {
                  self.tableView.backgroundView = .none;
                  return filteredContacts.count
              } else {
                  Helper.EmptyMessage(message: ConstantMap.NO_CONTACT_FOUND, viewController: self)
                  return 0
              }
          } else {
              if contacts.count > 0 {
                  self.tableView.backgroundView = .none;
                  return contacts.count
              } else {
                  Helper.EmptyMessage(message: ConstantMap.NO_CONTACT_FOUND, viewController: self)
                  return 0
              }
          }
      }
      

      具有功能的帮助类:

       /* Description: This function generate alert dialog for empty message by passing message and
                 associated viewcontroller for that function
                 - Parameters:
                  - message: message that require for  empty alert message
                  - viewController: selected viewcontroller at that time
               */
              static func EmptyMessage(message:String, viewController:UITableViewController) {
                  let messageLabel = UILabel(frame: CGRect(x: 0, y: 0, width: viewController.view.bounds.size.width, height: viewController.view.bounds.size.height))
                  messageLabel.text = message
                  let bubbleColor = UIColor(red: CGFloat(57)/255, green: CGFloat(81)/255, blue: CGFloat(104)/255, alpha :1)
      
                  messageLabel.textColor = bubbleColor
                  messageLabel.numberOfLines = 0;
                  messageLabel.textAlignment = .center;
                  messageLabel.font = UIFont(name: "TrebuchetMS", size: 18)
                  messageLabel.sizeToFit()
      
                  viewController.tableView.backgroundView = messageLabel;
                  viewController.tableView.separatorStyle = .none;
              }
      

      【讨论】:

      • 不要使用此解决方案。表视图数据源方法绝不能做超出它们应该做的事情。 numberOfSections 应该返回一个计数,就是这样。 numberOfRowsInSection 也一样。这些可以随时多次调用。永远不要更新视图或更新数据或做任何事情,除非返回一个计数。更新视图的逻辑绝不能在这些方法中。
      【解决方案8】:

      SWIFT 3

              let noDataLabel: UILabel     = UILabel(frame: CGRect(x: 0, y: 0, width: tableView.bounds.size.width, height: tableView.bounds.size.height))
              noDataLabel.text             = "No data available"
              noDataLabel.textColor        = UIColor.white
              noDataLabel.font             = UIFont(name: "Open Sans", size: 15)
              noDataLabel.textAlignment    = .center
              tableView.backgroundView = noDataLabel
              tableView.separatorStyle = .none
      

      【讨论】:

        【解决方案9】:

        Swift 3(更新):

        override func numberOfSections(in tableView: UITableView) -> Int {
            if myArray.count > 0 {
                self.tableView.backgroundView = nil
                self.tableView.separatorStyle = .singleLine
                return 1
            }
        
            let rect = CGRect(x: 0,
                              y: 0,
                              width: self.tableView.bounds.size.width,
                              height: self.tableView.bounds.size.height)
            let noDataLabel: UILabel = UILabel(frame: rect)
        
            noDataLabel.text = "Custom message."
            noDataLabel.textColor = UIColor.white
            noDataLabel.textAlignment = NSTextAlignment.center
            self.tableView.backgroundView = noDataLabel
            self.tableView.separatorStyle = .none
        
            return 0
        }
        

        【讨论】:

        • 不要使用此解决方案。表视图数据源方法绝不能做超出它们应该做的事情。 numberOfSections 应该返回一个计数,就是这样。 numberOfRowsInSection 也一样。这些可以随时多次调用。永远不要更新视图或更新数据或做任何事情,除非返回一个计数。更新视图的逻辑绝不能在这些方法中。
        • 我同意。这个方案可以改进,但也可以使用。
        • 你怎么能同意你不应该使用这个解决方案,但又说它也可以使用?这是一个矛盾。
        • 我同意这个解决方案可以改进,但在目前的状态下,也可以工作。
        【解决方案10】:

        这是对我有用的解决方案。

        1. 将以下代码添加到新文件中。

        2. 将您的表格类更改为故事板或 .xib 中的自定义类“MyTableView”

        (这仅适用于第一部分。如果您想自定义更多,请在 MyTableView reloadData() 函数中对其他部分进行相应更改)

        public class MyTableView: UITableView {
        
            override public func reloadData() {
                super.reloadData()
        
                if self.numberOfRows(inSection: 0) == 0 {
                    if self.viewWithTag(1111) == nil {
                        let noDataLabel = UILabel()
                        noDataLabel.textAlignment = .center
                        noDataLabel.text = "No Data Available"
                        noDataLabel.tag = 1111
                        noDataLabel.center = self.center
                        self.backgroundView = noDataLabel
                    }
        
                } else {
                    if self.viewWithTag(1111) != nil {
                        self.backgroundView = nil
                    }
                }
            }
        }
        

        【讨论】:

        • 这是一个好方法。我添加了一些增强功能,使其更加全面。 1.缓存tableview的分隔符样式,并在空/非空状态转换时恢复它,使该子类适用于需要不同分隔符样式的用例。 2.添加@IBInspectable var emptyStateText: String?并将该类标记为@IBDesignable,然后您将能够在storyboard或xibs中为不同的场景更改不同的空状态文本。享受! :)
        【解决方案11】:

        对于 Xcode 8.3.2 - Swift 3.1

        这是一种不太知名但非常简单的方法,可以将“No Items”视图添加到可追溯到 Xcode 7 的空表视图中。我将把它留给您控制添加的逻辑/ 将视图移至表格的背景视图,但这里是 Xcode (8.3.2) 故事板的流程:

        1. 在情节提要中选择具有您的表格视图的场景。
        2. 将一个空的 UIView 拖到该场景的“Scene Dock”中

        1. 向新视图添加 UILabel 和任何约束,然后为该视图创建 IBOutlet

        1. 将该视图分配给 tableView.backgroundView

        1. 看看魔法!

        最终,只要您想向视图控制器添加一个简单的视图,您不一定希望立即显示,但您也不想手动编写代码,这最终会起作用。

        【讨论】:

        • 这种技术适用于任何需要简单视图的东西。我也将它用于自定义表格部分标题。真的,您可以将它用于任何需要查看的内容。只需通过 IBOutlet 引用并将其作为子视图添加到您需要自定义视图的任何位置。
        • 正如@gmogames 所说,做IOS 2 年后第一次知道tableView 背景!。谢谢人
        • 谢谢。只是为了把它放在那里,我不得不使用 tableView.separatorStyle = .none 并调整默认 UIView 的大小以查看 backgroundView。我正在使用 Xcode 9.4 和 Swift 4。
        • 如何放置自定义视图?
        • @Nol4635 在 tableview 背景的情况下,您只需将创建为 IBOutlet 的视图分配给 tableview 的背景,或者,如果您只想将视图添加到任何其他视图,您可以将其添加为子视图。您必须设置框架值,但它与任何其他视图一样。
        【解决方案12】:

        如果您不使用 tableview 页脚并且不希望 tableview 用空的默认表格单元格填满屏幕,我建议您将 tableview 页脚设置为空的 UIView。我不知道在 obj-c 或 Swift 中执行此操作的正确语法,但在 Xamarin.iOS 中我会这样做:

        public class ViewController : UIViewController
        {
            UITableView _table;
        
            public ViewController (IntPtr handle) : base (handle)
            {
            }
        
            public override void ViewWillAppear(bool animated) {
                // Initialize table
        
                _table.TableFooterView = new UIView();
            }
        }
        

        以上代码将产生一个没有空单元格的表格视图

        【讨论】:

          【解决方案13】:

          将此代码添加到一个文件中并将您的集合类型更改为 CustomCollectionView

          import Foundation
          
          class CustomCollectionView: UICollectionView {
          
            var emptyModel = EmptyMessageModel()
            var emptyView: EmptyMessageView?
            var showEmptyView: Bool = true
          
            override func reloadData() {
              super.reloadData()
          
              emptyView?.removeFromSuperview()
              self.backgroundView = nil
          
              if !showEmptyView {
                return
              }
          
              if numberOfSections < 1 {
                let rect = CGRect(x: 0,
                                  y: 0,
                                  width: self.bounds.size.width,
                                  height: self.bounds.size.height)
          
                emptyView = EmptyMessageView()
                emptyView?.frame = rect
                if let emptyView = emptyView {
                  //                self.addSubview(emptyView)
                  self.backgroundView = emptyView
                }
                emptyView?.setView(with: emptyModel)
          
              } else {
                emptyView?.removeFromSuperview()
                self.backgroundView = nil
              }
            }
          }
          
          class EmptyMessageView: UIView {
          
            @IBOutlet weak var messageLabel: UILabel!
            @IBOutlet weak var imageView: UIImageView!
          
            var view: UIView!
          
            override init(frame: CGRect) {
              super.init(frame: frame)
              xibSetup()
            }
          
            required init?(coder aDecoder: NSCoder) {
              super.init(coder: aDecoder)
              xibSetup()
            }
          
            func xibSetup() {
              view = loadViewFromNib()
          
              view.frame = bounds
          
              view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
              addSubview(view)
            }
          
            func loadViewFromNib() -> UIView {
          
              let bundle = Bundle(for: type(of: self))
              let nib = UINib(nibName: "EmptyMessageView", bundle: bundle)
              let view = nib.instantiate(withOwner: self, options: nil)[0] as! UIView
          
              return view
            }
          
            func setView(with model: EmptyMessageModel) {
              messageLabel.text = model.message ?? ""
              imageView.image = model.image ?? #imageLiteral(resourceName: "no_notification")
            }
          }
          
          ///////////
          class EmptyMessageModel {
            var message: String?
            var image: UIImage?
          
            init(message: String = "No data available", image: UIImage = #imageLiteral(resourceName: "no_notification")) {
              self.message = message
              self.image = image
            }
          }
          

          【讨论】:

            【解决方案14】:

            如果您想在没有任何代码的情况下执行此操作,请试试这个!

            单击您的 tableView。

            将样式从“普通”更改为“分组”。

            现在当你使用 ....

            tableView.backgroundView = 插入您的标签或视图

            它不会显示分隔符!

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2021-10-09
              • 2013-02-19
              • 2015-12-15
              • 1970-01-01
              • 1970-01-01
              • 2011-11-16
              相关资源
              最近更新 更多