Ширина ячейки UITableView на iOS 8 застряла на 320pt
В настоящее время я пытаюсь создать простой UITableView с пользовательскими ячейками без использования раскадровки.
Я получаю проблему на симуляторе iPhone 6, где табличное представление имеет ширину 375 (как и должно быть), но ячейки внутри получают ширину 320.
Число 320 нигде не встречается в проекте, так как я его не жестко кодирую. Когда я устанавливаю цвет фона ячейки, он расширяет всю ширину 375, но мне нужно выровнять изображение вправо, которое выравнивает только 320, как показано на фотографии ниже.
![image of weird tableviewcell sizing]()
Я не уверен, что это потому, что я пропускаю ограничения или если есть ошибка. Любая помощь приветствуется, спасибо!
Код для настройки таблицы:
- (TBMessageViewCell *)getMessageCellforTableView:(UITableView *)tableView atIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = @"MessageCell";
TBMessageViewCell *cell = (TBMessageViewCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[TBMessageViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
[cell createSubviews];
}
// Set the new message and refresh
[cell setMessage:self.viewModel.messages[indexPath.row]];
[cell populateSubviews];
cell.backgroundColor = [UIColor blueColor];
NSLog(@"cell Width: %f", cell.contentView.frame.size.width);
return cell;
}
Завершить TBMessageViewCell:
@implementation TBMessageViewCell
const CGFloat MARGIN = 10.0f;
const CGFloat AVATAR_SIZE = 40.0f;
-(id)initWithStyle:(UITableViewCellStyle *)style reuseIdentifier:(NSString *)reuseIdentifier
{
if(self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier]){
}
// Sets background and selected background color
self.backgroundColor = [UIColor clearColor];
UIView *selectionColor = [[UIView alloc] init];
selectionColor.backgroundColor = [UIColor clearColor];
self.selectedBackgroundView = selectionColor;
return self;
}
- (void)populateSubviews
{
// Set the message body
[self.messageBodyLabel setText:self.message.body];
[self.messageBodyLabel setTextAlignment:NSTextAlignmentRight];
CGRect bodyFrame = CGRectMake(MARGIN, MARGIN, self.frame.size.width - (AVATAR_SIZE + (MARGIN * 3)), self.frame.size.height);
// Calculates the expected frame size based on the font and dimensions of the label
// FLT_MAX simply means no constraint in height
CGSize maximumLabelSize = CGSizeMake(bodyFrame.size.width, FLT_MAX);
CGRect textRect = [self.message.body boundingRectWithSize:maximumLabelSize
options:NSStringDrawingUsesLineFragmentOrigin
attributes:@{NSFontAttributeName:self.messageBodyLabel.font}
context:nil];
bodyFrame.size.height = textRect.size.height;
// Setup the new avatar frame (Right aligned)
CGRect avatarFrame = CGRectMake(bodyFrame.size.width + (MARGIN * 2), MARGIN, AVATAR_SIZE, AVATAR_SIZE);
// Align to the LEFT side for current user messages
if ([[TBConfig userID] isEqualToString:self.message.user.userID]) {
// Set avatar to left if it me
avatarFrame.origin.x = MARGIN;
bodyFrame.origin.x = AVATAR_SIZE + (MARGIN * 2);
[self.messageBodyLabel setTextAlignment:NSTextAlignmentLeft];
}
self.avatar.frame = avatarFrame;
self.avatar.layer.cornerRadius = self.avatar.frame.size.width/2;
self.messageBodyLabel.frame = bodyFrame;
// Set the new cell height on the main Cell
CGFloat cellHeight = MAX(bodyFrame.size.height, self.frame.size.height) + MARGIN;
self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, self.frame.size.width, cellHeight);
// Set the new Profile avatar
if (![self.avatar.profileID isEqualToString:self.message.user.facebookID]) {
[self.avatar setProfileID:nil];
[self.avatar setProfileID:self.message.user.facebookID];
}
}
- (void)createSubviews
{
self.messageBodyLabel = [[UILabel alloc] init];
self.messageBodyLabel.textColor = [UIColor whiteColor];
self.messageBodyLabel.lineBreakMode = NSLineBreakByWordWrapping;
self.messageBodyLabel.numberOfLines = 0;
[self addSubview:self.messageBodyLabel];
// Creates the avatar
self.avatar = [[FBProfilePictureView alloc] init];
[self.avatar setPictureCropping:FBProfilePictureCroppingSquare];
[self addSubview:self.avatar];
}
Ответы
Ответ 1
Вы печатаете размер ячейки до того, как она будет добавлена на дисплей - до того, как она будет изменена. Кому вы представляете, будет ли размер ячейки? С чего, как вы думаете, должно получить ширину экрана таблицы? Он даже не знает, какой вид таблицы он будет передан.
Ячейкам будет присвоен соответствующий кадр при добавлении на дисплей.
EDIT: oh, и вы, вероятно, не хотите, чтобы cellIdentifier
был static
. Вероятно, вы хотели *const
.
Ответ 2
Не знаю, нашли ли вы ответ. У меня возникла та же проблема, когда я пытался подклассифицировать UITableViewCell и добавлять пользовательские подпрограммы программно, не используя xib.
Наконец, решение для меня помогло использовать [[UIScreen mainScreen] applicationFrame]
вместо self.frame
при расчете кадров subviews.
Ответ 3
Правильный способ решить эту задачу - выполнить макет в методе layoutSubviews.
В вашем случае просто вызовите "populateSubviews" в методе "layoutSubviews", например:
- (void)layoutSubviews {
[super layoutSubviews];
[self populateSubviews];
}
... но прежде чем делать это, я бы рекомендовал, чтобы вы размещали контент в отдельном методе (т.е. вызывали label.text =...) и размещали все вызовы, влияющие на макет (т.е. label.frame =...) ниже [super layoutSubviews] в методе выше.
Это приведет к чему-то вроде:
- (void)layoutSubviews {
[super layoutSubviews];
CGRect bodyFrame = CGRectMake(MARGIN, MARGIN, self.frame.size.width - (AVATAR_SIZE + (MARGIN * 3)), self.frame.size.height);
// Calculates the expected frame size based on the font and dimensions of the label
// FLT_MAX simply means no constraint in height
CGSize maximumLabelSize = CGSizeMake(bodyFrame.size.width, FLT_MAX);
CGRect textRect = [self.message.body boundingRectWithSize:maximumLabelSize
options:NSStringDrawingUsesLineFragmentOrigin
attributes:@{NSFontAttributeName:self.messageBodyLabel.font}
context:nil];
bodyFrame.size.height = textRect.size.height;
// .. the rest of your layout code here ..
}
- (void)populateSubviews {
[self.messageBodyLabel setText:self.message.body];
// .. the rest of your code here ..
}
Ответ 4
После того, как вы установили кадр аватара в:
self.avatar.frame = avatarFrame;
self.avatar.layer.cornerRadius = self.avatar.frame.size.width/2;
self.messageBodyLabel.frame = bodyFrame;
написать
self.avatar.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleLeftMargin;
Он должен закрепить изображение аватара на правом поле и оставить левое поле гибким.
Ответ 5
Выберите своего инспектора сотовой связи со списком таблиц и проверьте, не ошибочно ли вы подключили editAccessoryView
![введите описание изображения здесь]()
Ответ 6
Хотя этот ответ может быть не таким простым, как вы ожидаете, UIKit будет доставлять из-за ошибки в UITableView - когда вы делаете что-то программно - вы должны заразиться руками. Любители Xib - будьте предупреждены - этот ответ не для вас. Вероятно, он просто работает.
В более поздних версиях IOS позвольте надеяться, что эта проблема будет решена. Проблема заключается в том, что uitableview жестко кодирует размеры ячейки до 320. В одном проекте у меня было - я заставлял размер кадра исправлять это. Нотабене это имеет проблемы с контроллером splitview на iPad.
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath{
NSLog(@"cell frame width:%f",cell.frame.size.width); // you should see <- 320! WTH
// you can crudely correct this here
cell.frame = CGRectMake(0,0,[[UIScreen mainScreen] applicationFrame].size.width,CELL_HEIGHT);
}
Другая опция - лучше работать для меня - это переменная локальной ширины для ссылки. Я знаю, что этот код не идеален, но он работает последовательно.
@interface AbtractCustomCell : UITableViewCell {
float width;
}
@end
@implementation AbtractCustomCell
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
//optimise speed
// [self setOpaque:YES];
if ([SDiPhoneVersion deviceSize] == iPhone47inch) {
width = 375;
}
else if ([SDiPhoneVersion deviceSize] == iPhone47inch) {
width = 414;
}
else {
width = 320; // hardcode iphone 4/5 /ipad2
}
}
return self;
}
@end
тогда у вас есть возможность сделать TBMessageViewCell подклассом этого AbstractCustomCell, который будет иметь эту переменную для вас. Вместо использования self.contentView.bounds.size.width/self.bounds.size.width просто используйте ширину.
Ответ 7
Я программирую макет без Storyboard и сталкиваюсь с той же проблемой, и мне нужно вернуть ячейку на cellForRowAt indexPath
, которая в свою очередь еще не смогла получить размер контейнера.
И мне удастся его решить, переместив коды макета в делегат willDisplay cell
.