ios 如何使用 AutoLayout 以编程方式创建自定义 UITableViewCell
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18969355/
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
How to create a custom UITableViewCell programmatically using AutoLayout
提问by Shawn Throop
I'm trying to implement a UITableView that will behave similarly to the timeline of a twitter client. Right now I'm simply attempting to get two labels inside a UITableViewCell. As recommended by this Stack Overflow answer, I'm using a different reuseIdentifier for each layouts. My layouts are simple, consisting of either a single label or two labels. Eventually I will be adjusting the height of the UITableViewCells but first I need to get the cells populated with content.
我正在尝试实现一个 UITableView,它的行为类似于 twitter 客户端的时间线。现在我只是试图在 UITableViewCell 中获取两个标签。正如这个 Stack Overflow answer所推荐的那样,我为每个布局使用不同的重用标识符。我的布局很简单,由一个标签或两个标签组成。最终我将调整 UITableViewCells 的高度,但首先我需要让单元格填充内容。
I can get the labels so show up if I set their frame with initWithFrame:
, however the constraints aren't being implemented.
如果我用 设置它们的框架initWithFrame:
,我可以得到标签,但是没有实现约束。
Question: What is preventing the labels and constraints from appearing? I'm clearly missing something in my implementation of the UITableViewCell but I have no idea what it is.
Secondary question: Am I registering the UITableViewCell class correctly for each reuseIdentifier in
viewDidLoad
?
问题:是什么阻止了标签和约束出现?我在 UITableViewCell 的实现中显然遗漏了一些东西,但我不知道它是什么。
次要问题:我是否为每个重用标识符正确注册了 UITableViewCell 类
viewDidLoad
?
This might come across as being difficult but Interface Builder confuses me, I would like to accomplish this all in code.
这可能看起来很困难,但 Interface Builder 让我感到困惑,我想用代码来完成这一切。
Here is the code for the custom UITableViewCell named TVTCell.h:
这是名为 TVTCell.h 的自定义 UITableViewCell 的代码:
static NSString * const kCellIDTitle = @"CellWithTitle";
static NSString * const kCellIDTitleMain = @"CellWithTitleMain";
@interface TVTCell : UITableViewCell
{
NSString *reuseID;
}
@property (nonatomic, strong) UILabel *nameLabel;
@property (nonatomic, strong) UILabel *mainLabel;
@end
And TVTCell.m:
和 TVTCell.m:
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
reuseID = reuseIdentifier;
nameLabel = [[UILabel alloc] init];
[nameLabel setTextColor:[UIColor blackColor]];
[nameLabel setBackgroundColor:[UIColor colorWithHue:32 saturation:100 brightness:63 alpha:1]];
[nameLabel setFont:[UIFont fontWithName:@"HelveticaNeue" size:18.0f]];
[nameLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.contentView addSubview:nameLabel];
mainLabel = [[UILabel alloc] init];
[mainLabel setTextColor:[UIColor blackColor]];
[mainLabel setBackgroundColor:[UIColor colorWithHue:66 saturation:100 brightness:63 alpha:1]];
[mainLabel setFont:[UIFont fontWithName:@"HelveticaNeue" size:18.0f]];
[mainLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.contentView addSubview:mainLabel];
[self.contentView setTranslatesAutoresizingMaskIntoConstraints:NO];
}
return self;
}
- (void)updateConstraints
{
[super updateConstraints];
NSDictionary *views = NSDictionaryOfVariableBindings(nameLabel, mainLabel);
if (reuseID == kCellIDTitle) {
NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[nameLabel]|"
options: NSLayoutFormatAlignAllCenterX
metrics:nil
views:views];
[self.contentView addConstraints:constraints];
constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[nameLabel]|"
options: NSLayoutFormatAlignAllCenterX
metrics:nil
views:views];
[self.contentView addConstraints:constraints];
}
if (reuseID == kCellIDTitleMain) {
NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[nameLabel]|"
options: NSLayoutFormatAlignAllCenterX
metrics:nil
views:views];
[self.contentView addConstraints:constraints];
constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[mainLabel]|"
options: NSLayoutFormatAlignAllCenterX
metrics:nil
views:views];
[self.contentView addConstraints:constraints];
constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[nameLabel][mainLabel]|"
options: NSLayoutFormatAlignAllLeft
metrics:nil
views:views];
[self.contentView addConstraints:constraints];
[self.contentView addConstraint:[NSLayoutConstraint constraintWithItem:nameLabel
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:0.0
constant:44.0]];
[self.contentView addConstraint:[NSLayoutConstraint constraintWithItem:nameLabel
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:self.contentView
attribute:NSLayoutAttributeNotAnAttribute
multiplier:0.0
constant:1]];
}
}
Sorry, ton of code. Here's my UITableView's tableView:cellForRowAtIndexPath:
对不起,大量的代码。这是我的 UITableViewtableView:cellForRowAtIndexPath:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row == 0 || indexPath.row == 2 || indexPath.row == 3) {
TVTCell *cell = [tableView dequeueReusableCellWithIdentifier:kCellIDTitle forIndexPath:indexPath];
[[cell nameLabel] setText:[nameArray objectAtIndex:indexPath.row]];
return cell;
} else if (indexPath.row == 1 || indexPath.row == 4 || indexPath.row == 5) {
TVTCell *cell = [tableView dequeueReusableCellWithIdentifier:kCellIDTitleMain forIndexPath:indexPath];
[[cell nameLabel] setText:[nameArray objectAtIndex:indexPath.row]];
[[cell mainLabel] setText:[dataArray objectAtIndex:indexPath.row]];
return cell;
} else
{
UITableViewCell *badCell = [[UITableViewCell alloc] init];
NSLog(@"Warning! returning a cell that shouldnt be here");
badCell.textLabel.text = @"Warning!";
return badCell;
}
}
And lastly, the UITableView's viewDidLoad method:
最后,UITableView 的 viewDidLoad 方法:
- (void)viewDidLoad
{
[super viewDidLoad];
[[self tableView] registerClass:[TVTCell class] forCellReuseIdentifier:kCellIDTitle];
[[self tableView] registerClass:[TVTCell class] forCellReuseIdentifier:kCellIDTitleMain];
}
回答by rdelmar
There are several things wrong with your code. First, I think you'll find, if you do some logging, that updateConstraints is never called. I would put all the code in the init method. Also, there are several things wrong in your constraints. The constraint where you set the height to 44 is not needed since you already have the labels pinned to the to and bottom of the cell. I don't know what you're trying to do with that last one, it looks like that would make the nameLabel 1 point wide. Also, you shouldn't set the translatesAutoresizingMaskIntoConstraints to NO for the content view, that causes weird effects. So this is the code I think you want:
您的代码有几处错误。首先,我想您会发现,如果您进行一些日志记录,则永远不会调用 updateConstraints。我会把所有的代码都放在 init 方法中。此外,您的约束有几处错误。不需要将高度设置为 44 的约束,因为您已经将标签固定到单元格的顶部和底部。我不知道你想用最后一个做什么,看起来这会使 nameLabel 宽 1 磅。此外,您不应该将内容视图的 translatesAutoresizingMaskIntoConstraints 设置为 NO,这会导致奇怪的效果。所以这是我认为你想要的代码:
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
reuseID = reuseIdentifier;
nameLabel = [[UILabel alloc] init];
[nameLabel setTextColor:[UIColor blackColor]];
[nameLabel setBackgroundColor:[UIColor colorWithHue:32 saturation:100 brightness:63 alpha:1]];
[nameLabel setFont:[UIFont fontWithName:@"HelveticaNeue" size:18.0f]];
[nameLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.contentView addSubview:nameLabel];
mainLabel = [[UILabel alloc] init];
[mainLabel setTextColor:[UIColor blackColor]];
[mainLabel setBackgroundColor:[UIColor colorWithHue:66 saturation:100 brightness:63 alpha:1]];
[mainLabel setFont:[UIFont fontWithName:@"HelveticaNeue" size:18.0f]];
[mainLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.contentView addSubview:mainLabel];
NSDictionary *views = NSDictionaryOfVariableBindings(nameLabel, mainLabel);
if (reuseID == kCellIDTitle) {
NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[nameLabel]|"
options: 0
metrics:nil
views:views];
[self.contentView addConstraints:constraints];
constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[nameLabel]|"
options: 0
metrics:nil
views:views];
[self.contentView addConstraints:constraints];
}
if (reuseID == kCellIDTitleMain) {
NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[nameLabel]|"
options:0
metrics:nil
views:views];
[self.contentView addConstraints:constraints];
constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[mainLabel]|"
options: 0
metrics:nil
views:views];
[self.contentView addConstraints:constraints];
constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[nameLabel][mainLabel(==nameLabel)]|"
options: 0
metrics:nil
views:views];
[self.contentView addConstraints:constraints];
}
}
return self;
}
回答by Ashis Laha
You can create UITableViewCell programatically in swift 4 using auto-layout like below. It's not exactly the solution of your above problem as you specified in question, It's more generic implementation how to create Tableview cell programatically in swift using auto-layout :
您可以使用如下所示的自动布局在 swift 4 中以编程方式创建 UITableViewCell。正如您所指定的那样,这并不是您上述问题的解决方案,而是如何使用自动布局以编程方式快速创建 Tableview 单元的更通用的实现:
class ViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(CustomCell2.self, forCellReuseIdentifier: "cell")
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 2
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as? CustomCell2 else { return UITableViewCell() }
cell.model = CellModel(labelString: "set constriant by code")
return cell
}
}
Define Model :
定义模型:
struct CellModel {
let labelString : String
}
Define Custom Cell :
定义自定义单元格:
class CustomCell2 : UITableViewCell {
private let label : UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false // enable auto layout
label.backgroundColor = .green // to visualize the background of label
label.textAlignment = .center // center text alignment
return label
}()
private func addLabel() {
addSubview(label)
NSLayoutConstraint.activate([
// label width is 70% of cell width
label.widthAnchor.constraint(equalTo: widthAnchor, multiplier: 0.7),
// label is horizontally center of cell
label.centerXAnchor.constraint(equalTo: centerXAnchor)
])
}
var model : CellModel? {
didSet {
label.text = model?.labelString ?? ""
}
}
// Init
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
addLabel()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
This is the output of above program.