Ios 将UIButton添加到UITableView节标题

Ios 将UIButton添加到UITableView节标题,ios,objective-c,uitableview,uiview,uibutton,Ios,Objective C,Uitableview,Uiview,Uibutton,我有一个UITableView,其中有一个部分,对于部分标题,我想保持标题的所有内容不变,但只需在右侧添加一个按钮。我无法将该按钮放入导航控制器,因为放置该按钮的两个可用位置已被其他按钮占用 在这里你可以看到我尝试做的结果。现在我想做的就是在标题的右侧放置一个add按钮,但我尝试的方法没有成功。我还在StackOverflow上尝试了其他一些解决方案,但它们并没有达到我想要的效果。此外,如果有更好的方法创建添加按钮,请让我知道。我尝试使用UIBarButtonItem,但我不知道如何将其视图添加

我有一个
UITableView
,其中有一个部分,对于部分标题,我想保持标题的所有内容不变,但只需在右侧添加一个按钮。我无法将该按钮放入导航控制器,因为放置该按钮的两个可用位置已被其他按钮占用

在这里你可以看到我尝试做的结果。现在我想做的就是在标题的右侧放置一个add按钮,但我尝试的方法没有成功。我还在StackOverflow上尝试了其他一些解决方案,但它们并没有达到我想要的效果。此外,如果有更好的方法创建添加按钮,请让我知道。我尝试使用
UIBarButtonItem
,但我不知道如何将其视图添加到实际视图中。谢谢

到目前为止,我在我的代表中有以下内容:

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    UIButton *addButton = [[UIButton alloc] init]; //I also tried setting a frame for the
    button, but that did not seem to work, so I figured I would just leave it blank for posting       
    the question.
    addButton.titleLabel.text = @"+";
    addButton.backgroundColor = [UIColor redColor];
    [self.tableView.tableHeaderView insertSubview:addButton atIndex:0]; 
    //I feel like this is a bad idea

    return self.tableView.tableHeaderView;
}

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

问题是您的
self.tableView.tableHeaderView
此时为
nil
,因此无法使用它。所以您需要做的是,创建一个UIView,添加标题和按钮,设置它们的样式,然后返回它

这应该在你的部分标题中添加标题和按钮,你仍然需要用正确的字体和大小来设置标题的样式,但这会给你一个想法

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
    CGRect frame = tableView.frame;

    UIButton *addButton = [[UIButton alloc] initWithFrame:CGRectMake(frame.size.width-60, 10, 50, 30)];
    [addButton setTitle:@"+" forState:UIControlStateNormal];
    addButton.backgroundColor = [UIColor redColor];

    UILabel *title = [[UILabel alloc] initWithFrame:CGRectMake(10, 10, 100, 30)];
    title.text = @"Reminders";

    UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.height)];
    [headerView addSubview:title];
    [headerView addSubview:addButton];

    return headerView;
}

您可以使用下面的代码来实现这一点,您可以在header视图中放置任何类型的视图,但必须为其指定框架

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    UIView *view=[[UIView alloc]init];
    UIButton *addButton=[UIButton buttonWithType:UIButtonTypeContactAdd];
    addButton.frame=CGRectMake(250, 0, 100, 50);
    [view addSubview:addButton];
    [tblView.tableHeaderView insertSubview:view atIndex:0];
    //I feel like this is a bad idea

    return view;
}

在iOS 6中,您还可以实现

- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section
在您的
UITableViewDelegate
中。例如:

- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section {
    if (section == 0) {
        if ([view.subviews.lastObject isKindOfClass:[UIButton class]]) {
            return;
        }
        UIButton *button = [UIButtonbuttonWithType:UIButtonTypeSystem];
        button.frame = CGRectMake(view.frame.size.width - 160.0, 0, 160.0, view.frame.size.height); // x,y,width,height
        [button setTitle:@"My Button" forState:UIControlStateNormal];
        [button addTarget:self action:@selector(sectionHeaderButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
        [view addSubview:button];
    }
}

您有两个选择,都是通过
tableView.delegate
。第一个涉及到实现委托方法

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section
这使您基本上可以在自定义视图中返回所需的任何内容,该视图将用作所需部分的标题。这可以简单到

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    UIButton *addButton = [UIButton buttonWithType:UIButtonTypeContactAdd];
    [addButton addTarget:self action:@selector(SomeMethod:) forControlEvents:UIControlEventTouchUpInside];
    return addButton;
}
这将放置一个圆形信息按钮(居中)作为标题。但更可能的情况是,您希望创建一个实际的UIView对象,并用按钮(和一个分区标题标签?)填充它,并按照自己的喜好布置所有内容[请参阅其他人的答案了解如何操作]

然而,第二种方法可能更适合于简单地在(其中一个)分区标题中添加按钮的一般情况[我知道您声明了1个分区,但是很多人可能会在这个问题上想要在多分区表中执行类似操作]。这涉及到实现委托方法

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section
基本上是在事件发生后将按钮添加到标题中;具体地

- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section
{
    // Remove old button from re-used header
    if ([view.subviews.lastObject isKindOfClass:UIButton.class])
        [view.subviews.lastObject removeFromSuperview];

    if (section == MySectionNumberWithButton) {
        UIButton *addButton = [UIButton buttonWithType:UIButtonTypeContactAdd];
        [addButton addTarget:self action:@selector(SomeMethod:) forControlEvents:UIControlEventTouchUpInside];
        [view addSubview:addButton];

        // Place button on far right margin of header
        addButton.translatesAutoresizingMaskIntoConstraints = NO; // use autolayout constraints instead
        [addButton.trailingAnchor constraintEqualToAnchor:view.layoutMarginsGuide.trailingAnchor].active = YES;
        [addButton.bottomAnchor constraintEqualToAnchor:view.layoutMarginsGuide.bottomAnchor].active = YES;
    }
}
请注意,由于tableView重复使用标题,因此在多分区表中,必须确保删除先前添加的任何按钮,否则最终会在不需要的分区中出现按钮。然后,如果这是右侧部分,则将该按钮添加到现有标题中。注意,为了简洁起见,我正在使用
nslayoutachor
(iOS 9+)来布局按钮;您可以使用
NSLayoutConstraint
(iOS 6+)执行相同的操作


这种方法有一个明显的优点,即只需添加一个按钮,就不必重新创建常规布局以匹配所有其他(非按钮)标题,也不必担心旋转设备时边距会发生变化等。特别是,标题标题未被更改,将保留您为表格标题定义的所有全局外观设置(例如字体、颜色等),如果您采用
tableView:viewForHeaderInSection:
方法,则所有这些都将需要重新创建。

如果您对Swift解决方案感兴趣:

override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {

    let frame = tableView.frame

    let button = UIButton(frame: CGRectMake(5, 10, 15, 15))  // create button
    button.tag = section 
    // the button is image - set image
    button.setImage(UIImage(named: "remove_button"), forState: UIControlState.Normal)  // assumes there is an image named "remove_button"
    button.addTarget(self, action: #selector(TestController.remove(_:)), forControlEvents: .TouchUpInside)  // add selector called by clicking on the button

    let headerView = UIView(frame: CGRectMake(0, 0, frame.size.width, frame.size.height))  // create custom view
    headerView.addSubview(button)   // add the button to the view

    return headerView   
}
您可能需要在节中指定标题的高度。这必须与自定义视图的高度同步:

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

如果要使用Interface Builder构建节标题,可以使用
UITableViewCell
作为标题。在UITableView中为标题创建一个原型单元格,像其他单元格一样进行自定义,包括添加标签、按钮和约束

您可以在UITableViewController中延迟实例化:

lazy var headerCell: MyHeaderTableViewCell = {
    let cell = tableView.dequeueReusableCell(withIdentifier: "Header") as! MyHeaderTableViewCell
    return cell
}()
要使其成为标题,请执行以下操作:

override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    return headerCell
}
Swift 4:

func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {

    let frame = tableView.frame
    let button = UIButton(frame: CGRect(x: 5, y: 10, width: 15, height: 15))
    button.tag = section
    button.setImage(UIImage(named: "remove_button"), for: UIControl.State.normal)
    button.addTarget(self,action:#selector(buttonClicked),for:.touchUpInside)

    let headerView = UIView(frame: CGRect(x: 0, y: 0, width: frame.size.width, height: frame.size.height))
    headerView.addSubview(button)

    return headerView
}
此函数用于处理按钮单击:

@objc func buttonClicked(sender:UIButton)
{
    if(sender.tag == 1){

       //Do something for tag 1
    }
    print("buttonClicked")
}

出于某些原因,此代码生成正确的视图(图片),但按钮对触摸不起反应:(@AlexSorokoletov-请确保您的按钮不在其父帧之外。它不在其父帧之外,会引发TouchUpInside/TouchDownInside事件,但屏幕上没有视觉动画button@AlexSorokoletov-在这种情况下,您需要更改
突出显示的
和/或
选定的
状态的按钮样式。您能详细说明一下吗?我不是苏re我知道如何做到这一点,我将非常感谢您通过查看lastObjectGreat Response!和一篇简洁无痛的介绍
nslayoutAcho
,这是我迄今为止一直避免的。建议添加
addButton.centerYAnchor.constraint(equalTo:view.layoutMarginsGuide.centerYAnchor).isActive=true
作为替代!我喜欢这个答案。这正是我想要的。仅供参考,我需要使用:let headerView=UITableViewHeaderFooterView(frame:CGRect(x:0,y:0,width:frame.size.width,height:60))