Как создать пользовательский UITableViewCell программно, используя AutoLayout
Я пытаюсь реализовать UITableView, который будет вести себя аналогично временной шкале клиента twitter. Прямо сейчас я просто пытаюсь получить две метки внутри UITableViewCell. Как рекомендовано этим ответом, я использую другой reuseIdentifier для каждого макета. Мои макеты простые, состоящие из одной метки или двух меток. В конце концов я буду корректировать высоту UITableViewCells, но сначала мне нужно получить ячейки, заполненные контентом.
Я могу получить ярлыки, чтобы они отображались, если я устанавливаю их фрейм с initWithFrame:
, однако ограничения не выполняются.
-
Вопрос: Что мешает появлению ярлыков и ограничений? Мне явно не хватает чего-то в моей реализации UITableViewCell, но я понятия не имею, что это такое.
-
Вторичный вопрос: Я правильно регистрирую класс UITableViewCell для каждого повторного идентификатора в viewDidLoad
?
Это может показаться трудным, но интерфейс Builder меня смущает, я хотел бы выполнить все это в коде.
Вот код для пользовательского UITableViewCell с именем TVTCell.h:
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
И 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]];
}
}
Извините, тонна кода. Здесь мой UITableView tableView: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;
}
}
И, наконец, метод UITableView viewDidLoad:
- (void)viewDidLoad
{
[super viewDidLoad];
[[self tableView] registerClass:[TVTCell class] forCellReuseIdentifier:kCellIDTitle];
[[self tableView] registerClass:[TVTCell class] forCellReuseIdentifier:kCellIDTitleMain];
}
Ответы
Ответ 1
В коде есть несколько ошибок. Во-первых, я думаю, вы обнаружите, что если вы выполните некоторые протоколирования, то updateConstraints никогда не вызывается. Я бы поместил весь код в метод init. Кроме того, в ваших ограничениях есть несколько ошибок. Ограничение, в котором вы устанавливаете высоту до 44, не требуется, поскольку у вас уже есть метки, прикрепленные к ячейкам и внизу. Я не знаю, что вы пытаетесь сделать с этим последним, похоже, это сделало бы имяLabel 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;
}
Ответ 2
Вы можете создавать UITableViewCell программно в swift 4 с использованием автоматического макета, как показано ниже. Это не совсем решение вашей проблемы выше, как вы указали в вопросе. Это более общая реализация. Как создать табличную ячейку программно с помощью автоматического макета:
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
}
}
Определить модель:
struct CellModel {
let labelString : String
}
Определите пользовательскую ячейку:
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")
}
}
Это результат вышеуказанной программы.
Это фактический проект, вы можете проверить.