【发布时间】:2015-03-14 14:49:20
【问题描述】:
我正在学习 Objective C 并正在为课堂作业制作 Instagram 克隆。目前我有自动布局的问题。具体来说,图像和 cmets 相互重叠:
我认为问题出在自动布局上:
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
self.mediaImageView = [[UIImageView alloc] init];
self.usernameAndCaptionLabel = [[UILabel alloc] init];
self.usernameAndCaptionLabel.numberOfLines = 0;
self.commentLabel = [[UILabel alloc] init];
self.commentLabel.numberOfLines = 0;
for (UIView *view in @[self.mediaImageView, self.usernameAndCaptionLabel, self.commentLabel]) {
[self.contentView addSubview:view];
view.translatesAutoresizingMaskIntoConstraints = NO;
}
NSDictionary *viewDictionary = NSDictionaryOfVariableBindings(_mediaImageView, _usernameAndCaptionLabel, _commentLabel);
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_mediaImageView]|" options:kNilOptions metrics:nil views:viewDictionary]];
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_usernameAndCaptionLabel]|" options:kNilOptions metrics:nil views:viewDictionary]];
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_commentLabel]|" options:kNilOptions metrics:nil views:viewDictionary]];
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_mediaImageView][_usernameAndCaptionLabel][_commentLabel]"
options:kNilOptions
metrics:nil
views:viewDictionary]];
self.imageHeightConstraint = [NSLayoutConstraint constraintWithItem:_mediaImageView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1
constant:100];
self.usernameAndCaptionLabelHeightConstraint = [NSLayoutConstraint constraintWithItem:_usernameAndCaptionLabel
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1
constant:100];
self.commentLabelHeightConstraint = [NSLayoutConstraint constraintWithItem:_commentLabel
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1
constant:100];
[self.contentView addConstraints:@[self.imageHeightConstraint, self.usernameAndCaptionLabelHeightConstraint, self.commentLabelHeightConstraint]]; }
return self;
}
我已经多次阅读课堂教程并研究了iOS SDK Table Cell Overlapping但未能找到合适的答案。
这是完整的代码:
#import "AppDelegate.h"
#import "UITableViewCell+BLCMediaTableViewCell.h"
#import "NSObject+BLCMedia.h"
#import "NSObject+BLCComment.h"
#import "NSObject+BLCUser.h"
//@implementation UITableViewCell (BLCMediaTableViewCell)
@interface BLCMediaTableViewCell() {
BLCMedia* _mediaItem;
}
@property (nonatomic, strong) UIImageView *mediaImageView;
@property (nonatomic, strong) UILabel *usernameAndCaptionLabel;
@property (nonatomic, strong) UILabel *commentLabel;
// Assignment: Added auto layout
@property (nonatomic, strong) NSLayoutConstraint *imageHeightConstraint;
@property (nonatomic, strong) NSLayoutConstraint *usernameAndCaptionLabelHeightConstraint;
@property (nonatomic, strong) NSLayoutConstraint *commentLabelHeightConstraint;
@end
static UIFont *lightFont;
static UIFont *boldFont;
static UIColor *usernameLabelGray;
static UIColor *commentLabelGray;
static UIColor *linkColor;
static NSParagraphStyle *paragraphStyle;
@implementation BLCMediaTableViewCell : UITableViewCell
- (void) layoutSubviews
{
[super layoutSubviews];
// Before layout, calculate the intrinsic size of the labels (the size they "want" to be), and add 20 to the height for some vertical padding.
self.imageView.contentMode = UIViewContentModeScaleAspectFill;
self.imageView.frame = CGRectMake(self.imageView.frame.origin.x, self.imageView.frame.origin.y, 100, 100);
CGSize maxSize = CGSizeMake(CGRectGetWidth(self.bounds), CGFLOAT_MAX);
CGSize usernameLabelSize = [self.usernameAndCaptionLabel sizeThatFits:maxSize];
CGSize commentLabelSize = [self.commentLabel sizeThatFits:maxSize];
self.usernameAndCaptionLabelHeightConstraint.constant = usernameLabelSize.height + 20;
self.commentLabelHeightConstraint.constant = commentLabelSize.height + 20;
// Hide the line between cells
self.separatorInset = UIEdgeInsetsMake(0, 0, 0, CGRectGetWidth(self.bounds));
}
+ (void)load {
lightFont = [UIFont fontWithName:@"HelveticaNeue-Thin" size:11];
boldFont = [UIFont fontWithName:@"HelveticaNeue-Bold" size:11];
usernameLabelGray = [UIColor colorWithRed:0.933 green:0.933 blue:0.933 alpha:1]; /*#eeeeee*/
commentLabelGray = [UIColor colorWithRed:0.898 green:0.898 blue:0.898 alpha:1]; /*#e5e5e5*/
linkColor = [UIColor colorWithRed:0.345 green:0.314 blue:0.427 alpha:1]; /*#58506d*/
NSMutableParagraphStyle *mutableParagraphStyle = [[NSMutableParagraphStyle alloc] init];
mutableParagraphStyle.headIndent = 20.0;
mutableParagraphStyle.firstLineHeadIndent = 20.0;
mutableParagraphStyle.tailIndent = -20.0;
mutableParagraphStyle.paragraphSpacingBefore = 5;
paragraphStyle = mutableParagraphStyle;
}
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
self.mediaImageView = [[UIImageView alloc] init];
self.usernameAndCaptionLabel = [[UILabel alloc] init];
self.usernameAndCaptionLabel.numberOfLines = 0;
self.commentLabel = [[UILabel alloc] init];
self.commentLabel.numberOfLines = 0;
for (UIView *view in @[self.mediaImageView, self.usernameAndCaptionLabel, self.commentLabel]) {
[self.contentView addSubview:view];
view.translatesAutoresizingMaskIntoConstraints = NO;
}
NSDictionary *viewDictionary = NSDictionaryOfVariableBindings(_mediaImageView, _usernameAndCaptionLabel, _commentLabel);
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_mediaImageView]|" options:kNilOptions metrics:nil views:viewDictionary]];
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_usernameAndCaptionLabel]|" options:kNilOptions metrics:nil views:viewDictionary]];
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_commentLabel]|" options:kNilOptions metrics:nil views:viewDictionary]];
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_mediaImageView][_usernameAndCaptionLabel][_commentLabel]"
options:kNilOptions
metrics:nil
views:viewDictionary]];
self.imageHeightConstraint = [NSLayoutConstraint constraintWithItem:_mediaImageView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1
constant:100];
self.usernameAndCaptionLabelHeightConstraint = [NSLayoutConstraint constraintWithItem:_usernameAndCaptionLabel
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1
constant:100];
self.commentLabelHeightConstraint = [NSLayoutConstraint constraintWithItem:_commentLabel
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1
constant:100];
[self.contentView addConstraints:@[self.imageHeightConstraint, self.usernameAndCaptionLabelHeightConstraint, self.commentLabelHeightConstraint]]; }
return self;
}
- (NSAttributedString *) usernameAndCaptionString {
CGFloat usernameFontSize = 15;
// Make a string that says "username caption text"
NSString *baseString = [NSString stringWithFormat:@"%@ %@", self.mediaItem.user.userName, self.mediaItem.caption];
// Make an attributed string, with the "username" bold
NSMutableAttributedString *mutableUsernameAndCaptionString = [[NSMutableAttributedString alloc] initWithString:baseString attributes:@{NSFontAttributeName : [lightFont fontWithSize:usernameFontSize], NSParagraphStyleAttributeName : paragraphStyle}];
NSRange usernameRange = [baseString rangeOfString:self.mediaItem.user.userName];
[mutableUsernameAndCaptionString addAttribute:NSFontAttributeName value:[boldFont fontWithSize:usernameFontSize] range:usernameRange];
[mutableUsernameAndCaptionString addAttribute:NSForegroundColorAttributeName value:linkColor range:usernameRange];
return mutableUsernameAndCaptionString;
}
- (void) setMediaItem:(BLCMedia *)mediaItem {
_mediaItem = mediaItem;
self.mediaImageView.image = _mediaItem.image;
self.usernameAndCaptionLabel.attributedText = [self usernameAndCaptionString];
self.commentLabel.attributedText = [self commentString];
self.imageHeightConstraint.constant = self.mediaItem.image.size.height / self.mediaItem.image.size.width * CGRectGetWidth(self.contentView.bounds);
}
//Added
- (CGSize) sizeOfString:(NSAttributedString *)string {
CGSize maxSize = CGSizeMake(CGRectGetWidth(self.contentView.bounds) - 40, 0.0);
CGRect sizeRect = [string boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin context:nil];
sizeRect.size.height += 20;
sizeRect = CGRectIntegral(sizeRect);
return sizeRect.size;
}
- (NSAttributedString *) commentString {
NSMutableAttributedString *commentString = [[NSMutableAttributedString alloc] init];
for (BLCComment *comment in self.mediaItem.comments) {
// Make a string that says "username comment text" followed by a line break
NSString *baseString = [NSString stringWithFormat:@"%@ %@\n", comment.from.userName, comment.text];
// Make an attributed string, with the "username" bold
NSMutableAttributedString *oneCommentString = [[NSMutableAttributedString alloc] initWithString:baseString attributes:@{NSFontAttributeName : lightFont, NSParagraphStyleAttributeName : paragraphStyle}];
NSRange usernameRange = [baseString rangeOfString:comment.from.userName];
[oneCommentString addAttribute:NSFontAttributeName value:boldFont range:usernameRange];
[oneCommentString addAttribute:NSForegroundColorAttributeName value:linkColor range:usernameRange];
[commentString appendAttributedString:oneCommentString];
}
return commentString;
}
+ (CGFloat) heightForMediaItem:(BLCMedia *)mediaItem width:(CGFloat)width {
// Make a cell
BLCMediaTableViewCell *layoutCell = [[BLCMediaTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"layoutCell"];
[layoutCell setNeedsLayout];
[layoutCell layoutIfNeeded];
// Get the actual height required for the cell
return CGRectGetMaxY(layoutCell.commentLabel.frame);
}
@end
【问题讨论】:
-
那么它应该是什么样子呢?下面的图像和文本,然后是下一个图像和文本等?如果你使用约束,为什么还要设置框架?
-
桌子VC是如何计算高度的? - 你在 -heightForRowAtIndexPath: 中调用 heightForMediaItem 吗?或者您使用的是 iOS 8 唯一的估计高度方法。此外, -heightForMediaItem: width: 看起来很奇怪 - 您正在传递一个未使用的 BLCMedia 参数。每次计算高度时它都会实例化一个新单元格 - 使用存储为表视图控制器上的 ivar 的单个原型单元格更有效。如果你只有 iOS 8,你甚至不需要它。
-
@RichTolley,我确实意识到我错过了一些代码
//This was the missing code// layoutCell.mediaItem = mediaItem; layoutCell.frame = CGRectMake(0, 0, width, CGRectGetHeight(layoutCell.frame)); // ^ ^ ^ Missing Code ^ ^ ^,它解决了大部分问题(在 Dropbox 中更新了图像),但仍有一些重叠。我不知道新的 iOS8 方法,所以我会尝试实现它。
标签: ios objective-c autolayout