I have a custom UITextField that I use in multiple places, but am having a strange issue with it's constraints on only a few of the pages I use it. The custom class has a few things I add upon initialization:
awakeFromNib
function executesclass 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
])
}
...
}
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)
}
...
}
I'm seeing 3 different results on 3 different views even though all of them are set up exactly the same. The view architecture goes: View -> ScrollView -> View -> FormTextField
. In all of the views, the textfield has a leading space constraint to its super view equalling 32, and a trailing space constraint to its super view equalling 32.
Now here are the inconsistencies I'm seeing:
1) One view looks perfectly fine and everything looks exactly as it should. The bottom border spans the width of the actual textfield, and the error label appears on the left side.
2) Another view is partially correct. The bottom border spans the width of the actual textfield, but the error label appears on the right side instead of the left side.
3) The last view with it is completely wrong. The bottom border only spans a part of the textfield (it appears to correct for width of the device used in the storyboard, but looks incorrect when live on an iPhone with a larger screen), and the error label appears on the right side instead of the left as well.
I've checked over and over again and can't find a single difference in the ways I've implemented them. They all have the same constraints to their superview, addBottomBorder
is called in viewDidAppear
in all three different view controllers, etc.
My guess is that this has something to do with the layout constraints on the UITextField and possibly a weird race condition during the initialization, but I'm lost. What am I doing incorrectly that is resulting in inconsistent results?
I also think it's about setting your constrains, I recommend re doing it using the below function:
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
}
}
}
Hope it helps :)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.