Подтвердить что ты не робот

Как создать пользовательский 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];
}
4b9b3361

Ответ 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")
}
}

Это результат вышеуказанной программы.

Это фактический проект, вы можете проверить.