在Interface Builder中deviseUITableView的节标题

我有一个UITableViewxib文件,我想要使用委托方法tableView:viewForHeaderInSection:添加一个自定义节头视图。 有没有可能在Interface Builderdevise它,然后以编程方式更改它的一些子视图的属性?

我的UITableView有更多的节标题,所以在Interface Builder创build一个UIView并返回它不起作用,因为我不得不复制它,但没有任何好的方法。 存档和解除存档对UIImage不起作用,所以UIImageView将显示为空白。

另外,我不想以编程的方式来创build它们,因为它们太复杂了,所产生的代码将难以阅读和维护。

编辑1 :这是我的tableView:viewForHeaderInSection:方法:

 - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { if ([tableView.dataSource tableView:tableView numberOfRowsInSection:section] == 0) { return nil; } CGSize headerSize = CGSizeMake(self.view.frame.size.width, 100); /* wrapper */ UIView *wrapperView = [UIView viewWithSize:headerSize]; wrapperView.backgroundColor = [UIColor colorWithHexString:@"2670ce"]; /* title */ CGPoint titleMargin = CGPointMake(15, 8); UILabel *titleLabel = [UILabel labelWithText:self.categoriesNames[section] andFrame:CGEasyRectMake(titleMargin, CGSizeMake(headerSize.width - titleMargin.x * 2, 20))]; titleLabel.textColor = [UIColor whiteColor]; titleLabel.font = [UIFont fontWithStyle:FontStyleRegular andSize:14]; [wrapperView addSubview:titleLabel]; /* body wrapper */ CGPoint bodyWrapperMargin = CGPointMake(10, 8); CGPoint bodyWrapperViewOrigin = CGPointMake(bodyWrapperMargin.x, CGRectGetMaxY(titleLabel.frame) + bodyWrapperMargin.y); CGSize bodyWrapperViewSize = CGSizeMake(headerSize.width - bodyWrapperMargin.x * 2, headerSize.height - bodyWrapperViewOrigin.y - bodyWrapperMargin.y); UIView *bodyWrapperView = [UIView viewWithFrame:CGEasyRectMake(bodyWrapperViewOrigin, bodyWrapperViewSize)]; [wrapperView addSubview:bodyWrapperView]; /* image */ NSInteger imageSize = 56; NSString *imageName = [self getCategoryResourceItem:section + 1][@"image"]; UIImageView *imageView = [UIImageView imageViewWithImage:[UIImage imageNamed:imageName] andFrame:CGEasyRectMake(CGPointZero, CGEqualSizeMake(imageSize))]; imageView.layer.masksToBounds = YES; imageView.layer.cornerRadius = imageSize / 2; [bodyWrapperView addSubview:imageView]; /* labels */ NSInteger labelsWidth = 60; UILabel *firstLabel = [UILabel labelWithText:@"first" andFrame:CGRectMake(imageSize + bodyWrapperMargin.x, 0, labelsWidth, 16)]; [bodyWrapperView addSubview:firstLabel]; UILabel *secondLabel = [UILabel labelWithText:@"second" andFrame:CGRectMake(imageSize + bodyWrapperMargin.x, 20, labelsWidth, 16)]; [bodyWrapperView addSubview:secondLabel]; UILabel *thirdLabel = [UILabel labelWithText:@"third" andFrame:CGRectMake(imageSize + bodyWrapperMargin.x, 40, labelsWidth, 16)]; [bodyWrapperView addSubview:thirdLabel]; [@[ firstLabel, secondLabel, thirdLabel ] forEachView:^(UIView *view) { UILabel *label = (UILabel *)view; label.textColor = [UIColor whiteColor]; label.font = [UIFont fontWithStyle:FontStyleLight andSize:11]; }]; /* line */ UIView *lineView = [UIView viewWithFrame:CGRectMake(imageSize + labelsWidth + bodyWrapperMargin.x * 2, bodyWrapperMargin.y, 1, bodyWrapperView.frame.size.height - bodyWrapperMargin.y * 2)]; lineView.backgroundColor = [UIColor whiteColorWithAlpha:0.2]; [bodyWrapperView addSubview:lineView]; /* progress */ CGPoint progressSliderOrigin = CGPointMake(imageSize + labelsWidth + bodyWrapperMargin.x * 3 + 1, bodyWrapperView.frame.size.height / 2 - 15); CGSize progressSliderSize = CGSizeMake(bodyWrapperViewSize.width - bodyWrapperMargin.x - progressSliderOrigin.x, 30); UISlider *progressSlider = [UISlider viewWithFrame:CGEasyRectMake(progressSliderOrigin, progressSliderSize)]; progressSlider.value = [self getCategoryProgress]; [bodyWrapperView addSubview:progressSlider]; return wrapperView; } 

我希望它看起来像这样:

 - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { if ([tableView.dataSource tableView:tableView numberOfRowsInSection:section] == 0) { return nil; } SectionView *sectionView = ... // get the view that is already designed in the Interface Builder sectionView.headerText = self.categoriesNames[section]; sectionView.headerImage = [self getCategoryResourceItem:section + 1][@"image"]; sectionView.firstLabelText = @"first"; sectionView.secondLabelText = @"second"; sectionView.thirdLabelText = @"third"; sectionView.progress = [self getCategoryProgress]; return wrapperView; } 

编辑2 :我不使用Storyboard ,只是.xib文件。 另外,我没有一个UITableViewController ,只是一个UIViewController ,我添加了一个UITableView

故事板或XIB

  1. 同样的Storyboard

     return tableView.dequeueReusableCell(withIdentifier: "header") 

    两段标题

  2. 单独的XIB (附加步骤:您必须先注册该Nib ):

     tableView.register(UINib(nibName: "XIBSectionHeader", bundle:nil), forCellReuseIdentifier: "xibheader") 

要从Storyboard而不是XIB加载,请参阅Stack Overflow答案 。


使用UITableViewCell在IB中创buildSection Header

利用这个事实,一个节头是一个普通的UIView ,而UITableViewCell也是一个UIView 。 在界面生成器中 ,将表格视图单元对象库拖放到您的表视图原型内容中

标识符添加到新添加的表格视图单元格中 ,并自定义其外观以满足您的需求。 对于这个例子,我使用header

编辑单元格

使用dequeueReusableCell:withIdentifier来定位您的部分标题,就像您使用任何表格视图单元格一样。 您将需要提供heightForHeaderInSection ,为了清晰起见,将其硬编码为44

 //MARK: UITableViewDelegate override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { // This is where you would change section header content return tableView.dequeueReusableCell(withIdentifier: "header") } override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { return 44 } 

Swift 2及更早版本:

 return tableView.dequeueReusableCellWithIdentifier("header") as? UIView self.tableView.registerNib(UINib(nibName: "XIBSectionHeader", bundle:nil), forCellReuseIdentifier: "xibheader") 

►在GitHub上find这个解决scheme和Swift Recipes的更多细节。

我终于用这个教程来解决它,主要由以下内容组成(适应我的例子)

  1. 创build子类UIView SectionHeaderView类。
  2. 创buildSectionHeaderView.xib文件,并将其File's OwnerCustomClass设置为SectionHeaderView类。
  3. .m文件中创build一个UIView属性,如: @property (strong, nonatomic) IBOutlet UIView *viewContent;
  4. viewContentView连接到这个viewContent出口。
  5. 添加一个如下所示的初始化方法:

     + (instancetype)header { SectionHeaderView *sectionHeaderView = [[SectionHeaderView alloc] init]; if (sectionHeaderView) { // important part sectionHeaderView.viewContent = [[[NSBundle mainBundle] loadNibNamed:NSStringFromClass([self class]) owner:sectionHeaderView options:nil] firstObject]; [sectionHeaderView addSubview:sectionHeaderView.viewContent]; return sectionHeaderView; } return nil; } 

然后,我在labelCategoryName文件中添加了一个UILabel ,并将其连接到labelCategoryName出口,并在SectionHeaderView类中实现了setCategoryName:方法,如下所示:

 - (void)setCategoryName:(NSString *)categoryName { self.labelCategoryName.text = categoryName; } 

然后我实现了这样的tableView:viewForHeaderInSection:方法:

 - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { SectionHeaderView *sectionHeaderView = [SectionHeaderView header]; [sectionHeaderView setCategoryName:self.categoriesNames[section]]; return sectionHeaderView; } 

它终于奏效了。 每个部分都有自己的名字,并且UIImageView也能正常显示。

希望它可以帮助别人一遍又一遍地在同一个错误的解决scheme上绊倒,就像我一样。

解决方法简单

创build一个xib,根据您的文档制作UI,然后在viewForHeaderInSection中获取xib

 -(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { NSArray *nibArray = [[NSBundle mainBundle] loadNibNamed:@"HeaderView" owner:self options:nil]; HeaderView *headerView = [nibArray objectAtIndex:0]; return headerView; } 

据我了解你的问题,你想有相同的UIView多次重复多个部分标题,你想能够显示。

如果这是我的问题,这是我将如何解决它。

原来的解决scheme

1)

在我拥有表视图的UIViewController中,我也创build了一个视图,这是一个模板头。 将其分配给IBOutlet。 这将是您可以通过Interface Builder进行编辑的视图

2)

在您的ViewDidLoad或(也许更好) ViewWillAppear方法中,您将需要制作该头文件模板UIView的副本,因为您需要显示节标题。

在内存中制作UIViews的副本不是微不足道的,但也不难。 下面是一个相关问题的答案,告诉你如何去做。

将副本添加到一个NSMutableArray (其中每个对象的索引将对应于这些部分…数组的索引0中的视图将是您返回的部分0,数组中的视图1的第1部分,ec。) 。

3)

您将无法使用IBOutlets作为该部分标题的元素 (因为您的代码仅将插口与来自XIB文件的特定视图相关联)。

所以,对于这个,你可能会想要为你的标题视图中的每个UI元素使用视图标签属性,你需要修改/更改每个不同的部分。 您可以通过Interface Builder设置这些标签,然后在您的代码中以编程方式引用它们。

在你的viewForHeaderInSection方法中,你会做类似的事情:

 - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { if ([tableView.dataSource tableView:tableView numberOfRowsInSection:section] == 0) { return nil; } SectionView *sectionView = [self.arrayOfDuplicatedHeaderViews objectAtIndex: section]; // my title view has a tag of 10 UILabel *titleToModify = [sectionView viewWithTag: 10]; if(titleToModify) { titleToModify.text = [NSString stringWithFormat:@"section %d", section]; } return sectionView; } 

说得通?

不同的解决scheme

1)

你仍然需要一个UIViews(或者“ Section View ”子类UIViews)的数组,但是你可以用连续的调用来创build它们,从它自己的XIB文件中加载视图。

像这样的东西:

 @implementation SectionView + (SectionView*) getSectionView { NSArray* array = [[NSBundle mainBundle] loadNibNamed:@"SectionView" owner:nil options:nil]; return [array objectAtIndex:0]; // assume that SectionView is the only object in the xib } @end 

( 在这个相关问题的答案中有更多的细节)

2)

可能可以使用IBOutlets(但我不是100%肯定),但标签属性再次可能工作得很好。