Overview
近期在开发中遇到一个奇葩问题:UITableViewHeaderFooterView使用autolayout时报约束异常,但显示上一切正常。经过一番排查,约束并无冲突。网上有看到说因为使用了复用才会出现这问题,这里并不是通过取消复用来解决此问题。虽问题解决,但甚是不解。望大神答疑解惑。
异常示例
上图红框部分用到了UITableViewHeaderFooterView,作为section的头,并不是UITableView的headerView。
这是初始化了UITableViewHeaderFooterView子视图的代码
- (void)initUI {
self.contentView.backgroundColor = [UIColor whiteColor];
//商家logo
self.logoImageView = [[UIImageView alloc] init];
self.logoImageView.backgroundColor = RGB_HEX(0xffffff);
self.logoImageView.layer.borderWidth = 1.f;
self.logoImageView.layer.borderColor = RGB_HEX(0xbfbfbf).CGColor;
self.logoImageView.layer.cornerRadius = 50/2.f;
self.logoImageView.clipsToBounds = YES;
[self addSubview:self.logoImageView];
//店铺名
self.storeNameLabel = [[UILabel alloc] init];
self.storeNameLabel.font = [UIFont boldSystemFontOfSize:kHeight(32)];
self.storeNameLabel.textAlignment = NSTextAlignmentCenter;
[self addSubview:self.storeNameLabel];
//套餐背景视图
self.comboImageView = [[UIImageView alloc] init];
// self.comboImageView.contentMode = UIViewContentModeScaleAspectFit;
self.comboImageView.image = [UIImage imageNamed:@"order_rectangle"];
[self addSubview:self.comboImageView];
//套餐视图
self.comboView = [[UIView alloc] init];
self.comboView.clipsToBounds = YES;
self.comboView.layer.cornerRadius = 4.f;
[self addSubview:self.comboView];
//商品图片
self.merchandiseImageView = [[UIImageView alloc] init];
self.merchandiseImageView.clipsToBounds = YES;
self.merchandiseImageView.contentMode = UIViewContentModeScaleAspectFill;
// self.merchandiseImageView.backgroundColor = [UIColor randomColor];
[self.comboView addSubview:self.merchandiseImageView];
//商品标题
self.titleLabel = [[UILabel alloc] init];
self.titleLabel.textAlignment = NSTextAlignmentCenter;
self.titleLabel.font = [UIFont boldSystemFontOfSize:kHeight(32)];
[self.comboView addSubview:self.titleLabel];
//有效期
self.expirationTimeLabel = [[UILabel alloc] init];
self.expirationTimeLabel.textAlignment = NSTextAlignmentCenter;
self.expirationTimeLabel.font = [UIFont pingFangRegularFontOfSize:kHeight(24)];
[self.comboView addSubview:self.expirationTimeLabel];
//左线条
self.leftLineView = [[UIView alloc] init];
self.leftLineView.backgroundColor = RGB_HEX(0x000000);
[self.comboView addSubview:self.leftLineView];
//右线条
self.rightLineView = [[UIView alloc] init];
self.rightLineView.backgroundColor = RGB_HEX(0x000000);
[self.comboView addSubview:self.rightLineView];
//当前砍价人数
self.currentBargainLabel = [[UILabel alloc] init];
self.currentBargainLabel.textAlignment = NSTextAlignmentCenter;
self.currentBargainLabel.font = [UIFont pingFangRegularFontOfSize:kHeight(24)];
[self.comboView addSubview:self.currentBargainLabel];
//当前价格
self.bargainPriceLabel = [[UILabel alloc] init];
self.bargainPriceLabel.textColor = RGB_HEX(0xb4282d);
self.bargainPriceLabel.font = [UIFont pingFangMediumFontOfSize:kHeight(26)];
[self addSubview:self.bargainPriceLabel];
//进度条倒三角
self.progressTriangleImageView = [[UIImageView alloc] init];
// self.progressTriangleImageView.image = [UIImage imageNamed:@"order_progress_triangle"];
[self addSubview:self.progressTriangleImageView];
//进度条
//左右轨的图片
UIImage *stetchLeftTrack= [UIImage imageNamed:@"brightness_bar"];
UIImage *stetchRightTrack = [UIImage imageNamed:@"brightness_bar_bg"];
//滑块图片
UIImage *thumbImage = [UIImage imageNamed:@"order_progress_round"];
self.slider = [[UISlider alloc] init];
self.slider.userInteractionEnabled = NO;
// self.slider.enabled = NO; //禁止滑动
[self.slider setMinimumTrackImage:stetchLeftTrack forState:UIControlStateNormal];
[self.slider setMaximumTrackImage:stetchRightTrack forState:UIControlStateNormal];
//注意这里要加UIControlStateHightlighted的状态,否则当拖动滑块时滑块将变成原生的控件
[self.slider setThumbImage:thumbImage forState:UIControlStateHighlighted];
[self.slider setThumbImage:thumbImage forState:UIControlStateNormal];
[self addSubview:self.slider];
//优选价
self.originalPriceLabel = [[UILabel alloc] init];
self.originalPriceLabel.numberOfLines = 2;
self.originalPriceLabel.textAlignment = NSTextAlignmentCenter;
self.originalPriceLabel.font = [UIFont pingFangRegularFontOfSize:kHeight(26)];
[self addSubview:self.originalPriceLabel];
//最惠价
self.preferentialPriceLabel = [[UILabel alloc] init];
self.preferentialPriceLabel.numberOfLines = 2;
self.preferentialPriceLabel.textAlignment = NSTextAlignmentCenter;
self.preferentialPriceLabel.font = [UIFont pingFangRegularFontOfSize:kHeight(26)];
[self addSubview:self.preferentialPriceLabel];
//底部分割线
self.bottomLineView = [[UIView alloc] init];
self.bottomLineView.backgroundColor = RGB_HEX(0xF2F2F2);
[self addSubview:self.bottomLineView];
//砍价人数
self.bargainNumLabel = [[UILabel alloc] init];
self.bargainNumLabel.font = [UIFont pingFangMediumFontOfSize:kHeight(30)];
[self addSubview:self.bargainNumLabel];
//约束
//头像
[self.logoImageView makeConstraints:^(MASConstraintMaker *make) {
make.centerX.equalTo(self);
make.top.equalTo(self).offset(kHeight(30));
make.width.height.equalTo(50);
}];
//店铺名
[self.storeNameLabel makeConstraints:^(MASConstraintMaker *make) {
make.left.right.equalTo(self);
make.top.equalTo(self.logoImageView.bottom).offset(kHeight(26));
}];
//套餐视图
[self.comboView makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.storeNameLabel.bottom).offset(kHeight(34));
make.left.equalTo(self).offset(kWidth(52));
make.right.equalTo(self).offset(-kWidth(52));
make.height.equalTo(kHeight(586));
}];
//套餐背景视图
[self.comboImageView makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.comboView).offset(-kHeight(10));
make.left.equalTo(self.comboView).offset(-kWidth(16));
make.right.equalTo(self.comboView).offset(kWidth(16));
make.bottom.equalTo(self.comboView).offset(kHeight(10));
}];
//商品图片
[self.merchandiseImageView makeConstraints:^(MASConstraintMaker *make) {
make.top.left.right.equalTo(self.comboView);
make.height.equalTo(kHeight(308));
}];
//标题
[self.titleLabel makeConstraints:^(MASConstraintMaker *make) {
make.left.right.equalTo(self.comboView);
make.top.equalTo(self.merchandiseImageView.bottom).offset(kHeight(46));
}];
//截止日期
[self.expirationTimeLabel makeConstraints:^(MASConstraintMaker *make) {
make.centerX.equalTo(self.titleLabel);
make.top.equalTo(self.titleLabel.bottom).offset(kHeight(26));
}];
//左线条
[self.leftLineView makeConstraints:^(MASConstraintMaker *make) {
make.right.equalTo(self.expirationTimeLabel.left).offset(-kWidth(28));
make.centerY.equalTo(self.expirationTimeLabel);
make.width.equalTo(kWidth(20));
make.height.equalTo(1);
}];
//右线条
[self.rightLineView makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.expirationTimeLabel.right).offset(14);
make.centerY.equalTo(self.expirationTimeLabel);
make.width.equalTo(kWidth(20));
make.height.equalTo(1);
}];
//当前参与砍价人数
[self.currentBargainLabel makeConstraints:^(MASConstraintMaker *make) {
make.left.right.equalTo(self);
make.top.equalTo(self.expirationTimeLabel.bottom).offset(kHeight(30));
}];
//进度条
[self.slider makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.comboView.bottom).offset(kHeight(110));
make.left.equalTo(self).offset(kWidth(50));
make.right.equalTo(self).offset(-kWidth(50));
make.height.equalTo(3);
}];
//倒三角
[self.progressTriangleImageView makeConstraints:^(MASConstraintMaker *make) {
make.bottom.equalTo(self.slider.top).equalTo(-kHeight(16));
make.left.equalTo(self.slider.left);
}];
//当前价格
[self.bargainPriceLabel makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.slider.left);
make.bottom.equalTo(self.progressTriangleImageView.top).offset(-kHeight(10));
}];
//优选价
[self.originalPriceLabel makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.slider);
make.top.equalTo(self.slider.bottom).offset(kHeight(16));
}];
//最惠价
[self.preferentialPriceLabel makeConstraints:^(MASConstraintMaker *make) {
make.right.equalTo(self.slider);
make.top.equalTo(self.slider.bottom).offset(kHeight(16));
}];
//底部分割线
[self.bottomLineView makeConstraints:^(MASConstraintMaker *make) {
make.left.right.equalTo(self);
make.top.equalTo(self.preferentialPriceLabel.bottom).offset(kHeight(70));
make.height.equalTo(kHeight(20));
}];
//砍价好友
[self.bargainNumLabel makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self).offset(kWidth(30));
make.right.equalTo(self).offset(-kWidth(30));
make.top.equalTo(self.bottomLineView.bottom).offset(kHeight(30));
make.bottom.equalTo(self);
}];
}
这是初始化UITableView的代码
- (void)initUI {
self.title = @"砍价";
self.view.backgroundColor = [UIColor whiteColor];
self.table = [UITableView customTableViewWithFrame:CGRectZero
style:UITableViewStyleGrouped
separatorColor:[UIColor clearColor]
estimatedSectionHeaderHeight:UITableViewAutomaticDimension
estimatedSectionFooterHeight:UITableViewAutomaticDimension];
self.table.hidden = YES;
self.table.backgroundColor = [UIColor whiteColor];
self.table.showsVerticalScrollIndicator = NO;
self.table.showsHorizontalScrollIndicator = NO;
self.table.delegate = self;
self.table.dataSource = self;
[self.table registerClass:[VCBargainHeaderView class] forHeaderFooterViewReuseIdentifier:@"VCBargainHeaderView"];
[self.table registerClass:[VCBargainFriendsCell class] forCellReuseIdentifier:@"VCBargainFriendsCell"];
[self.view addSubview:self.table];
//底部视图
self.bottomView = [[UIView alloc] init];
self.bottomView.backgroundColor = [UIColor whiteColor];
self.bottomView.hidden = YES;
[self.view addSubview:self.bottomView];
//分享按钮
self.shareBargainBtn = [[UIButton alloc] init];
self.shareBargainBtn.layer.cornerRadius = 4.f;
self.shareBargainBtn.titleLabel.font = [UIFont pingFangRegularFontOfSize:kHeight(30)];
self.shareBargainBtn.backgroundColor = RGB_HEX(0xcc5253);
[self.shareBargainBtn setTitle:@"分享砍价" forState:UIControlStateNormal];
[self.bottomView addSubview:self.shareBargainBtn];
//立即使用
self.useBtn = [[UIButton alloc] init];
self.useBtn.layer.cornerRadius = 4.f;
self.useBtn.layer.borderColor = RGB_HEX(0xb4282d).CGColor;
self.useBtn.layer.borderWidth = 1.f;
self.useBtn.titleLabel.font = [UIFont pingFangRegularFontOfSize:kHeight(30)];
[self.useBtn setTitle:@"立即使用" forState:UIControlStateNormal];
[self.useBtn setTitleColor:RGB_HEX(0xb4282d) forState:UIControlStateNormal];
[self.bottomView addSubview:self.useBtn];
//约束
[self.bottomView makeConstraints:^(MASConstraintMaker *make) {
if (@available(iOS 11.0, *)) {
make.left.equalTo(self.view.safeAreaLayoutGuideLeft).offset(0);
make.right.equalTo(self.view.safeAreaLayoutGuideRight).offset(0);
make.bottom.equalTo(self.view.safeAreaLayoutGuideBottom).offset(0);
} else {
// Fallback on earlier versions
make.left.right.bottom.equalTo(self.view);
}
make.height.equalTo(73);
}];
[self.table makeConstraints:^(MASConstraintMaker *make) {
if (@available(iOS 11.0, *)) {
make.left.equalTo(self.view.safeAreaLayoutGuideLeft).offset(0);
make.right.equalTo(self.view.safeAreaLayoutGuideRight).offset(0);
make.top.equalTo(self.view.safeAreaLayoutGuideTop).offset(0);
} else {
// Fallback on earlier versions
make.left.right.top.equalTo(self.view);
}
make.bottom.equalTo(self.bottomView.top).offset(0);
}];
}
UITableViewHeaderFooterView代码
static NSString * headerViewStr = @"VCBargainHeaderView";
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
VCBargainHeaderView * bargainHeaderView = [tableView dequeueReusableHeaderFooterViewWithIdentifier:headerViewStr];
if (bargainHeaderView == nil) {
bargainHeaderView = (VCBargainHeaderView *)[[UITableViewHeaderFooterView alloc] initWithReuseIdentifier:headerViewStr];
}
[bargainHeaderView setModel:self.viewModel.couponItem];
//砍价人数
bargainHeaderView.bargainNumLabel.text = [NSString stringWithFormat:@"砍价好友(%d)",self.viewModel.cutPriceList.count];
return bargainHeaderView;
}
解决办法
解决方法1:
找到与UITableViewHeaderFooterView底部有约束的控件将他与底部的约束优先级改低。如上图(正常代码)所示 即可解决问题
2、解决方法2(网上看到的,亲测无效):
使用UITableView的header或footer复用时,如果采用自动布局,你会发现有约束冲突,下面这样写可以消除约束冲突:
#import
@interface SectionView : UITableViewHeaderFooterView
@property (nonatomic, copy) NSString *sectionTitle;
@end
####import "SectionView.h"
@interface SectionView ()
{
UIImageView *titleBgImageView;
UIImageView *timePonitImageView;
UIImageView *circleImageView;
UILabel *titleLabe;
}
@end
@implementation SectionView
// 带有复用
- (instancetype)initWithReuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithReuseIdentifier:reuseIdentifier];
if (self) {
[self createUI];
}
return self;
}
- (void)createUI
{
titleBgImageView = [[UIImageView alloc] initForAutoLayout];
titleBgImageView.userInteractionEnabled = NO;
UIImage *image = [UIImage imageNamed:@"event_bottom_line"];
image = [image stretchableImageWithLeftCapWidth:image.size.width*0.5 topCapHeight:image.size.height*0.5];
titleBgImageView.image = image;
[self.contentView addSubview:titleBgImageView];
circleImageView = [[UIImageView alloc] initForAutoLayout];
UIImage *circleImage = [UIImage imageNamed:@"event_blue1"];
circleImage = [circleImage stretchableImageWithLeftCapWidth:circleImage.size.width*0.5 topCapHeight:circleImage.size.height*0.5];
circleImageView.image = circleImage;
[self.contentView addSubview:circleImageView];
timePonitImageView = [[UIImageView alloc] initForAutoLayout];
timePonitImageView.image = [UIImage imageNamed:@"event_write_line"];
[self.contentView addSubview:timePonitImageView];
titleLabe = [[UILabel alloc] initForAutoLayout];
titleLabe.font = [UIFont systemFontOfSize:13];
titleLabe.textColor = [UIColor whiteColor];
titleLabe.textAlignment = NSTextAlignmentCenter;
[circleImageView addSubview:titleLabe];
}
把布局代码写到这里
- (void)layoutSubviews
{
[super layoutSubviews];
[titleBgImageView autoPinEdgesToSuperviewEdgesWithInsets:UIEdgeInsetsMake(0, 0, 0, 0)];
[circleImageView autoPinEdgeToSuperviewEdge:ALEdgeLeading withInset:8];
[circleImageView autoPinEdgeToSuperviewEdge:ALEdgeTrailing withInset:8];
[circleImageView autoSetDimension:ALDimensionHeight toSize:23];
[circleImageView autoAlignAxisToSuperviewAxis:ALAxisHorizontal];
[timePonitImageView autoPinEdgeToSuperviewEdge:ALEdgeLeading withInset:16];
[timePonitImageView autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:39/2.0-4];
[timePonitImageView autoSetDimensionsToSize:CGSizeMake(9, 23.5)];
[titleLabe autoCenterInSuperview];
[titleLabe autoSetDimension:ALDimensionWidth toSize:200];
}
该代码来自csdn用户王素燕的博客《UITableViewHeaderFooterView的使用+自动布局》。侵删!
文章有(1)条网友点评
因为你设置的约束和cell自己算的约束冲突了 必须以一个为主 你可以把你的优先级设高也可以 你优先级设置高 cell自己就不算了 以你的约束为主了