Программно сделанные ограничения не работают - PullRequest
1 голос
/ 02 ноября 2019

Поскольку я хочу отойти от xib и сделать свой макет программным способом, я обнаружил, что использование тех же самых точных ограничений не работает, как я ожидал.

Я хочу сделать эту UITableViewCell TableCell I want to make Это довольно простая ячейка с небольшим значком справа и индикатором активности, поэтому я могу выбрать, какой из них я хочу видеть. Они находятся внутри вида, и слева от них есть метка

Это мои ограничения в виде структуры Outline view И это работает отлично. Однако, когда я удаляю XIB и выполняю весь код сам, ничто больше не работает

Так вот мой код:

class StandardRow: UITableViewCell {    
    private var initialWidth: CGFloat = 20


public var fetching: Bool = false {
    didSet {
        if (fetching) {
            activityIndicator?.startAnimating()
        } else {
            activityIndicator?.stopAnimating()
        }

        changeImageWidth()
    }
}

public var rightImage: UIImage? = nil {
    didSet {
        rightImageView?.image = rightImage
        changeImageWidth()
    }
}

private func changeImageWidth() {
    if (activityIndicator?.isAnimating) ?? false || rightImage != nil {
        imageWidth?.constant = initialWidth
    } else {
        imageWidth?.constant = 0
    }
}

override func prepareForReuse() {
    valueLabel?.text = ""
    imageView?.image = nil
    rightImage = nil
    fetching = false
    textLabel?.text = ""
    accessoryType = .none
}


//Views
private var imageContainer = UIView()
private var rightImageView = UIImageView()
private var activityIndicator: UIActivityIndicatorView? = UIActivityIndicatorView()
public var valueLabel: UILabel? = UILabel()
private var imageWidth: NSLayoutConstraint? = nil

override init(style: UITableViewCell.CellStyle = .default, reuseIdentifier: String? = nil) {
    super.init(style: style, reuseIdentifier: reuseIdentifier)
    buildView()
}

required init?(coder: NSCoder) {
    super.init(coder: coder)
    buildView()
}

func buildView() {
    contentView.addSubview(valueLabel!)
    imageContainer.addSubview(rightImageView)
    imageContainer.addSubview(activityIndicator!)
    contentView.addSubview(imageContainer)

    imageContainer.backgroundColor = .red
}

override func layoutSubviews() {
    super.layoutSubviews()

    //IMAGE CONTAINER CONSTRAINTS
    imageWidth = NSLayoutConstraint(item: imageContainer, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: initialWidth)
    imageWidth?.priority = UILayoutPriority(rawValue: 999)
    imageWidth?.isActive = true
    let bottomImageContainerConstraint = NSLayoutConstraint(item: imageContainer, attribute: .bottom, relatedBy: .equal, toItem: contentView, attribute: .bottom, multiplier: 1, constant: 0)
    bottomImageContainerConstraint.isActive = true
    bottomImageContainerConstraint.priority = UILayoutPriority(rawValue: 999)

    let topImageContainerConstraint = NSLayoutConstraint(item: imageContainer, attribute: .top, relatedBy: .equal, toItem: contentView, attribute: .top, multiplier: 1, constant: 0)
    topImageContainerConstraint.isActive = true
    topImageContainerConstraint.priority = UILayoutPriority(rawValue: 999)

    let trailingImageContainerConstraint = NSLayoutConstraint(item: imageContainer, attribute: .trailing, relatedBy: .equal, toItem: contentView, attribute: .trailing, multiplier: 1, constant: 5)
    trailingImageContainerConstraint.priority = UILayoutPriority(rawValue: 999)
    trailingImageContainerConstraint.isActive = true

    let centerYImageContainerConstraint = NSLayoutConstraint(item: imageContainer, attribute: .centerY, relatedBy: .equal, toItem: contentView, attribute: .centerY, multiplier: 1, constant: 0)
    centerYImageContainerConstraint.isActive = true
    centerYImageContainerConstraint.priority = UILayoutPriority(rawValue: 999)
    //VALUE LABEL CONSTRAINTS
    let trailingValueLabelConstraint = NSLayoutConstraint(item: valueLabel!, attribute: .trailing, relatedBy: .equal, toItem: imageContainer, attribute: .leading, multiplier: 1, constant: 5)
    trailingValueLabelConstraint.isActive = true
    trailingValueLabelConstraint.priority = UILayoutPriority(rawValue: 999)

    let centerYValueLabelConstraint = NSLayoutConstraint(item: valueLabel!, attribute: .centerY, relatedBy: .equal, toItem: contentView, attribute: .centerY, multiplier: 1, constant: 0)
    centerYValueLabelConstraint.isActive = true
    centerYValueLabelConstraint.priority = UILayoutPriority(rawValue: 999)
    //ACTIVITY INDICATOR CONSTRAINGS
    NSLayoutConstraint(item: activityIndicator!, attribute: .trailing, relatedBy: .equal, toItem: imageContainer, attribute: .trailing, multiplier: 1, constant: 0).isActive = true
    NSLayoutConstraint(item: activityIndicator!, attribute: .leading, relatedBy: .equal, toItem: imageContainer, attribute: .leading, multiplier: 1, constant: 11).isActive = false
    NSLayoutConstraint(item: activityIndicator!, attribute: .bottom, relatedBy: .equal, toItem: imageContainer, attribute: .bottom, multiplier: 1, constant: 11).isActive = false
    NSLayoutConstraint(item: activityIndicator!, attribute: .top, relatedBy: .equal, toItem: imageContainer, attribute: .top, multiplier: 1, constant: 0).isActive = true
    NSLayoutConstraint(item: activityIndicator!, attribute: .centerY, relatedBy: .equal, toItem: imageContainer, attribute: .centerY, multiplier: 1, constant: 0).isActive = true
    //RIGHT IMAGE VIEW CONSTRAINTS
    NSLayoutConstraint(item: rightImageView, attribute: .trailing, relatedBy: .equal, toItem: activityIndicator!, attribute: .trailing, multiplier: 1, constant: 0).isActive = true
    NSLayoutConstraint(item: rightImageView, attribute: .leading, relatedBy: .equal, toItem: rightImageView, attribute: .leading, multiplier: 1, constant: 0).isActive = true
    NSLayoutConstraint(item: rightImageView, attribute: .bottom, relatedBy: .equal, toItem: activityIndicator!, attribute: .bottom, multiplier: 1, constant: 0).isActive = true
    NSLayoutConstraint(item: rightImageView, attribute: .top, relatedBy: .equal, toItem: activityIndicator!, attribute: .top, multiplier: 1, constant: 0).isActive = true
    NSLayoutConstraint(item: rightImageView, attribute: .centerY, relatedBy: .equal, toItem: activityIndicator!, attribute: .centerY, multiplier: 1, constant: 0).isActive = true
    //changeImageWidth()
}}

Так что у меня есть несколько идей, откуда он может прийтиfrom, во-первых, для «translatesAutoresizingMaskIntoConstraints» установлено значение true по умолчанию, но когда я устанавливаю значение false в суперпредставлении, тогда моя ячейка больше не отображается, а в contentView Xcode говорит мне, что я не должен этого делать из-занеопределенное поведение

Я также использую Reveal для отладки своего пользовательского интерфейса, и затем я нашел эти специфические значения:

Reveal values Это не то, что я хочу, Revealсообщая, что эти ограничения переводят маску авторазмера представления в autolayout, чтобы это подтвердило предыдущую теорию. Я установил приоритет на 999 для некоторых ограничений, потому что в противном случае они будут нарушены.

Я на самом деле зашел в тупик и думаю, что что-то упустил, но не могу точно определить, что, поскольку у меня недостаточно опыта с ограничениями неинтерфейсного конструктора

Ответы [ 3 ]

1 голос
/ 11 ноября 2019

Вы можете добавить тот же метод к вашему расширению UIView

 func constrainToEdges(_ subview: UIView, top: CGFloat = 0, bottom: CGFloat = 0, leading: CGFloat = 0, trailing: CGFloat = 0) {

    subview.translatesAutoresizingMaskIntoConstraints = false

    let topContraint = NSLayoutConstraint(
        item: subview,
        attribute: .top,
        relatedBy: .equal,
        toItem: self,
        attribute: .top,
        multiplier: 1.0,
        constant: top)

    let bottomConstraint = NSLayoutConstraint(
        item: subview,
        attribute: .bottom,
        relatedBy: .equal,
        toItem: self,
        attribute: .bottom,
        multiplier: 1.0,
        constant: bottom)

    let leadingContraint = NSLayoutConstraint(
        item: subview,
        attribute: .leading,
        relatedBy: .equal,
        toItem: self,
        attribute: .leading,
        multiplier: 1.0,
        constant: leading)

    let trailingContraint = NSLayoutConstraint(
        item: subview,
        attribute: .trailing,
        relatedBy: .equal,
        toItem: self,
        attribute: .trailing,
        multiplier: 1.0,
        constant: trailing)

    addConstraints([
        topContraint,
        bottomConstraint,
        leadingContraint,
        trailingContraint])
}
1 голос
/ 03 ноября 2019

Попробуйте якоря, это намного проще.

Пример

var redView = UIView()
redView.backgroundColor = .red
anyView.addsubView(redView)
redView.translatesAutoresizingMaskIntoConstraints = false
redView.centerXAnchor.constraint(equalTo: self.parentView.centerXAnchor).isActive = true
redView.centerYAnchor.constraint(equalTo: self.parentView.centerYAnchor).isActive = true
redView.heightAnchor.constraint(equalToConstant: 100).isActive = true
redView.widthAnchor.constraint(equalToConstant: 100).isActive = true
0 голосов
/ 15 ноября 2019

Я рекомендую использовать эту framework для программного построения макетов на основе ограничений, это делает процесс простым и быстрым. Возьмите настройку для contentView этой ячейки, например:

contentView.addSubview(descriptionLabel)
    contentView.addSubview(amountLabel)
    contentView.addSubview(dateLabel)
    contentView.addSubview(bottomRightLabel)

    constrain(descriptionLabel, amountLabel, dateLabel, bottomRightLabel) { desc, amount, date, bottomRight in

        desc.top              == desc.superview!.top + 16
        desc.left             == desc.superview!.left + 16
        desc.right            <= amount.left + 12
        desc.bottom           == date.top - 12

        amount.centerY        == desc.centerY
        amount.right          == amount.superview!.right - 12

        date.left             == date.superview!.left + 16
        date.right            <= bottomRight.left - 12
        date.bottom           == date.superview!.bottom - 16

        bottomRight.centerY   == date.centerY
        bottomRight.right     == bottomRight.superview!.right - 12
    }
...