当前位置: 首页 > 知识库问答 >
问题:

在界面生成器中设计UITableView的节标题

狄宏大
2023-03-14

我有一个带有UITableView的xib文件,我想使用委托方法为其添加一个自定义的节标题视图。有没有可能在Interface Builder中设计它,然后以编程方式更改它的某些子视图属性?

我的UITableView有更多的节标题,因此在接口生成器中创建一个 并返回它是行不通的,因为我必须复制它,但没有任何好的方法。归档和取消归档对于 UIImages不起作用,因此 UIImageViews将显示为空白。

此外,我不想以编程方式创建它们,因为它们太复杂了,并且生成的代码很难阅读和维护。

编辑1:这是我的表查看:视图标题部分:方法:

- (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:我没有使用< code >故事板,只是< code >。xib文件。另外,我没有< code > UITableViewController ,只有一个< code>UIViewController,我在其中添加了一个< code>UITableView。

共有3个答案

尹正奇
2023-03-14

解决方案很简单

创建一个xib,根据您的文档制作UI,然后在viewForHeaderInSect中获取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;
} 
柳向明
2023-03-14

我最终使用本教程解决了这个问题,本教程主要包括以下内容(根据我的示例改编):

>

  • 创建子类UIViewSectionHeaderView类。
  • 创建SectionHeaderView.xib文件并将其File's OwnerCustomClass设置为SectionHeaderView类。
  • . m文件中创建一个UIView属性,如下所示:@属性(强,非原子)IBOutlet UIView*viewContent;
  • . xibView连接到此viewContent出口。
  • 添加一个如下所示的初始化器方法:

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

    然后,我在 .xib 文件中添加了一个 UILabel,并将其连接到标签类别名称出口,并在节标题视图类中实现了 set 类别名称: 方法,如下所示:

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

    然后我实现了tableView: viewForHeaderInSect:方法,如下所示:

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

    它终于奏效了。每个部分都有自己的名称,并且 UI 图像视图也会正确显示。

    希望它能帮助那些像我一样在网上一次又一次被同样的错误解决方案绊倒的人。

  • 潘佐
    2023-03-14

    #Storyboard或西布。已更新至 2020 年。

    >

  • 相同的故事板

     return tableView.dequeueReusableCell(withIdentifier: "header")
    

    单独< code>XIB(附加步骤:您必须首先注册< code >笔尖):

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

    要从< code >故事板而不是< code>XIB加载,请参见此堆栈溢出答案。

    #使用UITableViewCell在IB中创建节标题

    利用这样一个事实:节标题是一个常规的< code>UIView,而< code>UITableViewCell也是一个< code>UIView。在界面构建器中,拖动

    (2020)在现代Xcode中,只需增加“动态原型”数量即可减少更多单元:

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

    使用dequeueReusableCell:withIdentifier查找单元格,就像查找任何表视图单元格一样。

    不要忘记它只是一个普通的单元格:但是你将把它用作一个标题。

    对于2020,只需在< code>ViewDidLoad中添加四行代码:

    tableView.rowHeight = UITableView.automaticDimension
    tableView.estimatedRowHeight = 70   // any reasonable value is fine
    tableView.sectionHeaderHeight =  UITableView.automaticDimension
    tableView.estimatedSectionHeaderHeight = 70 // any reasonable value is fine
    

    {有关讨论,请参见此示例。}

    标题单元格高度现在完全是动态的。更改标题中文本等的长度是可以的。

    (提示:纯粹关于故事板:简单地选择...

    …在故事板中,以便故事板能够正常工作。这对最终构建没有任何影响。选中该复选框对最终构建没有任何影响。如果高度是动态的,那么它的存在纯粹是为了使故事板正确工作。)

    在旧的Xcode中,或者,如果出于某种原因您不希望使用动态高度:

    只需提供heightForHeaderInDistrict,在此示例中,为清楚起见,将其硬编码为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上找到该解决方案,以及Swift菜谱的更多详细信息。

  •  类似资料:
    • 5. 生成器(Builder) Intent 封装一个对象的构造过程,并允许按步骤构造。 Class Diagram Implementation 以下是一个简易的 StringBuilder 实现,参考了 JDK 1.8 源码。 // java public class AbstractStringBuilder { protected char[] value; protec

    • 我创建了这个部分标题,不幸的是,我不知道如何在右边添加一些填充。 这是我的密码:

    • 扩展的交互界面应该是有目的且最简单的。 就像扩展本身一样,界面 UI 应该是自定义或能增强浏览体验,而不会分散用户注意力。 本指南探讨了必需的和可选的用户界面功能,了解如何以及何时在扩展中实现不同的 UI 元素。 在所有页面上激活扩展 当扩展程序的功能在大多数情况下都可以使用时,请使用 browser_action 。 注册 browser_action browser_action 在 mani

    • 我正在使用IntelliJ GUI Designer来生成一个GUI应用程序(第一次用户)。我尝试生成一些小的示例UI,并能够做到这一点。然而,今天尝试一些东西,应用程序提示我提供一个用户名和日期,我认为这在包文件中做了更改(我想)。从那以后,每当我生成一个新的GUI表单时,它都不会生成。java文件(只生成。form文件)。并给出了以下错误。

    • 主要内容:本节引言:,Mockplus原型工具的使用:,Android自带DroidDraw工具设计Android界面:,本节小结:本节引言: 引用锤子科技视觉设计总监——罗子雄在重庆TEDx活动上说的一小段话: 每当我们看到一些美妙的设计的时候,很多人心里面会有一种冲动,这种冲动会让你们想去创造一些 新的东西,创造一些美妙的事物。 我们常说用户体验用户体验,用户使用你的软件,第一个会接触的是什么?没错,图形化界面(GUI),简称UI,对于用户而言,最直观,给用户留下第一印像的是往往是程序的界面

    • 这种设计模式是否只适用于一个接口,因为我能找到的只是谈论由类实现的接口? 就像网站http://www.tutorialspoint.com/design_pattern/data_access_object_pattern.htm 如果我有很多接口,那么设计模式很好用,那么类图会是谁? 谢谢。