在 iOS UITextField 上显示验证错误类似于 Android 的 TextView.setError()
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/30574484/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Displaying validation error on iOS UITextField similar to Android's TextView.setError()
提问by ihsan
Is there a way to show a validation error on a UITextField
which is similar to Android's TextView.setError()
in swift?
有没有办法在UITextField
类似于 Android 的TextView.setError()
swift上显示验证错误?
采纳答案by Shamas S - Reinstate Monica
UITextField
doesn't come with a validation function out of the box. You can find some open source APIs to help you accomplish this. One possible option would be to look into the SSValidationTextFieldapi.
UITextField
没有开箱即用的验证功能。您可以找到一些开源 API 来帮助您完成此任务。一种可能的选择是查看SSValidationTextFieldapi。
Code would be
代码将是
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)
回答by SpanTag
Just sharing something I use often. This is designed to fit for "bottom border only" TextFields. - Because I like them ;) - but can with ease be customized to fit whatever style
只是分享一些我经常使用的东西。这旨在适合“仅底部边框”文本字段。- 因为我喜欢它们 ;) - 但可以轻松定制以适应任何风格
Extension for setting up the text field to only show a single bottom line:
将文本字段设置为仅显示一条底线的扩展:
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
}
}
Then another extension to make it flash red and shake showing that there is a validation error:
然后另一个扩展使其闪烁红色并摇晃显示存在验证错误:
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")
}
}
How to use:
如何使用:
Setup the UITextField to show only bottom border in viewDidLoad:
设置 UITextField 在 viewDidLoad 中只显示底部边框:
override func viewDidLoad() {
myTextField.setBottomBorderOnlyWith(color: UIColor.gray.cgColor)
}
Then when some button is clicked and you do not validate the field:
然后,当单击某个按钮并且您不验证该字段时:
@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)
}
}
回答by Victor Sigler
You can validate the text by setting the UITextField
delegate to your view controller then do something like this :
您可以通过将UITextField
委托设置为您的视图控制器来验证文本,然后执行以下操作:
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
// Your method to validate the input
// self.validateInputText()
return true
}
And you can even change its border color if you want:
如果需要,您甚至可以更改其边框颜色:
textField.layer.borderColor = UIColor.redColor().CGColor
I hope this help you.
我希望这对你有帮助。
回答by Vergiliy
After a day of work, I made an analogue of TextView.setError()
on Swift. Here's what I got:
经过一天的工作,我TextView.setError()
在 Swift 上做了一个类比。这是我得到的:
Code on swift 5:
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()
}
}
How to use:
如何使用:
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 let EMAIL_ADDRESS =
"[a-zA-Z0-9\+\.\_\%\-\+]{1,256}" +
"\@" +
"[a-zA-Z0-9][a-zA-Z0-9\-]{0,64}" +
"(" +
"\." +
"[a-zA-Z0-9][a-zA-Z0-9\-]{0,25}" +
")+"
// Validator e-mail from string
static func isValidEmail(_ value: String) -> Bool {
let string = value.trimmingCharacters(in: .whitespacesAndNewlines)
let predicate = NSPredicate(format: "SELF MATCHES %@", Validator.EMAIL_ADDRESS)
return predicate.evaluate(with: string) || string.isEmpty
}
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
}
}
回答by JayVDiyk
No, you need to
不,你需要
subclass the
UITextField
Create a function that setError, let's call it
func setError()
In that function you can create an
UIImageView
which contains anUIImage
(error image). Set it to the rightView ofUITextField
by usingUITextField.rightView
- Don't forget to set the
UITextField.rightViewMode
to always show
子类
UITextField
创建一个 setError 函数,让我们调用它
func setError()
在该函数中,您可以创建一个
UIImageView
包含UIImage
(错误图像)的。UITextField
通过使用将其设置为 rightViewUITextField.rightView
- 不要忘记设置
UITextField.rightViewMode
为始终显示
EDIT:
编辑:
Alternatively, if you does not prefer subclassing. You could directly set the rightVIew of the UITextField
to an UIImageView
that holds an error image
或者,如果您不喜欢子类化。你可以的了rightVIew直接设置UITextField
成UIImageView
保存错误图像
回答by Midhun MP
No, there is no built in method available for doing the same. For that you need to customize the UITextField
.
不,没有可用于执行相同操作的内置方法。为此,您需要自定义UITextField
.
There are some open-source library available for doing that. You can find one here : US2FormValidator
有一些开源库可用于执行此操作。你可以在这里找到一个:US2FormValidator