如何强制 uitableview 调整单元格的大小(在停用高度约束后)?
Posted
技术标签:
【中文标题】如何强制 uitableview 调整单元格的大小(在停用高度约束后)?【英文标题】:How to force uitableview to resize a cell (after deactivating a height constraint)? 【发布时间】:2016-02-22 21:25:36 【问题描述】:我正在尝试通过点击一个按钮来放置一个可扩展的UITableViewCell
。
我正在使用约束来强制动态UITextView
告诉UITableViewCell
它的新高度。 (使用自动布局和UITableViewAutomaticDimension
)
这在没有按钮的情况下按预期工作:UITableViewCell
的高度取决于UITextView
的高度。
对UITextView
有一个约束以最大化单元格的大小,当点击按钮时(单元格已折叠),我想删除对UITextView
的高度约束(即限制单元格高度)和相应地更新单元格。这是扩展方法:
-(void)extendCellWasTapped:(UITableViewCell*)senderCell
MAFollowingPostTableViewCell *cell = (MAFollowingPostTableViewCell*)senderCell;
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
if (![self.arrayExtendedTitlesAtIndexPaths containsObject:indexPath])
[self.arrayExtendedTitlesAtIndexPaths addObject:indexPath];
if ([self.tableView.indexPathsForVisibleRows containsObject:indexPath] )
dispatch_async(dispatch_get_main_queue(), ^(void)
[NSLayoutConstraint deactivateConstraints:@[cell.constraintTextViewHeight]];
// CGPoint offset = self.tableView.contentOffset;
[self.tableView beginUpdates];
[self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
[self.tableView endUpdates];
// I would like to minimize the animations as well here.. but thats another //problem
// [self.tableView.layer removeAllAnimations];
// [self.tableView setContentOffset:offset animated:NO];
// [self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
);
如果我点击按钮然后滚动到类似的单元格,则它已经展开。所以我在这里遗漏了一些东西。我已经尝试在停用约束后执行[cell updateConstraints]
,但它不起作用。
更新
起初,由于某种原因,该按钮没有显示。而且我注意到(使用相同的代码)如果我向下滚动然后向上滚动,按钮就会显示出来,如果我尝试扩展它,它就会起作用。
更新
这是我的 UIViewController :
http://www.gfycat.com/FairBossyAfricanporcupine
请注意,扩展按钮不存在,但是一旦我向下/向上滚动,它就会出现,并且一旦我点击扩展按钮,它就会扩展单元格。
更新
我注意到在计算 textSize 时(查看单元格是否可扩展),首先,textView 比其最终状态更宽。我正在对 cellForRowAtIndexPath 执行此检查:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
MAPostTableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:kCellIdentifier forIndexPath:indexPath];
cell.delegate = self;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
MAPostFollowing *post = (MAPostFollowing*)[self.arrayPosts objectAtIndex:indexPath.section];
cell.textViewTitle.textContainer.lineBreakMode = NSLineBreakByWordWrapping;
NSString *title = [post.post title];
[cell.textViewTitle setText:title];
UIButton * buttonExtend = [cell buttonExtend];
if ([self.arrayExtendedTitlesAtIndexPaths containsObject:indexPath])
cell.constraintTextViewHeight.active = NO;
if (![buttonExtend isHidden])
buttonExtend.hidden = YES;
buttonExtend.userInteractionEnabled = NO;
else
cell.constraintTextViewHeight.active = YES;
NSLog(@"index %li", (long)indexPath.row);
BOOL b = ![self isTitleExtendable:title forTextView:cell.textViewTitle]; // Checks if the current text view is able to fit the title. If not, it will show the buttonExtend
buttonExtend.hidden = b;
buttonExtend.userInteractionEnabled = !b;
...
所以在第一次运行(滚动前)时,[self isTitleExtendable:title forTextView:cell.textViewTitle];不返回所需的值,因为在计算 textSize 时 textView 没有正确的宽度。
所以我相信有以下选择: - 更改布局后强制 textViewTitle 刷新(从而正确计算可扩展 UI 状态) - 一旦 textViewTitle 改变宽度,重新检查可扩展 UI 状态
更新
在 prepareForReuse 方法上,textViewTitle 仍然有一个更宽的框架。在 layoutSubviews 方法中,它实际上有一个小框架。这里的挑战是被更频繁地调用,它让我得到错误的情况(按钮在不应该显示的时候显示)
这是我正在尝试的:
-(void)layoutSubviews
[super layoutSubviews];
BOOL b = [self isTitleExtendable:self.textViewTitle.text forTextView:self.textViewTitle];
self.buttonExtend.hidden = !b;
self.buttonExtend.userInteractionEnabled = b;
if (!b)
NSLog(@"Button hidden YES UserInteraction NO");
else
NSLog(@"Button hidden NO UserInteraction YES");
NSLog(@"textViewTitle layout %f",self.textViewTitle.frame.size.width);
【问题讨论】:
如果您尝试删除约束而不是停用它会发生什么[cell removeConstraints:cell.constraintTextViewHeight]
?
同样的事情。不确定一旦单元被重用它是否会起作用(这就是我停用而不是删除的原因)
我对这个问题有点困惑。通过查看您的 GIF,听起来问题在于首次呈现单元格时按钮不存在。在您似乎暗示的问题中,按钮在那里并且不起作用。请耐心等待,也许只是我误解了这个问题。
你是对的。按钮一开始就不在那里,所以我想要的行为不适用于那些。
您是否已经为视图/按钮/控件尝试了 [tableView reloadData] 和 [view setNeedsDisplay]?
【参考方案1】:
要做这样的事情,你不应该依赖约束,而是在tableView(_:heightForRowAtIndexPath:)
你只需要根据上下文给出正确的高度。
按下按钮会触发更改,因此 tableView(_:heightForRowAtIndexPath:)
会为您扩展的单元格返回不同的值。
在执行此触发器之后,只需执行以下操作:
[self.tableView beginUpdates];
[self.tableView endUpdates];
它们之间没有任何东西,它会触发UITableView
的“自然动画”并做你想做的事
【讨论】:
正如描述所说,我正在使用 UITableViewAutomaticDimension 我仍然会使用开始更新技巧来强制动画更新 ;) 但是在使用自动调整大小的单元格时我没有尝试【参考方案2】:忘记从 self.arrayExtendedTitlesAtIndexPaths 中删除 indexpath 吗?
if (![self.arrayExtendedTitlesAtIndexPaths containsObject:indexPath])
[self.arrayExtendedTitlesAtIndexPaths addObject:indexPath];
else
[self.arrayExtendedTitlesAtIndexPaths removeObject:indexPath];
【讨论】:
没有。这是用户点击扩展按钮后执行的操作。一旦他这样做了,那个单元格就会一直被扩展。【参考方案3】:如果按钮不存在并且在您滚动它时再次显示,那么您肯定有可重用性问题。
您可能决定在cellForRowAtIndexPath:
中显示或隐藏按钮。如果您有条件,请尝试始终显示此按钮,并且如果这将按预期工作,则无论是否存在此约束,都将按钮隐藏在单元格内。正确的方法是在UITableViewCell
子类中的prepareForReuse
。
【讨论】:
这可能是要走的路。不过,我仍然不能 100% 确定实施情况【参考方案4】:更改完成后致电[cell layoutSubviews];
。
【讨论】:
根据 layoutSubviews 的文档:方法:“你不应该直接调用这个方法。”以上是关于如何强制 uitableview 调整单元格的大小(在停用高度约束后)?的主要内容,如果未能解决你的问题,请参考以下文章
通过 UITextView 内容大小调整 UITableView 单元格的大小
UICollectionViewController 如何调整单元格的大小?