如何在横向上调整自定义 UITableView 分隔符并防止消失

Posted

技术标签:

【中文标题】如何在横向上调整自定义 UITableView 分隔符并防止消失【英文标题】:How to resize custom UITableView separators on landscape and prevent from disappearing 【发布时间】:2014-05-22 22:45:10 【问题描述】:

我决定以编程方式创建自己的 UITableView 分隔线,因为我需要精细控制在每个 UITableViewCell 上方和/或下方显示分隔符。我的tableView 有静态单元格,所以我不在cellForRowAtIndexPath 中创建分隔符。相反,我为每个单元格设置了propertys,在viewDidLoad 中,我根据需要添加了顶部和/或底部分隔符。它正在工作,直到我旋转到横向,然后分隔线不会拉伸以填充屏幕 - 它当然保持与创建时相同的宽度。我没有看到如何自动调整它们以适应屏幕的宽度。

我尝试添加自动布局约束(前导、尾随、顶部/底部),但由于某种原因它不起作用 - 宽度没有改变,但没有记录任何错误消息以指示约束有任何问题。分隔线有时也会在滚动或旋转时消失,如果我注释掉自动布局约束,它们不会消失。

那么如何让我的自定义单元格分隔符在旋转时始终拉伸以填充设备宽度,以及如何防止它们消失?

如果以不同的方式创建我的自定义单元格分隔符会更容易/更好,我愿意这样做。我只是不知道当细胞是静态的时,除了我的方法之外如何做到这一点。我考虑在情节提要中创建视图,并以可视方式设置约束,但这不等同于我正在以编程方式执行的操作吗?如果它们是动态单元格,我会在 cellForRowAtIndexPath 中进行。

//In viewDidLoad:
[self addTopSeparatorForCell:self.myCell];

//Helper method
- (void)addTopSeparatorForCell:(UITableViewCell *)cell 
    UIView *topSeparator = [[UIView alloc] initWithFrame:CGRectMake(15, 1, cell.contentView.frame.size.width, 0.5)];

    //add CALayer to preserve line separator visibility when row is highlighted
    CALayer *backgroundColorLayer = [CALayer layer];
    backgroundColorLayer.frame = topSeparator.bounds;
    backgroundColorLayer.backgroundColor = [UIColor colorWithWhite:204/255.0f alpha:1].CGColor;

    [topSeparator.layer addSublayer:backgroundColorLayer];

    [cell.contentView addSubview:topSeparator];

    //add auto layout constraints
    topSeparator.translatesAutoresizingMaskIntoConstraints = NO;
    NSLayoutConstraint *cn = nil;
    cn = [NSLayoutConstraint constraintWithItem:topSeparator
                                      attribute:NSLayoutAttributeLeading
                                      relatedBy:NSLayoutRelationEqual
                                         toItem:cell.contentView
                                      attribute:NSLayoutAttributeLeading
                                     multiplier:1.0
                                       constant:15];
    [cell.contentView addConstraint:cn];
    cn = [NSLayoutConstraint constraintWithItem:topSeparator
                                      attribute:NSLayoutAttributeTrailing
                                      relatedBy:NSLayoutRelationEqual
                                         toItem:cell.contentView
                                      attribute:NSLayoutAttributeTrailing
                                     multiplier:1.0
                                       constant:0];
    [cell.contentView addConstraint:cn];
    cn = [NSLayoutConstraint constraintWithItem:topSeparator
                                      attribute:NSLayoutAttributeTop
                                      relatedBy:NSLayoutRelationEqual
                                         toItem:cell.contentView
                                      attribute:NSLayoutAttributeTop
                                     multiplier:1.0
                                       constant:1];
    [cell.contentView addConstraint:cn];

编辑:感谢@user1966109,我们已经能够解决线条未延伸以填充宽度的问题,现在它们在突出显示单元格时被保留。但是仍然存在一个我无法解决的问题,因为我不确定它为什么会发生。向下滚动向上滚动后,分隔线消失。它与自动布局约束有关,因为以前的解决方案有其他问题并没有表现出这个问题。这是导致线条消失的当前解决方案。如果有人知道如何防止此问题(并保留已解决的其他问题),我将不胜感激。

[self.cell addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(15@750)-[myView]-(-47@750)-|" options:0 metrics:0 views:viewsDictionary]];
[self.cell addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[myView(2)]-(-2@750)-|" options:0 metrics:0 views:viewsDictionary]];

【问题讨论】:

【参考方案1】:

您不应混合使用 initWithFrame 和自动布局。使用 Visual Format Language for Auto layout 只需几行即可获得良好的结果:

//@interface TableViewController ()
@property (weak, nonatomic) IBOutlet UITableViewCell *cell;

//@implementation TableViewController
- (void)viewDidLoad

    [super viewDidLoad];

    UIView *myView = [[UIView alloc] init];
    myView.backgroundColor = [UIColor redColor];

    [self.cell.contentView addSubview:myView];    
    myView.translatesAutoresizingMaskIntoConstraints = NO;
    NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(myView);

    [self.cell.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[myView]|" options:0 metrics:0 views:viewsDictionary]];
    [self.cell.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[myView(2)]" options:0 metrics:0 views:viewsDictionary]];

这可以完美地处理旋转。

编辑!

如果使用辅助视图,请设置以下约束:

//Set a negative value to the trailing space in order to display myView under the accessory view
//Those constraints work for both self.cell and self.cell.contentView (kind of odd)
[self.cell addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(15@750)-[myView]-(-47@750)-|" options:0 metrics:0 views:viewsDictionary]];
[self.cell addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[myView(2)]-(-2@750)-|" options:0 metrics:0 views:viewsDictionary]];

【讨论】:

谢谢你,效果很好!只有一个问题。当单元格具有附件类型(例如,披露指示器)时,分隔线将停止在该视图而不是屏幕的右边缘。我怎样才能强制它总是走到边缘?干杯。 你是对的。我没有考虑过......但是,我可以使用一个技巧来处理它(请参阅我的帖子编辑)。 谢谢,等我放假回去工作的时候试试。 :) 我注意到另一个问题,尽管很小。当您点击一个单元格时,它会突出显示,ios 会使自定义视图消失。我在我的第一个解决方案中使用CALayer 解决了这个问题,但我不能再使用它了,因为没有定义边界。您能想出一种解决方案,在使用这种新方法突出显示单元格时保留线条吗? 这是一种已知情况:当一个 UITableViewcell 被选中时,其 contentView 内所有 UIView 的 backgroundColors 都会消失。存在多种解决方案(参见here 或here)。 我已经查看了这些问题,这就是我偶然发现 CALayer 解决方法的原因。但我没有对那个单元格进行子类化。也许还有另一种不需要子类化的解决方案。【参考方案2】:

在 user1966109 的初步帮助下,我找到了可以解决所有问题并且运行良好的约束:

    [cell addConstraint:[NSLayoutConstraint constraintWithItem:imageView
                                                     attribute:NSLayoutAttributeLeading
                                                     relatedBy:NSLayoutRelationEqual
                                                        toItem:cell
                                                     attribute:NSLayoutAttributeLeading
                                                    multiplier:1.0
                                                      constant:indent]];
    [cell addConstraint:[NSLayoutConstraint constraintWithItem:imageView
                                                     attribute:NSLayoutAttributeTrailing
                                                     relatedBy:NSLayoutRelationEqual
                                                        toItem:cell
                                                     attribute:NSLayoutAttributeTrailing
                                                    multiplier:1.0
                                                      constant:0.0]];
    [cell addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[imageView(0.5)]" options:0 metrics:0 views:viewsDictionary]];

【讨论】:

以上是关于如何在横向上调整自定义 UITableView 分隔符并防止消失的主要内容,如果未能解决你的问题,请参考以下文章

如何避免在自定义容器(stackedViewcontroller)内的 UiNavigationcontroller 内调整 UITableView 的大小

如何将 UIView 调整为横向?

在自定义 UIView 中为部分自动调整 UITableView

如何在自定义 UITableView 中获取文本字段

UITableView 标题部分的高度不会为自定义 UIView() 类自动调整

具有自定义 UINavigationBar 大小的 UITableView“自动调整大小”