xcode 为什么我的 UITableViewCell 的宽度与我的 UITableView 的宽度不同?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/23445218/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why does my UITableViewCell have width different from my UITableView's width?
提问by Христо Узунов
The trouble is this: I have a custom table view cell, that is used by a table view, which in turn is generic. The width of that table view is set to 240 via IB. Assuming that the cell will have the same width as the table, I went on and added some logic as to calculate rects for an image view and two labels, which are subsequently added to the cell's content view. As it turned out, my assumption was wrong. Trying to discover what is wrong, I went on and overridden tableView:willDisplayCell:forRowAtIndexPath:. The thing is this method shows that the width of the cell will be the desired 240 points, but it gets called after the designated initialiser of the custom cell initWithStyle:reuseIdentifier:, which, oddly enough, returns 320 points.
问题是:我有一个自定义表格视图单元格,由表格视图使用,而表格视图又是通用的。该表格视图的宽度通过 IB 设置为 240。假设单元格与表格的宽度相同,我继续添加一些逻辑来计算图像视图和两个标签的矩形,随后将它们添加到单元格的内容视图中。事实证明,我的假设是错误的。为了找出问题所在,我继续并覆盖了 tableView:willDisplayCell:forRowAtIndexPath:。问题是这个方法显示单元格的宽度将是所需的 240 点,但它在自定义单元格 initWithStyle:reuseIdentifier: 的指定初始化器之后被调用,奇怪的是,返回 320 点。
The following is the initialisation of the cell:
以下是单元格的初始化:
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
NSLog(@"cell frame at init: %@", NSStringFromCGRect(self.contentView.frame));
self.avatarView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, self.contentView.frame.size.height, self.contentView.frame.size.height)];
[self.contentView addSubview:self.avatarView];
self.nameLabel = [[UILabel alloc] initWithFrame:CGRectMake(self.avatarView.frame.size.width + 10, 0, self.frame.size.width - self.avatarView.frame.size.width - 40, self.frame.size.height)];
self.nameLabel.backgroundColor = [UIColor greenColor];
[self.contentView addSubview:self.nameLabel];
self.visitorsLabel = [[UILabel alloc] initWithFrame:CGRectMake(self.avatarView.frame.size.width + self.nameLabel.frame.size.width + 20, 0, self.frame.size.width - (self.avatarView.frame.size.width + self.nameLabel.frame.size.width + 20), self.contentView.frame.size.height)];
self.visitorsLabel.textColor = [UIColor whiteColor];
self.visitorsLabel.backgroundColor = [UIColor redColor];
[self.contentView addSubview:self.visitorsLabel];
}
return self;
}
The information for the subviews is supplied in a different method. This is the code in the controller, delegate of the table view:
子视图的信息以不同的方法提供。这是控制器中的代码,表视图的委托:
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NewClubTableCell *cell = [tableView dequeueReusableCellWithIdentifier:@"newCell"];
Club *club = [self.clubs getClubAtIndex:indexPath.row];
cell = [[NewClubTableCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"newCell"];
[cell setAvatar:club.avatar name:club.name visitors:club.visitors];
return cell;
}
-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(@"table view will display frame: %@", NSStringFromCGRect(cell.frame));
}
And this is the result from the logs:
这是日志的结果:
2014-05-03 16:18:04.143 FanStation[2436:70b] cell frame at init: {{0, 0}, {320, 44}}
2014-05-03 16:18:04.144 FanStation[2436:70b] table view will display frame: {{0, 0}, {240, 44}}
2014-05-03 16:18:04.145 FanStation[2436:70b] cell frame at init: {{0, 0}, {320, 44}}
2014-05-03 16:18:04.146 FanStation[2436:70b] table view will display frame: {{0, 44}, {240, 44}}
2014-05-03 16:18:04.146 FanStation[2436:70b] cell frame at init: {{0, 0}, {320, 44}}
2014-05-03 16:18:04.147 FanStation[2436:70b] table view will display frame: {{0, 88}, {240, 44}}
2014-05-03 16:18:04.147 FanStation[2436:70b] cell frame at init: {{0, 0}, {320, 44}}
2014-05-03 16:18:04.148 FanStation[2436:70b] table view will display frame: {{0, 132}, {240, 44}}
2014-05-03 16:18:04.148 FanStation[2436:70b] cell frame at init: {{0, 0}, {320, 44}}
2014-05-03 16:18:04.149 FanStation[2436:70b] table view will display frame: {{0, 176}, {240, 44}}
As you can see, the table view gives correct width, but still the cell has it's own mind about it.
正如你所看到的,表格视图给出了正确的宽度,但单元格仍然有它自己的想法。
My question is if I'm doing something wrong here, and if there is a way to rectify this issue? If you would require any additional information on this case, I'll be more than happy to provide it.
我的问题是我是否在这里做错了什么,是否有办法纠正这个问题?如果您需要有关此案例的任何其他信息,我将非常乐意提供。
回答by Duncan C
A table view cell has no idea what size it should be in it's initializer. It gets initialized at a default size (320 points) and then resized before being displayed. Don't pay attention to the size that's set in the init method.
表格视图单元格不知道它在它的初始值设定项中应该是什么大小。它以默认大小(320 磅)初始化,然后在显示之前调整大小。不要注意 init 方法中设置的大小。
What you are seeing is perfectly normal.
你所看到的是完全正常的。
You'll see the same thing with the main view in view controllers. The view gets created at it's default size and orientation in viewDidLoad, and then sized and rotated for display.
您将在视图控制器中的主视图中看到相同的内容。视图在 viewDidLoad 中以其默认大小和方向创建,然后调整大小和旋转以显示。
EDIT:
编辑:
If you need to be notified when your cells have been resized, you can implement the view controller method didLayoutSubViews. That will get called both when cells are initially size for the table view after initialization, and after the size of the view controller's content view changes (After device rotation, for example.)
如果您需要在调整单元格大小时收到通知,您可以实现视图控制器方法 didLayoutSubViews。当初始化后表格视图的单元格初始大小时,以及视图控制器的内容视图的大小更改后(例如,在设备旋转之后),这都会被调用。
回答by Христо Узунов
After the very helpful discussion with @Duncan C and @Basheer_CAD I feel the need to elaborate on the solution of the problem I presented with the current post.
I thought it would be foul if I did any UITableViewCell subviews initialisation outside the cell itself. So following the advises of the two mentioned above, I went on and overridden the cell's layoutSubviews
, where I create the rects for the subviews. As it turns out though, layoutSubviews
arrives on the scene very late, rendering my method providing the information for the subviews useless. So I had to create additional properties to temporarily store an image and two strings. Which are then used in the process of initialising the subviews.
Again, this is the code in the controller and if you follow the number, you'll get the sequence:
在与@Duncan C 和@Basheer_CAD 进行了非常有帮助的讨论之后,我觉得有必要详细说明我在当前帖子中提出的问题的解决方案。我认为如果我在单元格本身之外进行任何 UITableViewCell 子视图初始化,那将是犯规的。因此,按照上面提到的两个建议,我继续并覆盖了单元格的layoutSubviews
,在那里我为子视图创建了矩形。但事实证明,它layoutSubviews
很晚才到达现场,使我的方法为子视图提供信息无用。所以我不得不创建额外的属性来临时存储一个图像和两个字符串。然后在初始化子视图的过程中使用它们。同样,这是控制器中的代码,如果您按照数字进行操作,您将获得序列:
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NewClubTableCell *cell = [tableView dequeueReusableCellWithIdentifier:@"newCell"];
Club *club = [self.clubs getClubAtIndex:indexPath.row];
(1)
cell = [[NewClubTableCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"newCell"];
(3)
[cell setAvatar:club.avatar name:club.name visitors:club.visitors];
return cell;
}
This is the cell's initialiser. As you can see, it does nothing:
这是单元格的初始化程序。如您所见,它什么都不做:
-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier avatar:(UIImage *)avatar name:(NSString *)name visitors:(NSInteger)visitors
{
(2)
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
}
return self;
}
The data transfer method:
数据传输方式:
-(void)setAvatar:(UIImage *)avatar name:(NSString *)name visitors:(NSInteger)visitors
{
(4)
self.avatarImage = avatar;
self.name = name;
self.visitors = [NSString stringWithFormat:@"%d", visitors];
}
And finally, layoutSubviews
:
最后,layoutSubviews
:
-(void)layoutSubviews
{
(5)
self.avatarView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, self.contentView.frame.size.height, self.contentView.frame.size.height)];
self.avatarView.image = self.avatarImage;
[self.contentView addSubview:self.avatarView];
self.nameLabel = [[UILabel alloc] initWithFrame:CGRectMake(self.avatarView.frame.size.width, 0, self.frame.size.width - self.avatarView.frame.size.width - 40, self.frame.size.height)];
self.nameLabel.text = self.name;
self.nameLabel.backgroundColor = [UIColor greenColor];
[self.contentView addSubview:self.nameLabel];
self.visitorsLabel = [[UILabel alloc] initWithFrame:CGRectMake(self.avatarView.frame.size.width + self.nameLabel.frame.size.width, 0, self.frame.size.width - (self.avatarView.frame.size.width + self.nameLabel.frame.size.width), self.contentView.frame.size.height)];
self.visitorsLabel.text = self.visitors;
self.visitorsLabel.textColor = [UIColor whiteColor];
self.visitorsLabel.backgroundColor = [UIColor redColor];
[self.contentView addSubview:self.visitorsLabel];
}
The beauty of it is that only one method in the lifecycle was the key to have the whole thing up and running and properly displaying no matter the device and its orientation.
它的美妙之处在于,生命周期中只有一种方法是使整个事物启动并运行并正确显示的关键,无论设备及其方向如何。