// // TextFieldErrorView.swift // WOKA // // Created by MacBook Pro on 29/04/24. // import UIKit //private var rightViews = NSMapTable(keyOptions: NSPointerFunctions.Options.weakMemory, valueOptions: NSPointerFunctions.Options.strongMemory) 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) { // Remove message guard string != nil else { 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: -20).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.heightAnchor.constraint(equalToConstant: 30).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 } // Add container to superview if let rootView = UIApplication.shared.windows.first(where: { $0.isKeyWindow }) { rootView.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 } // Save view with error message errorViews.setObject(container, forKey: self) } // // Show error message // @IBAction // func errorAction(_ sender: Any) { // let errorButton = sender as! UIButton // let textField = errorButton.superview as! UITextField // // let errorView = errorViews.object(forKey: textField) // if let errorView = errorView { // errorView.isHidden.toggle() // } // // let enumerator = errorViews.objectEnumerator() // while let view = enumerator!.nextObject() as! UIView? { // if view != errorView { // view.isHidden = true // } // } // // // Don't hide keyboard after click by icon // // UIViewController.isCatchTappedAround = false // } } class TriangleTop: UIView { override init(frame: CGRect) { super.init(frame: frame) } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } override func draw(_ rect: CGRect) { guard let context = UIGraphicsGetCurrentContext() else { return } context.beginPath() context.move(to: CGPoint(x: (rect.maxX / 2.0), y: rect.minY)) context.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY)) context.addLine(to: CGPoint(x: (rect.minX / 2.0), y: rect.maxY)) context.closePath() context.setFillColor(UIColor.red.cgColor) context.fillPath() } }