我在做一个类似于微信朋友圈一样的,复杂的 UITableViewCell
在 UITableViewCell 的init(style: UITableViewCellStyle, reuseIdentifier: String?)里,我先创建好所有要用的控制,比如头像、昵称、内容、图片的容器等。
然后通过一个 setModal 的方法去设置每个 cell 不同的数据, setModal 会在 cellForRowAt 里调用,
而 setModal 里会根据图片的情况显示或隐藏图片的容器。同时更新所有相关视图 AutoLayout 的 top
内容有些只有图片,有些只有文字内容,而有些同时拥有文字跟图片,开始的一屏没问题,往下滚动后,新出来的 cell 也没什么问题,
但当重新往上滚的时候,重新出来的上面的 cell 布局乱了。
我用的是 SnapKit ,乱了布局的 cell 报了Unable to simultaneously satisfy constraints的错。
我检查了我的代码,在 setModal 里,如果有要显示的内容,我就新 makeConstraints ,而一般都是新加一个 top 的约束,如果不需要显示,就把缓存了的 top 约束 deactivate ,并 isHidden=true 掉。
所以我在怀疑,是不是 UITableViewCell 的重用问题, UITableViewCell 的重用不是拿缓存里的 cell 来用的吗?
如果一个 cell 我先用过了,并设置了图片、文字的视图是显示状态的,下一次被调用的时候,他们应该也是显示的,
所以我需要根据内容再做一次显示 /隐藏的动作。那文字呢?我的内容是通过 attributedText 设置的,第一次加载 的时候是正确的,但先往下滚,再往上滚的时候,就不对了,文字的框明显就高了,所以原来对的约束逻辑,就会被“尝试打破约束”这样的错。是不是有什么办法能让显示内容的 label 高度也刷新一下?
而且我还作了另一种尝试,就是把可能会发生隐藏或显示的视图的约束,在setModal里全部重新做一遍, 就是根据数据,如果这个视图是隐藏的,我就直接removeConstraints,下次如果显示,我也先removeConstraints 然后再makeConstraints 把全部约束重新加一遍,显示是对了,但还是会报“尝试打破约束”的打,不知道到底是哪不对
import UIKit
import SnapKit
class CircleCell: UITableViewCell {
var avatar : UIView!;
var nickname : UILabel!;
var downArrow : UILabel!;
var timeLabel : UILabel!;
var contentLabel : UILabel!;
var likeBtn : UIButton!;
var commentBtn : UIButton!;
var expandLabel : UILabel!;
var imageBox : ImageCell!;
var pageBox : PageCell!;
var contentTopConstraint : Constraint?;
var expandTopConstriaint : Constraint?;
var imageBoxTopConstrint : Constraint?;
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier);
self.selectionStyle = .none;
self.setUp();
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
fileprivate func setUp(){
self.contentView.layer.shouldRasterize = true;
self.contentView.isOpaque = true;
self.layer.shouldRasterize = true;
self.isOpaque = true;
avatar = UIView();
avatar.isUserInteractionEnabled = true;
avatar.backgroundColor = .red;
nickname = UILabel();
nickname.sizeToFit();
nickname.numberOfLines = 1;
nickname.font = UIFont.boldSystemFont(ofSize: Dimens.COMMON_FONT_SIZE);
nickname.textColor = Colors.MainYellow;
expandLabel = UILabel();
expandLabel.sizeToFit();
expandLabel.numberOfLines = 1;
expandLabel.textColor = Colors.MainYellow;
expandLabel.isUserInteractionEnabled = true;
expandLabel.font = UIFont.systemFont(ofSize: Dimens.COMMON_FONT_SIZE);
contentLabel = UILabel();
contentLabel.numberOfLines = 0;
contentLabel.font = UIFont.systemFont(ofSize: Dimens.COMMON_FONT_SIZE);
contentLabel.textColor = Colors.MAIN_BLACK;
contentLabel.backgroundColor = .brown;
downArrow = UILabel();
downArrow.sizeToFit();
downArrow.textAlignment = .right;
let arrowStr = FontAwesome.icon("fa-angle-down");
let arrowAttribute = NSMutableAttributedString(string: arrowStr);
let arrowFont = UIFont(name: Fonts.FontAwesome, size: Dimens.MATERIAL_ICON_SIZE);
arrowAttribute.addAttribute(NSFontAttributeName, value: arrowFont!, range: NSMakeRange(0, 1));
arrowAttribute.addAttribute(NSForegroundColorAttributeName, value: Colors.COLOR9ea1ab, range: NSMakeRange(0, 1));
downArrow.attributedText = arrowAttribute;
downArrow.isUserInteractionEnabled = true;
timeLabel = UILabel();
timeLabel.sizeToFit();
timeLabel.numberOfLines = 1;
timeLabel.font = UIFont.systemFont(ofSize: Dimens.SECOND_TITLE_FONT_SIZE);
timeLabel.textColor = Colors.COLOR9ea1ab;
timeLabel.backgroundColor = .yellow;
imageBox = ImageCell();
pageBox = PageCell();
likeBtn = UIButton();
likeBtn.contentEdgeInsets = UIEdgeInsetsMake(0.01, 0, 0.01, 0);
commentBtn = UIButton();
commentBtn.contentEdgeInsets = UIEdgeInsetsMake(0.01, 0, 0.01, 0);
self.contentView.addSubview(self.avatar);
self.contentView.addSubview(self.nickname);
self.contentView.addSubview(self.downArrow);
self.contentView.addSubview(self.timeLabel);
self.contentView.addSubview(self.commentBtn);
self.contentView.addSubview(self.likeBtn);
self.contentView.addSubview(self.contentLabel);
self.contentView.addSubview(self.expandLabel);
self.contentView.addSubview(self.imageBox);
self.contentView.addSubview(self.pageBox);
layout();
}
fileprivate func layout(){
self.avatar.snp.makeConstraints { [unowned self](make) in
make.left.top.equalTo(self.contentView).offset(10);
make.width.height.equalTo(40);
}
self.downArrow.snp.makeConstraints { [unowned self](make) in
make.right.equalTo(self.contentView).offset(-10);
make.centerY.equalTo(self.nickname);
make.width.equalTo(40);
make.height.equalTo(self.nickname).offset(10);
}
self.nickname.snp.makeConstraints { [unowned self](make) in
make.left.equalTo(self.avatar.snp.right).offset(10);
make.top.equalTo(self.avatar);
}
self.contentLabel.snp.makeConstraints{ [unowned self](make) in
make.left.equalTo(self.nickname);
make.right.equalTo(self.contentView).offset(-10);
}
self.expandLabel.snp.makeConstraints{ [unowned self](make) in
make.left.equalTo(self.contentLabel);
}
self.imageBox.snp.makeConstraints{ [unowned self](make) in
make.left.equalTo(self.contentLabel);
make.right.equalTo(self.contentView);
}
self.pageBox.snp.makeConstraints{ [unowned self](make) in
make.left.equalTo(self.imageBox);
make.right.equalTo(self.contentView).offset(-10);
}
self.timeLabel.snp.makeConstraints { [unowned self](make) in
make.left.equalTo(self.nickname);
make.bottom.equalTo(self.contentView).offset(-10);
}
self.commentBtn.snp.makeConstraints { [unowned self](make) in
make.right.equalTo(self.contentView).offset(-10);
make.centerY.equalTo(self.timeLabel);
}
self.likeBtn.snp.makeConstraints { [unowned self](make) in
make.right.equalTo(self.commentBtn.snp.left).offset(-10);
make.centerY.equalTo(self.timeLabel);
}
}
func setModel(data: PostStatus, sizeCache: SizeCache){
//set up avatar
self.nickname.text = data.user!.nickname;
let content = data.content;
var showExpand = false;
var hasContent = false;
var hasImage = false;
var hasPage = false;
if content != "" {
hasContent = true;
self.contentLabel.isHidden = false;
var lines = sizeCache.visibleLines;
if sizeCache.totalLines <= 12 {
lines = sizeCache.totalLines;
}else{
showExpand = true;
}
self.contentLabel.text = content;
self.contentLabel.numberOfLines = lines;
self.contentLabel.snp.makeConstraints({ [unowned self](make) in
self.contentTopConstraint = make.top.equalTo(self.nickname.snp.bottom).offset(10).constraint;
});
if showExpand {
self.expandLabel.isHidden = false;
self.expandLabel.text = "展开";
self.expandLabel.snp.makeConstraints{ [unowned self](make) in
self.expandTopConstriaint = make.top.equalTo(self.contentLabel.snp.bottom).offset(10).constraint;
}
}else{
self.expandLabel.isHidden = true;
self.expandTopConstriaint?.deactivate();
}
}else{
self.contentTopConstraint?.deactivate();
self.contentLabel.isHidden = true;
self.expandTopConstriaint?.deactivate();
self.expandLabel.isHidden = true;
}
let arr = [UIImage](repeating: UIImage(), count: data.images.count);
self.imageBox.update(images: arr);
if data.images.count > 0 {
hasImage = true;
self.imageBox.isHidden = false;
if hasContent {
if showExpand {
self.imageBox.snp.makeConstraints({ [unowned self](make) in
self.imageBoxTopConstrint = make.top.equalTo(self.expandLabel.snp.bottom).offset(10).constraint;
});
}else{
self.imageBox.snp.makeConstraints({ [unowned self](make) in
self.imageBoxTopConstrint = make.top.equalTo(self.contentLabel.snp.bottom).offset(10).constraint;
});
}
}else{
self.imageBox.snp.makeConstraints({ [unowned self](make) in
self.imageBoxTopConstrint = make.top.equalTo(self.nickname.snp.bottom).offset(10).constraint;
});
}
}else{
self.imageBoxTopConstrint?.deactivate();
self.imageBox.isHidden = true;
}
if let _ = data.game {
hasPage = true;
self.pageBox.snp.makeConstraints({ (make) in
make.height.equalTo(70);
});
if hasImage {
self.pageBox.snp.makeConstraints({ [unowned self](make) in
make.top.equalTo(self.imageBox.snp.bottom).offset(10);
});
}else{
if hasContent {
if showExpand {
self.pageBox.snp.makeConstraints({ [unowned self](make) in
make.top.equalTo(self.expandLabel.snp.bottom).offset(10);
});
}else{
self.pageBox.snp.makeConstraints({ [unowned self](make) in
make.top.equalTo(self.contentLabel.snp.bottom).offset(10);
});
}
}else{
self.pageBox.snp.makeConstraints({ [unowned self](make) in
make.top.equalTo(self.nickname.snp.bottom).offset(10);
});
}
}
}else{
//TODO: clear content
}
self.timeLabel.text = Time.sinceNow(data.created_at!);
if hasPage {
self.timeLabel.snp.makeConstraints({ [unowned self](make) in
make.top.equalTo(self.pageBox.snp.bottom).offset(10);
});
}else{
if hasImage {
self.timeLabel.snp.makeConstraints({ [unowned self](make) in
make.top.equalTo(self.imageBox.snp.bottom).offset(10);
});
}else{
if hasContent {
if showExpand {
self.timeLabel.snp.makeConstraints({ [unowned self](make) in
make.top.equalTo(self.expandLabel.snp.bottom).offset(10);
});
}else{
self.timeLabel.snp.makeConstraints({ [unowned self](make) in
make.top.equalTo(self.contentLabel.snp.bottom).offset(10);
});
}
}
}
}
let likeStr = FontAwesome.icon("fa-thumbs-o-up");
let likeAttribute = NSMutableAttributedString(string: "\(likeStr) 0");
let likeFont = UIFont(name: Fonts.FontAwesome, size: Dimens.COMMON_TITLE_FONT_SIZE);
let commonFont = UIFont.systemFont(ofSize: Dimens.COMMON_TITLE_FONT_SIZE);
var numStr = "\(data.like_num)";
var numNum = numStr.characters.count;
likeAttribute.addAttribute(NSFontAttributeName, value: likeFont!, range: NSMakeRange(0, 1));
likeAttribute.addAttribute(NSFontAttributeName, value: commonFont, range: NSMakeRange(1, numNum + 1));
likeAttribute.addAttribute(NSForegroundColorAttributeName, value: Colors.COLOR9ea1ab, range: NSMakeRange(0, numNum + 2));
let likeHighlightedAttribute = NSMutableAttributedString(string: "\(likeStr) 0");
likeHighlightedAttribute.addAttribute(NSFontAttributeName, value: likeFont!, range: NSMakeRange(0, 1));
likeHighlightedAttribute.addAttribute(NSFontAttributeName, value: commonFont, range: NSMakeRange(1, numNum + 1));
likeHighlightedAttribute.addAttribute(NSForegroundColorAttributeName, value: Colors.COLOReeeeee, range: NSMakeRange(0, numNum + 2));
likeBtn.setAttributedTitle(likeAttribute, for: UIControlState());
likeBtn.setAttributedTitle(likeHighlightedAttribute, for: .highlighted);
let commentStr = FontAwesome.icon("fa-commenting-o");
let commentAttribute = NSMutableAttributedString(string: "\(commentStr) 0");
let commentFont = UIFont(name: Fonts.FontAwesome, size: Dimens.COMMON_TITLE_FONT_SIZE);
numStr = "\(data.comment_num)";
numNum = numStr.characters.count;
commentAttribute.addAttribute(NSFontAttributeName, value: commentFont!, range: NSMakeRange(0, 1));
commentAttribute.addAttribute(NSFontAttributeName, value: commentFont!, range: NSMakeRange(1, numNum + 1));
commentAttribute.addAttribute(NSForegroundColorAttributeName, value: Colors.COLOR9ea1ab, range: NSMakeRange(0, numNum + 2));
commentAttribute.addAttribute(NSBaselineOffsetAttributeName, value: 1, range: NSMakeRange(0, 1));
let commentHighlightedAttribute = NSMutableAttributedString(string: "\(commentStr) 0");
commentHighlightedAttribute.addAttribute(NSFontAttributeName, value: commentFont!, range: NSMakeRange(0, 1));
commentHighlightedAttribute.addAttribute(NSFontAttributeName, value: commentFont!, range: NSMakeRange(1, numNum + 1));
commentHighlightedAttribute.addAttribute(NSForegroundColorAttributeName, value: Colors.COLOReeeeee, range: NSMakeRange(0, numNum + 2));
commentHighlightedAttribute.addAttribute(NSBaselineOffsetAttributeName, value: 1, range: NSMakeRange(0, 1));
commentBtn.setAttributedTitle(commentAttribute, for: UIControlState());
commentBtn.setAttributedTitle(commentHighlightedAttribute, for: .highlighted);
}
deinit {
Log.verbose("\(type(of: self)) deinit");
}
}
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.