У меня есть следующее расширение
private var rightViews = NSMapTable(keyOptions: NSPointerFunctions.Options.weakMemory, valueOptions: NSPointerFunctions.Options.strongMemory)
private var errorViews = NSMapTable(keyOptions: NSPointerFunctions.Options.weakMemory, valueOptions: NSPointerFunctions.Options.strongMemory)
extension UITextField {
// Add/remove error message
func setError(_ string: String? = nil, show: Bool = true) {
if let rightView = rightView, rightView.tag != 999 {
rightViews.setObject(rightView, forKey: self)
}
// Remove message
guard string != nil else {
if let rightView = rightViews.object(forKey: self) {
self.rightView = rightView
rightViews.removeObject(forKey: self)
} else {
self.rightView = nil
}
if let errorView = errorViews.object(forKey: self) {
errorView.isHidden = true
errorViews.removeObject(forKey: self)
}
return
}
// Create container
let container = UIView()
container.translatesAutoresizingMaskIntoConstraints = false
// Create triangle
let triagle = TriangleTop()
triagle.backgroundColor = .clear
triagle.translatesAutoresizingMaskIntoConstraints = false
container.addSubview(triagle)
// Create red line
let line = UIView()
line.backgroundColor = .red
line.translatesAutoresizingMaskIntoConstraints = false
container.addSubview(line)
// Create message
let label = UILabel()
label.text = string
label.textColor = .white
label.numberOfLines = 0
label.font = UIFont.systemFont(ofSize: 15)
label.backgroundColor = .black
label.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 250), for: .horizontal)
label.translatesAutoresizingMaskIntoConstraints = false
container.addSubview(label)
// Set constraints for triangle
triagle.heightAnchor.constraint(equalToConstant: 10).isActive = true
triagle.widthAnchor.constraint(equalToConstant: 15).isActive = true
triagle.topAnchor.constraint(equalTo: container.topAnchor, constant: -10).isActive = true
triagle.trailingAnchor.constraint(equalTo: container.trailingAnchor, constant: -15).isActive = true
// Set constraints for line
line.heightAnchor.constraint(equalToConstant: 3).isActive = true
line.topAnchor.constraint(equalTo: triagle.bottomAnchor, constant: 0).isActive = true
line.leadingAnchor.constraint(equalTo: container.leadingAnchor, constant: 0).isActive = true
line.trailingAnchor.constraint(equalTo: container.trailingAnchor, constant: 0).isActive = true
// Set constraints for label
label.topAnchor.constraint(equalTo: line.bottomAnchor, constant: 0).isActive = true
label.bottomAnchor.constraint(equalTo: container.bottomAnchor, constant: 0).isActive = true
label.leadingAnchor.constraint(equalTo: container.leadingAnchor, constant: 0).isActive = true
label.trailingAnchor.constraint(equalTo: container.trailingAnchor, constant: 0).isActive = true
if !show {
container.isHidden = true
}
// superview!.superview!.addSubview(container)
// UIApplication.shared.keyWindow!.addSubview(container)
self.addSubview(container)
// Set constraints for container
container.widthAnchor.constraint(lessThanOrEqualTo: superview!.widthAnchor, multiplier: 1).isActive = true
container.trailingAnchor.constraint(equalTo: superview!.trailingAnchor, constant: 0).isActive = true
container.topAnchor.constraint(equalTo: superview!.bottomAnchor, constant: 0).isActive = true
// Hide other error messages
let enumerator = errorViews.objectEnumerator()
while let view = enumerator!.nextObject() as! UIView? {
view.isHidden = true
}
// Add right button to textField
let errorButton = UIButton(type: .custom)
errorButton.tag = 999
errorButton.setImage(UIImage(named: "ic_error"), for: .normal)
errorButton.frame = CGRect(x: 0, y: 0, width: frame.size.height, height: frame.size.height)
errorButton.addTarget(self, action: #selector(errorAction), for: .touchUpInside)
rightView = errorButton
rightViewMode = .always
// Save view with error message
errorViews.setObject(container, forKey: self)
}
Которая производит меня
Который размещает это мне в конце вида, как возможно оценивать
то, что я желаю, состоит в том, чтобы мочь оставлять каждую ошибку внизу каждого ящика envez помещения этого в последнее view
Что эта проблема здесь
self.addSubview(container)
Поскольку я мог бы изменять этот extesion для того, чтобы я разместился под каждым ящиком envez размещения под view, с уже gracais
Было бы лучше, чтобы ты сделал custom class для твоего TextField, но, таким образом, ты servirГЎ, только помни, что, когда ты применишь constraints добавлять padding 15 к top предварительного textfield.
import UIKit
import PlaygroundSupport
extension UITextField {
func removeError () {
self.layer.sublayers?.removeAll()
}
func setError(_ title : String) {
setupErrorLayout()
guard let label = self.subviews.first(where: { [110] is UILabel }) else { return }
(label as? UILabel)?.text = title
}
func setupErrorLayout() {
setupUnderline()
setupTriangle()
setupLabel()
}
func setupUnderline() {
let bottomLine = CALayer()
bottomLine.frame = CGRect.init(x: 0, y: frame.height + 2, width: frame.width, height: 1)
bottomLine.backgroundColor = UIColor.red.cgColor
self.borderStyle = .none
self.layer.addSublayer(bottomLine)
}
func setupTriangle() {
let bounds = CGRect.init(x: frame.width, y: frame.height + 3, width: 10, height: 10)
let rad = bounds.size.width / 2
let aSide = rad * sqrt(rad / 2) / 2
let bSide = rad / 2
let bezierPath = UIBezierPath()
bezierPath.move(to: CGPoint.init(x: 0, y: -rad))
bezierPath.addLine(to: CGPoint.init(x: aSide, y: bSide))
bezierPath.addLine(to: CGPoint.init(x: -aSide, y: bSide))
bezierPath.close()
let triangle = CAShapeLayer()
triangle.path = bezierPath.cgPath
triangle.backgroundColor = UIColor.red.cgColor
triangle.fillColor = UIColor.red.cgColor
triangle.frame.origin = CGPoint(x: frame.width - rad, y: frame.height)
self.layer.addSublayer(triangle)
}
func setupLabel() {
let label = UILabel(frame: CGRect.init(x: 0, y: frame.height + 10, width: frame.width, height: 7))
label.text = ""
label.font = UIFont.systemFont(ofSize: 8.0)
label.textAlignment = .right
self.addSubview(label)
}
}
class MyViewController : UIViewController {
let textField = UITextField(frame: CGRect.init(x: 50, y: 50, width: 300, height: 50))
override func loadView() {
let view = UIView()
view.backgroundColor = .white
textField.backgroundColor = .lightGray
textField.text = "Some text to evaluate"
let set = UIButton(frame: CGRect.init(x: 0, y: 200, width: 100, height: 100))
set.addTarget(self, action: #selector(setAction(_:)), for: .touchUpInside)
set.backgroundColor = .green
let unset = UIButton(frame: CGRect.init(x: 150, y: 200, width: 100, height: 100))
unset.addTarget(self, action: #selector(unsetAction(_:)), for: .touchUpInside)
unset.backgroundColor = .red
view.addSubview(textField)
view.addSubview(set)
view.addSubview(unset)
self.view = view
}
@objc func setAction(_ sender: Any) {
textField.setError("Tienes algunos errores")
}
@objc func unsetAction(_ sender: Any) {
textField.removeError()
}
}
// Present the view controller in the Live View window
PlaygroundPage.current.liveView = MyViewController()