Ограничения не применяются должным образом - PullRequest
0 голосов
/ 13 марта 2020

У меня есть пользовательский UITextField, который я использую в нескольких местах, но у меня странная проблема с ограничениями только на нескольких страницах, которые я использую. У пользовательского класса есть несколько вещей, которые я добавляю при инициализации:

  • UILabel, который я добавляю как подпредставление, используя ограничения top, left и right для UITextField. Это вызывается, когда awakeFromNib функция UITextField выполняет
class FormTextField: UITextField {
    override func awakeFromNib() {
        self.layer.masksToBounds = true
        self.addErrorLabel()
    }

    ...

    private func addErrorLabel() {
        errorLabel = UILabel(frame: CGRect(x: self.frame.minX, y: self.frame.maxY-5, width: self.frame.width, height: self.frame.height))
        errorLabel.textColor = UIColor.red
        errorLabel.backgroundColor = UIColor.black
        errorLabel.font = UIFont.systemFont(ofSize: 12.0)
        errorLabel.text = ""
        errorLabel.alpha = 0.0
        errorLabel.numberOfLines = 0

        errorLabel.textAlignment = YTPAppManager.language == .arabic ? .right : .left

        if (self.textAlignment != .center) { self.textAlignment = YTPAppManager.language == .arabic ? .right : .left }

        errorLabel.translatesAutoresizingMaskIntoConstraints = false

        self.superview?.addSubview(errorLabel)

        let topConstraint = NSLayoutConstraint(item: errorLabel!, attribute: .top, relatedBy: .equal, toItem: self, attribute: .bottom, multiplier: 1.0, constant: 0.0)
        let leftConstraint = NSLayoutConstraint(item: errorLabel!, attribute: .left, relatedBy: .equal, toItem: self, attribute: .left, multiplier: 1.0, constant: 0.0)
        let rightConstraint = NSLayoutConstraint(item: errorLabel!, attribute: .right, relatedBy: .equal, toItem: self, attribute: .right, multiplier: 1.0, constant: 0.0)

        topConstraint.priority = UILayoutPriority(1.0)
        leftConstraint.priority = UILayoutPriority(1.0)
        rightConstraint.priority = UILayoutPriority(1.0)

        self.superview?.addConstraints([
            topConstraint, leftConstraint, rightConstraint
        ])
    }

    ...
}

  • У меня также есть CALayer, который добавляется как SubLayer UITextField, который я вызываю из ViewController после появления представления
class FormTextField: UITextField {
    func addBottomBorder(color: CGColor? = UIColor(red: 0.78, green: 0.78, blue: 0.78, alpha: 1.0).cgColor) {
        removeBottomBorder() { _ in
            let border = CALayer()
            let width = CGFloat(2.0)
            border.backgroundColor = color
            border.borderColor = color
            border.frame = CGRect(x: 0, y: self.frame.size.height - width, width: self.frame.size.width, height: width)
            border.borderWidth = width
            border.accessibilityValue = "bottomBorder"

            self.layer.addSublayer(border)
        }
    }
}

class AViewController: UIViewController {

    @IBOutlet weak var exampleTextField: FormTextField!

    override func viewDidAppear(_ animated: Bool) {
        exampleTextField.addBottomBorder
        self.view.setNeedsLayout()
        self.layoutIfNeeded()

        super.viewDidAppear(animated)
    }

    ...
}

Я вижу 3 разных результата в 3 разных представлениях, хотя все они настроены одинаково. Архитектура представления идет: View -> ScrollView -> View -> FormTextField. Во всех представлениях текстовое поле имеет начальное ограничение пространства для своего суперпредставления, равное 32, и конечное ограничение пространства для его суперпредставления, равное 32.

Теперь вот несоответствия, которые я вижу:

1) Один вид выглядит отлично и все выглядит точно так, как должно. Нижняя граница охватывает ширину фактического текстового поля, а с левой стороны появляется метка ошибки.

enter image description here

2) Другой вид является частично правильным. Нижняя граница охватывает ширину фактического текстового поля, но вместо левой стороны появляется метка ошибки.

enter image description here

3) Последний взгляд с ним совершенно не прав. Нижняя граница охватывает только часть текстового поля (кажется, что она корректируется по ширине устройства, используемого в раскадровке, но выглядит некорректно при прямом эфире на iPhone с большим экраном), а метка ошибки отображается справа вместо левой тоже.

enter image description here

enter image description here

Я проверял снова и снова снова и не могу найти единственную разницу в способах, которыми я их реализовал. Все они имеют одинаковые ограничения для своего суперпредставления, addBottomBorder вызывается в viewDidAppear во всех трех различных контроллерах представления и т. Д. c.

Я предполагаю, что это как-то связано с ограничениями макета на UITextField и, возможно, странное состояние гонки во время инициализации, но я заблудился. Что я делаю неправильно, что приводит к противоречивым результатам?

1 Ответ

0 голосов
/ 13 марта 2020

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

extension UIView {

    func anchors (top:NSLayoutYAxisAnchor? , leading:NSLayoutXAxisAnchor? , bottom : NSLayoutYAxisAnchor? , trailing: NSLayoutXAxisAnchor? , padding : UIEdgeInsets = .zero){

        translatesAutoresizingMaskIntoConstraints = false

        if let top = top {
            topAnchor.constraint(equalTo: top , constant: padding.top).isActive = true
        }
        if let leading = leading {
            leadingAnchor.constraint(equalTo: leading , constant: padding.left).isActive = true
        }
        if let bottom = bottom {
            bottomAnchor.constraint(equalTo: bottom , constant: -padding.bottom).isActive = true
        }
        if let trailing = trailing {
            trailingAnchor.constraint(equalTo: trailing , constant: -padding.right).isActive = true
        }
    }
}

Надеюсь, это поможет :)

...