【问题标题】:Customize UITableView header section自定义 UITableView 标题部分
【发布时间】:2013-03-14 17:33:35
【问题描述】:

我想为每个部分自定义 UITableView 标头。到目前为止,我已经实现了

-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section

这个UITabelViewDelegate 方法。我想要做的是获取每个部分的当前标题,然后将UILabel 添加为子视图。

到目前为止,我无法做到这一点。因为,我找不到任何东西来获取默认的节标题。第一个问题,有什么办法可以得到默认的section header

如果不可能,我需要创建一个容器视图,它是UIView,但是这次我需要设置默认背景颜色、阴影颜色等。因为,如果你仔细查看部分的标题,它已经被自定义了.

如何获取每个节标题的这些默认值?

【问题讨论】:

标签: ios objective-c swift uitableview


【解决方案1】:

Swift 5 代码

我们可以通过使用两个 tableView 委托函数来实现:

1] 我们可以为该部分指定自定义高度:

func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
    return 49
}
    

2] 然后我们可以创建自定义标题:

 func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    let sectionV = UIView.init(frame: CGRect(x: 0, y: 0, width: tableView.frame.width, height: 48) )
    let titleLbl = UILabel.init(frame: CGRect(x: 25, y: 24, width: tableView.frame.width-150, height: 20) )
    let viewAllBtn = UIButton.init(frame: CGRect(x: tableView.frame.width-150, y: 15, width: self.view.frame.width - titleLbl.frame.width, height: 45))
    viewAllBtn.titleLabel?.font = UIFont.systemFont(ofSize: 15)
    viewAllBtn.setTitle("View All", for: .normal)
    viewAllBtn.setTitleColor(.systemBlue, for: .normal)
    viewAllBtn.tag = section
    titleLbl.text = dashboardTempData.data?[section].title
    titleLbl.font = UIFont.systemFont(ofSize: 21, weight: UIFont.Weight.medium)
    sectionV.backgroundColor = .systemBackground
    sectionV.addSubview(titleLbl)
    sectionV.addSubview(viewAllBtn)
    sectionV.bringSubviewToFront(viewAllBtn)
    return sectionV
}

它将创建一个标签和按钮,部分标题高度为 49

【讨论】:

    【解决方案2】:

    复制和粘贴完整的 2019 示例

    在情节提要上首次设置“分组”:它必须在初始化时发生,您以后无法真正设置,因此在情节提要上更容易记住:

    接下来,

    必须实现 heightForHeaderInSection 由于 Apple 错误。

    func tableView(_ tableView: UITableView,
                       heightForHeaderInSection section: Int) -> CGFloat {
        return CGFloat(70.0)
    }
    

    Apple 仍然存在一个错误 - 十年了 - 如果您没有 heightForHeaderInSection 调用,它根本不会显示第一个标题(即索引 0)。

    所以,tableView.sectionHeaderHeight = 70 根本不起作用,它坏了

    设置框架无济于事:

    viewForHeaderInSection 中只需创建一个 UIView()。

    如果你 UIView(frame ...) 是没有意义的/什么都做不了,因为 iOS 只是将视图的大小设置为由表格确定。

    所以viewForHeaderInSection 的第一行就是let view = UIView(),这就是你返回的视图。

    func tableView(_ tableView: UITableView,
                           viewForHeaderInSection section: Int) -> UIView? {
        let view = UIView()
        
        let l = UILabel()
        view.addSubview(l)
        l.bindEdgesToSuperview()
        l.backgroundColor = .systemOrange
        l.font = UIFont.systemFont(ofSize: 15)
        l.textColor = .yourClientsFavoriteColor
        
        switch section {
        case 0:
            l.text =  "First section on screen"
        case 1:
            l.text =  "Here's the second section"
        default:
            l.text =  ""
        }
        
        return view
    }
    

    就是这样 - 其他任何事情都是浪费时间。

    另一个“挑剔”的苹果问题。


    上面使用的便利扩展是:

    extension UIView {
        
        // incredibly useful:
        
        func bindEdgesToSuperview() {
            
            guard let s = superview else {
                preconditionFailure("`superview` nil in bindEdgesToSuperview")
            }
            
            translatesAutoresizingMaskIntoConstraints = false
            leadingAnchor.constraint(equalTo: s.leadingAnchor).isActive = true
            trailingAnchor.constraint(equalTo: s.trailingAnchor).isActive = true
            topAnchor.constraint(equalTo: s.topAnchor).isActive = true
            bottomAnchor.constraint(equalTo: s.bottomAnchor).isActive = true
        }
    }
    

    【讨论】:

      【解决方案3】:

      斯威夫特 4.2

      在 Swift 4.2 中,表的名称略有变化。

          func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
              let view = UIView(frame: CGRect(x: 0, y: 0, width: tableView.frame.size.width, height: 18))
              let label = UILabel(frame: CGRect(x: 10, y: 5, width: tableView.frame.size.width, height: 18))
              label.font = UIFont.systemFont(ofSize: 14)
              label.text = list.objectAtIndex(section) as! String
              view.addSubview(label)
              view.backgroundColor = UIColor.gray // Set your background color
      
              return view
          }
      

      【讨论】:

        【解决方案4】:

        其他答案在重新创建默认标题视图方面做得很好,但实际上并没有回答您的主要问题:

        有什么方法可以获取默认的节标题?

        有一种方法 - 只需在您的委托中实现 tableView:willDisplayHeaderView:forSection:。默认的标题视图将被传递到第二个参数中,您可以从那里将其转换为UITableViewHeaderFooterView,然后根据需要添加/更改子视图。

        Obj-C

        - (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section
        {
            UITableViewHeaderFooterView *headerView = (UITableViewHeaderFooterView *)view;
        
            // Do whatever with the header view... e.g.
            // headerView.textLabel.textColor = [UIColor whiteColor]
        }
        

        斯威夫特

        override func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int)
        {
            let headerView = view as! UITableViewHeaderFooterView
        
            // Do whatever with the header view... e.g.
            // headerView.textLabel?.textColor = UIColor.white
        }
        

        【讨论】:

        • 你不需要投射它。您可以将所需的内容添加到视图中。事实上,除非你将它分配给view,否则创建一个新对象不会有任何作用。
        • @AlexZavatone 没错,如果您只是添加视图,则不需要投射它。如果您想自定义一些默认视图(例如文本标签),这将很有帮助。
        【解决方案5】:

        swif 4.2

        override func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
            guard let header = view as? UITableViewHeaderFooterView else { return }
        
            header.textLabel?.textAlignment = .center // for all sections
        
            switch section {
            case 1:  //only section No.1
                header.textLabel?.textColor = .black
            case 3:  //only section No.3
                header.textLabel?.textColor = .red
            default: //
                header.textLabel?.textColor = .yellow
            }
        }
        

        【讨论】:

          【解决方案6】:

          使用tableView: willDisplayHeaderView: 自定义即将显示的视图。

          这使您能够获取已经为标题视图创建的视图并对其进行扩展,而不必自己重新创建整个标题视图。

          这是一个基于 BOOL 为标题部分着色并向标题添加详细文本元素的示例。

          - (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section
          {
          //    view.tintColor = [UIColor colorWithWhite:0.825 alpha:1.0]; // gray
          //    view.tintColor = [UIColor colorWithRed:0.825 green:0.725 blue:0.725 alpha:1.0]; // reddish
          //    view.tintColor = [UIColor colorWithRed:0.925 green:0.725 blue:0.725 alpha:1.0]; // pink
          
              // Conditionally tint the header view
              BOOL isMyThingOnOrOff = [self isMyThingOnOrOff];
          
              if (isMyThingOnOrOff) {
                  view.tintColor = [UIColor colorWithRed:0.725 green:0.925 blue:0.725 alpha:1.0];
              } else {
                  view.tintColor = [UIColor colorWithRed:0.925 green:0.725 blue:0.725 alpha:1.0];
              }
          
              /* Add a detail text label (which has its own view to the section header… */
              CGFloat xOrigin = 100; // arbitrary
              CGFloat hInset = 20;
              UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(xOrigin + hInset, 5, tableView.frame.size.width - xOrigin - (hInset * 2), 22)];
          
              label.textAlignment = NSTextAlignmentRight;
          
              [label setFont:[UIFont fontWithName:@"Helvetica-Bold" size:14.0]
              label.text = @"Hi.  I'm the detail text";
          
              [view addSubview:label];
          }
          

          【讨论】:

            【解决方案7】:

            调用这个委托方法

            -(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{
            
            return @"Some Title";
            }
            

            这将有机会自动添加带有动态标题的默认标题。

            您可以使用可重复使用和可自定义的页眉/页脚。

            https://github.com/sourov2008/UITableViewCustomHeaderFooterSection

            【讨论】:

              【解决方案8】:
              - (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section
              {
                  if([view isKindOfClass:[UITableViewHeaderFooterView class]]){
              
                      UITableViewHeaderFooterView *headerView = view;
              
                      [[headerView textLabel] setTextColor:[UIColor colorWithHexString:@"666666"]];
                      [[headerView textLabel] setFont:[UIFont fontWithName:@"fontname" size:10]];
                  }
              }
              

              如果您想更改节标题中 textLabel 的字体,您可以在 willDisplayHeaderView 中进行。要设置文本,您可以在 viewForHeaderInSection 或 titleForHeaderInSection 中进行。祝你好运!

              【讨论】:

                【解决方案9】:

                Swift 3 版本的 lochana 和 estemendoza 答案:

                override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
                
                    let view = UIView(frame: CGRect(x:0, y:0, width:tableView.frame.size.width, height:18))
                    let label = UILabel(frame: CGRect(x:10, y:5, width:tableView.frame.size.width, height:18))
                    label.font = UIFont.systemFont(ofSize: 14)
                    label.text = "This is a test";
                    view.addSubview(label);
                    view.backgroundColor = UIColor.gray;
                    return view
                
                }
                

                另外,请注意,您还必须实施:

                override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
                    return 100;
                }
                

                【讨论】:

                  【解决方案10】:

                  这是最简单的解决方案。以下代码可直接用于创建自定义节标题。

                   -(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
                  {
                      SectionHeaderTableViewCell *headerView = [tableView dequeueReusableCellWithIdentifier:@"sectionHeader"];
                  
                      //For creating a drop menu of rows from the section
                      //==THIS IS JUST AN EXAMPLE. YOU CAN REMOVE THIS IF-ELSE.==
                      if (![self.sectionCollapsedArray[section] boolValue])
                      {
                          headerView.imageView.image = [UIImage imageNamed:@"up_icon"];
                      }
                      else
                      {
                          headerView.imageView.image = [UIImage imageNamed:@"drop_icon"];
                      }
                  
                      //For button action inside the custom cell
                      headerView.dropButton.tag = section;
                      [headerView.dropButton addTarget:self action:@selector(sectionTapped:) forControlEvents:UIControlEventTouchUpInside];
                  
                      //For removing long touch gestures.
                      for (UIGestureRecognizer *recognizer in headerView.contentView.gestureRecognizers)
                      {
                          [headerView.contentView removeGestureRecognizer:recognizer];
                          [headerView removeGestureRecognizer:recognizer];
                      }
                  
                      return headerView.contentView;
                  }
                  

                  注意:SectionHeaderTableViewCell 是在 Storyboard 中创建的自定义 UITableViewCell。

                  【讨论】:

                  • SectionHeaderTableViewCell - 使用未声明的标识符
                  • @BorisGafurov SectionHeaderTableViewCell 只是我在故事板中创建的 UITableViewCell 的示例名称。
                  【解决方案11】:

                  回到最初的问题(4 年后),而不是重建您自己的节标题,iOS 可以在构建默认标题后立即调用您(使用 willDisplayHeaderView:forSection:)。例如,我想在节标题的右边缘添加一个图形按钮:

                  - (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section {
                      UITableViewHeaderFooterView * header = (UITableViewHeaderFooterView *) view;
                      if (header.contentView.subviews.count >  0) return; //in case of reuse
                      CGFloat rightEdge = CGRectGetMaxX(header.contentView.bounds);
                      UIButton * button = [[UIButton alloc] initWithFrame:CGRectMake(rightEdge - 44, 0, 44, CGRectGetMaxY(header.contentView.bounds))];
                      [button setBackgroundImage:[UIImage imageNamed:@"graphIcon"] forState:UIControlStateNormal];
                      [button addTarget:self action:@selector(graphButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
                      [view addSubview:button];
                  }
                  

                  【讨论】:

                    【解决方案12】:

                    如果您只想为 tableView 标题添加标题,请不要添加视图。在 swift 3.x 中,代码如下所示:

                    override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
                        var lblStr = ""
                        if section == 0 {
                            lblStr = "Some String 1"
                        }
                        else if section == 1{
                            lblStr = "Some String 2"
                        }
                        else{
                            lblStr = "Some String 3"
                        }
                        return lblStr
                    }
                    

                    您可以实现一个数组来获取标题的标题。

                    【讨论】:

                      【解决方案13】:

                      @samwize 在 Swift 中的解决方案(所以支持他!)。出色的页眉/页脚部分也使用相同的回收机制:

                      func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
                          let settingsHeaderSectionCell:SettingsHeaderSectionCell = self.dequeueReusableCell(withIdentifier: "SettingsHeaderSectionCell") as! SettingsHeaderSectionCell
                      
                          return settingsHeaderSectionCell
                      }
                      

                      【讨论】:

                        【解决方案14】:

                        如果没有显示 headerInSection,可以试试这个。

                        - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
                        {
                            return 45;
                        }
                        

                        这将返回给定节的标题的高度。

                        【讨论】:

                        • 介意详细说明你的答案吗?
                        • 标题部分不会显示,除非您使用钩子方法指定部分标题的“高度”。如果没有指定高度,UITableView 默认不显示标题。 @CinCout
                        【解决方案15】:
                        -(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
                        {
                            //put your values, this is part of my code
                            UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 30.0f)];
                            [view setBackgroundColor:[UIColor redColor]];
                            UILabel *lbl = [[UILabel alloc] initWithFrame:CGRectMake(20, 5, 150, 20)];
                            [lbl setFont:[UIFont systemFontOfSize:18]];
                            [lbl setTextColor:[UIColor blueColor]];
                            [view addSubview:lbl];
                        
                            [lbl setText:[NSString stringWithFormat:@"Section: %ld",(long)section]];
                        
                            return view;
                        }
                        

                        【讨论】:

                          【解决方案16】:

                          试试这个......

                          override func tableView(tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) 
                          {
                              // Background view is at index 0, content view at index 1
                              if let bgView = view.subviews[0] as? UIView
                              {
                                  // do your stuff
                              }
                          
                              view.layer.borderColor = UIColor.magentaColor().CGColor
                              view.layer.borderWidth = 1
                          }
                          

                          【讨论】:

                            【解决方案17】:

                            Lochana Tejas 的 Swift 版本回答:

                            override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
                                let view = UIView(frame: CGRectMake(0, 0, tableView.frame.size.width, 18))
                                let label = UILabel(frame: CGRectMake(10, 5, tableView.frame.size.width, 18))
                                label.font = UIFont.systemFontOfSize(14)
                                label.text = list.objectAtIndex(indexPath.row) as! String
                                view.addSubview(label)
                                view.backgroundColor = UIColor.grayColor() // Set your background color
                            
                                return view
                            }
                            

                            【讨论】:

                            • 如何根据视图内的文本使标签高度动态化?
                            • override 关键字是多余的。更重要的是,考虑重用标题视图而不是重新创建它们。
                            【解决方案18】:

                            神奇地在swift中添加Table View Header

                            最近我试过这个。

                            我在整个 UITableView 中只需要一个标题。

                            就像我想要在 TableView 顶部的 UIImageView。所以我在 UITableViewCell 上添加了一个 UIImageView 并自动将它添加为 tableViewHeader。现在我将 ImageView 连接到 ViewController 并添加了 Image。

                            我很困惑,因为我是第一次做这样的事情。因此,为了消除我的困惑,打开 MainStoryBoard 的 xml 格式,发现 Image View 被添加为标题。

                            它对我有用。感谢 xCode 和 swift。

                            【讨论】:

                              【解决方案19】:

                              使用tableView :viewForHeaderInSection: 选择的答案是正确的。

                              只是在这里分享一个提示。

                              如果您使用的是故事板/xib,那么您可以创建另一个原型单元并将其用于您的“部分单元”。配置表头的代码与配置行单元格的代码类似。

                              - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
                                  static NSString *HeaderCellIdentifier = @"Header";
                              
                                  UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:HeaderCellIdentifier];
                                  if (cell == nil) {
                                      cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:HeaderCellIdentifier];
                                  }
                              
                                  // Configure the cell title etc
                                  [self configureHeaderCell:cell inSection:section];
                              
                                  return cell;
                              }
                              

                              【讨论】:

                              • 这个解决方案有很多问题。首先是如果你实现“tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool”,你会注意到当你滑动时节标题会随着行一起移动。为避免这种情况,您必须改为返回 cell.contentView。更大的问题是,使用此解决方案,当您长按部分标题时,应用程序将崩溃。正确的方法是创建一个扩展 UITableViewHeaderFooterView 的 nib,将其注册到 tableview 并在此方法中返回。在 iOS8 上测试
                              • @Kachi 解决方案是使用viewForHeaderInSection 而不是canEditRowAtIndexPath,正如您所提到的。我从来没有验证过你说的崩溃,但你能解释一下长按会导致崩溃吗?
                              • 我的意思是,如果您实施此解决方案并实施 canEditRowAtIndexPath,如果您不返回 cell.contentView,您将看到标题也将与您要删除的最顶行一起滑动。请参阅此 SO 帖子:stackoverflow.com/questions/26009722/… 长按会导致崩溃,因为一条消息试图发送到已释放的对象。请参阅此 SO 帖子:stackoverflow.com/questions/27622290/…
                              • 请永远不要使用UITableViewCell 作为标题视图。您将很难调试视觉故障 - 由于单元格的出列方式,标题有时会消失,您将寻找几个小时为什么会这样,直到您意识到 UITableViewCell 不属于 UITableView 标题。
                              • 使用UITableViewCell 作为标题是完全错误的。
                              【解决方案20】:

                              除了titleForHeaderInSection,你可以简单地改变页眉、页脚的视图。 在这里查看我的评论:Change UITable section backgroundColor without loosing section Title

                              【讨论】:

                                【解决方案21】:

                                如果您使用默认标题视图,您只能更改其上的文本

                                - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
                                

                                对于斯威夫特:

                                override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
                                

                                如果您想自定义视图,您需要自己创建一个新视图。

                                【讨论】:

                                  【解决方案22】:

                                  为什么不使用UITableViewHeaderFooterView

                                  【讨论】:

                                  • 只有在不使用 -(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section 的情况下才能使用它。
                                  • 完全有效的答案。此外,使用 UITableViewHeaderFooterView 可以像单元格一样从视图回收中受益。
                                  • @dmarsi 我没有发现它们被弃用的证据。
                                  【解决方案23】:

                                  你可以试试这个:

                                   -(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
                                  {
                                      UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, tableView.frame.size.width, 18)];
                                      /* Create custom view to display section header... */
                                      UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(10, 5, tableView.frame.size.width, 18)];
                                      [label setFont:[UIFont boldSystemFontOfSize:12]];
                                       NSString *string =[list objectAtIndex:section];
                                      /* Section header is in 0th index... */
                                      [label setText:string];
                                      [view addSubview:label];
                                      [view setBackgroundColor:[UIColor colorWithRed:166/255.0 green:177/255.0 blue:186/255.0 alpha:1.0]]; //your background color...
                                      return view;
                                  }
                                  

                                  【讨论】:

                                  • 这就是你想要设置的 bg 颜色水色,你可以
                                  • 这就是问题所在,我已经完成了你写的。但是,我不知道节标题的默认背景颜色,这是一种灰色。但是,我需要它是完全默认的节标题。
                                  • 嘿,使用数字色度计
                                  • 确保同时设置 UILabel 的背景颜色。我知道当我的背景没有变得清晰时,我有点困惑。
                                  • 什么是行 NSString *string =[list objectAtIndex:section];谁能告诉我
                                  【解决方案24】:

                                  如果我是你,我会创建一个返回 UIView 的方法,给定一个 NSString 来包含。例如

                                  + (UIView *) sectionViewWithTitle:(NSString *)title;
                                  

                                  在这个方法的实现中创建一个UIView,给它添加一个带有你想要设置的属性的UILabel,当然也要把它的标题设置为给定的。

                                  【讨论】:

                                  • 是的,我可以做到,但我的问题是如何获得默认的节标题背景,阴影值,其余的很容易实现。
                                  • 默认节标题背景是什么意思
                                  • 嗯,最简单的方法是使用数字色度计应用程序来获得您想要的颜色。据我所知,通过代码获取它们会很困难......
                                  猜你喜欢
                                  • 2023-03-14
                                  • 1970-01-01
                                  • 1970-01-01
                                  • 1970-01-01
                                  • 1970-01-01
                                  • 1970-01-01
                                  • 1970-01-01
                                  • 1970-01-01
                                  • 2013-11-26
                                  相关资源
                                  最近更新 更多