如何解决UITableViewCell何时完成布局子视图?
如下图所示,我想添加一个尖端(最大的UIView的子视图),该尖端与UITableViewCell中的UIStackView保持对齐。 UITableViewCell中UIStackView的宽度是动态的,因此我需要将提示视图放置在UITableViewCell布局的子视图之后。
我试图在willDisplayCell函数中添加提示视图,但是到达的位置不是最终位置。
此外,我尝试在UITableViewCell的layoutSubviews函数中设置笔尖视图的位置。由于多次调用此功能,因此笔尖最终会到达预期的位置,但开始时会闪烁。
那我应该在哪个函数中添加提示视图?
--------编辑--------
添加代码段以使其更清晰。我只想知道应该将以下代码放在哪里,以便rect.origin.x是stackview的最终位置。
UIView *view = self.view;
CGRect rect = [cell.stackView convertRect:cell.stackView.bounds toView:view];
[self.tipView.leadingAnchor constraintEqualToAnchor:view.leadingAnchor constant:rect.origin.x].active = YES;
[self.tipView.trailingAnchor constraintLessThanOrEqualToAnchor:view.trailingAnchor constant:-marginConstant].active = YES;
[self.tipView.bottomAnchor constraintEqualToAnchor:self.tableView.bottomAnchor constant:-TSkBubbleClickAreaHeight-marginConstant].active = YES;
[view layoutIfNeeded];
解决方法
修改
要尝试直接回答您的问题,您要知道对单元格所做的任何事情都将完全完成单元格内容的布局。因此,要确切知道单元的堆栈视图何时被布置,可以对堆栈视图进行子类化,并在该子类中实现layoutSubviews
。
由于尚不清楚您到底在做什么,我将提供几种方法...
如果您在表格视图上调用reloadData
,则可以尝试以下操作:
[tableView reloadData];
dispatch_async(dispatch_get_main_queue(),^{
[self showTipView:pth];
});
如果您呼叫insertRowsAtIndexPaths
,则可以尝试以下操作:
[CATransaction begin];
[CATransaction setCompletionBlock:^{
[self showTipView:pth];
}];
[self->tableView insertRowsAtIndexPaths:@[pth] withRowAnimation:UITableViewRowAnimationRight];
[CATransaction commit];
这是一个例子(我试图保持简单,并提供清晰的注释):
ExampleTableViewCell.h
//
// ExampleTableViewCell.h
// Created by Don Mag on 9/15/20.
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface ExampleTableViewCell : UITableViewCell
- (void) configureCell:(NSString *)s;
- (UIStackView *)getStackRef;
@end
NS_ASSUME_NONNULL_END
ExampleTableViewCell.m
//
// ExampleTableViewCell.m
// Created by Don Mag on 9/15/20.
//
#import "ExampleTableViewCell.h"
@interface ExampleTableViewCell ()
{
UIStackView *stackView;
UILabel *label;
}
@end
@implementation ExampleTableViewCell
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
[self commonInit];
}
return self;
}
- (void) commonInit {
label = [UILabel new];
label.backgroundColor = [UIColor yellowColor];
stackView = [UIStackView new];
stackView.translatesAutoresizingMaskIntoConstraints = NO;
[stackView addArrangedSubview:label];
[self.contentView addSubview:stackView];
UILayoutGuide *g = self.contentView.layoutMarginsGuide;
[NSLayoutConstraint activateConstraints:@[
// constrain stack view Top: 0 / Trailing: 0 / Bottom: 0
[stackView.topAnchor constraintEqualToAnchor:g.topAnchor constant:0.0],[stackView.trailingAnchor constraintEqualToAnchor:g.trailingAnchor constant:0.0],[stackView.bottomAnchor constraintEqualToAnchor:g.bottomAnchor constant:0.0],]];
}
- (void) configureCell:(NSString *)s {
label.text = s;
}
- (UIStackView *)getStackRef {
return stackView;
}
@end
ExampleViewController.h
//
// ExampleViewController.h
// Created by Don Mag on 9/15/20.
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface ExampleViewController : UIViewController
@end
NS_ASSUME_NONNULL_END
ExampleViewController.m
//
// ExampleViewController.m
// Created by Don Mag on 9/15/20.
//
#import "ExampleViewController.h"
#import "ExampleTableViewCell.h"
@interface ExampleViewController () <UITableViewDataSource,UITableViewDelegate,UIScrollViewDelegate>
{
NSMutableArray *myData;
NSMutableArray *sampleStrings;
UIView *tipView;
UIButton *reloadButton;
UIButton *insertButton;
UITableView *tableView;
NSInteger idx;
NSInteger insertRow;
}
@end
@implementation ExampleViewController
- (void)viewDidLoad {
[super viewDidLoad];
// row number to insert and show the tipView
insertRow = 7;
// init some sample data
myData = [NSMutableArray new];
for (int i = 0; i < 30; i++) {
NSString *s = [NSString stringWithFormat:@"Row %i",i];
[myData addObject:s];
}
// a few example strings
sampleStrings = [NSMutableArray new];
[sampleStrings addObject:@"Short text example."];
[sampleStrings addObject:@"A little more text example."];
[sampleStrings addObject:@"Considerably longer text for this example."];
// index for sampleStrings array
idx = -1;
// create a "tip view"
// red background view with
// green background label
// label is inset 4-pts on each side
tipView = [UIView new];
tipView.backgroundColor = [UIColor redColor];
UILabel *tipLabel = [UILabel new];
tipLabel.backgroundColor = [UIColor greenColor];
tipLabel.text = @"This is the tip!";
tipView.translatesAutoresizingMaskIntoConstraints = NO;
tipLabel.translatesAutoresizingMaskIntoConstraints = NO;
[tipView addSubview:tipLabel];
[NSLayoutConstraint activateConstraints:@[
[tipLabel.topAnchor constraintEqualToAnchor:tipView.topAnchor constant:4.0],[tipLabel.leadingAnchor constraintEqualToAnchor:tipView.leadingAnchor constant:4.0],[tipLabel.bottomAnchor constraintEqualToAnchor:tipView.bottomAnchor constant:-4.0],[tipLabel.trailingAnchor constraintEqualToAnchor:tipView.trailingAnchor constant:-4.0],]];
// init buttons
reloadButton = [UIButton new];
[reloadButton setTitle:@"Reload" forState:UIControlStateNormal];
[reloadButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[reloadButton setTitleColor:[UIColor grayColor] forState:UIControlStateHighlighted];
[reloadButton setBackgroundColor:[UIColor blueColor]];
insertButton = [UIButton new];
[insertButton setTitle:@"Insert" forState:UIControlStateNormal];
[insertButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[insertButton setTitleColor:[UIColor grayColor] forState:UIControlStateHighlighted];
[insertButton setBackgroundColor:[UIColor blueColor]];
// init table view
tableView = [UITableView new];
for (UIView *v in @[reloadButton,insertButton,tableView]) {
v.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:v];
}
UILayoutGuide *g = self.view.safeAreaLayoutGuide;
[NSLayoutConstraint activateConstraints:@[
// buttons at top
[reloadButton.topAnchor constraintEqualToAnchor:g.topAnchor constant:20.0],[reloadButton.leadingAnchor constraintEqualToAnchor:g.leadingAnchor constant:24.0],[insertButton.topAnchor constraintEqualToAnchor:g.topAnchor constant:20.0],[insertButton.trailingAnchor constraintEqualToAnchor:g.trailingAnchor constant:-24.0],[insertButton.leadingAnchor constraintEqualToAnchor:reloadButton.trailingAnchor constant:20.0],[insertButton.widthAnchor constraintEqualToAnchor:reloadButton.widthAnchor],// constrain tableView Top: 20-pts from buttons / Leading: 0 / Trailing: 0 / Bottom: 0
[tableView.topAnchor constraintEqualToAnchor:reloadButton.bottomAnchor constant:20.0],[tableView.leadingAnchor constraintEqualToAnchor:g.leadingAnchor constant:0.0],[tableView.trailingAnchor constraintEqualToAnchor:g.trailingAnchor constant:0.0],[tableView.bottomAnchor constraintEqualToAnchor:g.bottomAnchor constant:0.0],]];
[tableView registerClass:[ExampleTableViewCell class] forCellReuseIdentifier:@"exCell"];
tableView.delegate = self;
tableView.dataSource = self;
[reloadButton addTarget:self action:@selector(btnTap:) forControlEvents:UIControlEventTouchUpInside];
[insertButton addTarget:self action:@selector(btnTap:) forControlEvents:UIControlEventTouchUpInside];
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
[tipView removeFromSuperview];
}
- (void)btnTap:(UIButton *)btn {
// remove tipView if it's showing
[tipView removeFromSuperview];
NSString *s = sampleStrings[++idx % 3];
if (btn == reloadButton) {
[self reloadMethod:s];
} else {
[self insertMethod:s];
}
}
- (void)insertMethod:(NSString *)s {
// IndexPath for cell you want
__block NSIndexPath *pth = [NSIndexPath indexPathForRow:insertRow inSection:0];
[myData insertObject:s atIndex:pth.row];
[CATransaction begin];
[CATransaction setCompletionBlock:^{
[self showTipView:pth];
}];
[self->tableView insertRowsAtIndexPaths:@[pth] withRowAnimation:UITableViewRowAnimationRight];
[CATransaction commit];
}
- (void)reloadMethod:(NSString *)s {
// IndexPath for cell you want
__block NSIndexPath *pth = [NSIndexPath indexPathForRow:insertRow inSection:0];
[myData insertObject:s atIndex:pth.row];
[tableView reloadData];
dispatch_async(dispatch_get_main_queue(),^{
[self showTipView:pth];
});
}
- (void)showTipView:(NSIndexPath *)pth {
// get a reference to the cell
ExampleTableViewCell *cell = [tableView cellForRowAtIndexPath:pth];
// if row is not visible
if (!cell) {
return;
}
// get a reference to the cell's stack view
UIStackView *stack = [cell getStackRef];
// add tipView to self.view
[self.view addSubview:tipView];
// constrain tipView
// Leading to stack view's Leading
// Bottom to cell's Top - 4
[NSLayoutConstraint activateConstraints:@[
[tipView.leadingAnchor constraintEqualToAnchor:stack.leadingAnchor constant:0.0],[tipView.bottomAnchor constraintEqualToAnchor:cell.topAnchor constant:-4.0],]];
// if we want to "fade-in" the tipView
[tipView setAlpha:0.0];
[UIView animateWithDuration:0.3
animations:^{
[self->tipView setAlpha:1.0];
}];
}
- (nonnull UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath {
ExampleTableViewCell *c = (ExampleTableViewCell *)[tableView dequeueReusableCellWithIdentifier:@"exCell" forIndexPath:indexPath];
[c configureCell:myData[indexPath.row]];
return c;
}
- (NSInteger)tableView:(nonnull UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [myData count];
}
@end
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。