Есть ли способ показать ошибку проверки на UITextField
, которая похожа на Android TextView.setError()
в swift?
Отображение ошибки проверки на iOS UITextField, аналогичной Android TextView.setError()
Ответ 1
UITextField
не поставляется с функцией проверки достоверности. Вы можете найти некоторые API-интерфейсы с открытым исходным кодом, чтобы помочь вам в этом. Одним из возможных вариантов было бы изучить SSValidationTextField api.
Код будет
var phoneValidationTextField = SSValidationTextField(frame: CGRectMake(200, 200, 150, 50))
phoneValidationTextField.validityFunction = self.isValidPhone
phoneValidationTextField.delaytime = 0.5
phoneValidationTextField.errorText = "Incorrect Format"
phoneValidationTextField.successText = "Valid Format"
phoneValidationTextField.borderStyle = UITextBorderStyle.RoundedRect
self.addSubview(phoneValidationTextField)
Ответ 2
Просто делюсь чем-то, что я часто использую. Это разработано, чтобы соответствовать "только нижней границе" TextFields. - Потому что они мне нравятся;) - но с легкостью можно настроить под любой стиль
Расширение для настройки текстового поля, чтобы показать только одну нижнюю строку:
extension UITextField {
func setBottomBorderOnlyWith(color: CGColor) {
self.borderStyle = .none
self.layer.masksToBounds = false
self.layer.shadowColor = color
self.layer.shadowOffset = CGSize(width: 0.0, height: 1.0)
self.layer.shadowOpacity = 1.0
self.layer.shadowRadius = 0.0
}
}
Затем еще одно расширение, чтобы оно мигало красным и трясло, показывая, что есть ошибка проверки:
extension UITextField {
func isError(baseColor: CGColor, numberOfShakes shakes: Float, revert: Bool) {
let animation: CABasicAnimation = CABasicAnimation(keyPath: "shadowColor")
animation.fromValue = baseColor
animation.toValue = UIColor.red.cgColor
animation.duration = 0.4
if revert { animation.autoreverses = true } else { animation.autoreverses = false }
self.layer.add(animation, forKey: "")
let shake: CABasicAnimation = CABasicAnimation(keyPath: "position")
shake.duration = 0.07
shake.repeatCount = shakes
if revert { shake.autoreverses = true } else { shake.autoreverses = false }
shake.fromValue = NSValue(cgPoint: CGPoint(x: self.center.x - 10, y: self.center.y))
shake.toValue = NSValue(cgPoint: CGPoint(x: self.center.x + 10, y: self.center.y))
self.layer.add(shake, forKey: "position")
}
}
Как пользоваться:
Настройте UITextField для отображения только нижней границы в viewDidLoad:
override func viewDidLoad() {
myTextField.setBottomBorderOnlyWith(color: UIColor.gray.cgColor)
}
Затем, когда какая-то кнопка нажата, и вы не проверяете поле:
@IBAction func someButtonIsClicked(_ sender: Any) {
if let someValue = myTextField, !name.isEmpty {
// Good To Go!
} else {
myTextField.isError(baseColor: UIColor.gray.cgColor, numberOfShakes: 3, revert: true)
}
}
Ответ 3
Вы можете проверить текст, установив делегат UITextField
в контроллер вашего вида, а затем выполните следующее:
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
// Your method to validate the input
// self.validateInputText()
return true
}
И вы даже можете изменить свой цвет границы, если хотите:
textField.layer.borderColor = UIColor.redColor().CGColor
Надеюсь, это поможет вам.
Ответ 4
Нет, вам нужно
-
подкласс
UITextField
-
Создайте функцию setError, позвоните ей
func setError()
-
В этой функции вы можете создать
UIImageView
, который содержитUIImage
(изображение ошибки). Установите его вправо вUITextField
с помощьюUITextField.rightView
- Не забудьте установить
UITextField.rightViewMode
, чтобы всегда показывать
EDIT:
В качестве альтернативы, если вы не предпочитаете подклассы. Вы можете прямо установить rightVIew UITextField
на UIImageView
, который содержит изображение с ошибкой
Ответ 5
Нет, для этого не существует встроенного метода. Для этого вам нужно настроить UITextField
.
Для этого есть библиотека с открытым исходным кодом. Вы можете найти здесь: US2FormValidator
Ответ 6
После рабочего дня я сделал аналог TextView.setError()
в Swift. Вот что я получил:
Код на Свифте 5:
import UIKit
private var rightViews = NSMapTable<UITextField, UIView>(keyOptions: NSPointerFunctions.Options.weakMemory, valueOptions: NSPointerFunctions.Options.strongMemory)
private var errorViews = NSMapTable<UITextField, UIView>(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)
// 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)
}
// 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()
}
}
Как пользоваться:
class MyViewController: UIViewController {
@IBOutlet weak var emailField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
emailField.delegate = self
}
}
// Validation textFields
extension MyViewController: UITextFieldDelegate {
// Remove error message after start editing
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
textField.setError()
return true
}
// Check error
func textFieldDidBeginEditing(_ textField: UITextField) {
Validator.isValidEmail(field: textField)
}
// Check error
func textFieldDidEndEditing(_ textField: UITextField) {
Validator.isValidEmail(field: textField, show: false)
}
}
class Validator {
static func isValidEmail(field: UITextField, show: Bool = true) -> Bool {
if Validator.isValidEmail(field.text!) {
field.setError()
return true
} else {
field.setError("Error message", show: show)
}
return false
}
}