截至目前,我想选择退出iOS 11提供的新选项,即在应用中建议密码。当我在iOS 11上运行应用程序时,我在键盘顶部获得了自动填充选项,我的用户名和密码文本字段甚至都不显示。
所以,我的问题是,如何一起禁用新密码自动填充功能,以便键盘上的键完全不显示,整体行为与iOS 11之前的相同?
答案 0 :(得分:52)
iOS 11& 12 - Swift 4.2 (更新):
if #available(iOS 12, *) {
// iOS 12: Not the best solution, but it works.
passwordTextField.textContentType = .oneTimeCode
} else {
// iOS 11: Disables the autofill accessory view.
// For more information see the explanation below.
emailTextField.textContentType = .init(rawValue: "")
passwordTextField.textContentType = .init(rawValue: "")
}
iOS 11 说明:
确保您设置了所有UITextField
个对象。
如果您有一个UITextField
对象,其中用户必须输入他的电子邮件地址,另一个用户必须输入密码才能将UITextContentType("")
分配给他们的textContentType
属性。否则它将无法工作,仍会显示自动填充附件视图。
答案 1 :(得分:9)
iOS 12 似乎也可以通过isSecureTextEntry
属性识别密码文本字段,而不仅仅是通过textContentType
属性识别密码文本字段,因此,除非双方都设置,否则实际上不可能使此附件视图消失将textContentType设置为空,并删除secureEntry功能(并在您的应用程序中引起安全漏洞),该功能随后阻止iOS 12将textField识别为密码textField并显示此烦人的附件视图。
在我的情况下,该附件导致了一个错误,该错误导致我的应用在点击时无法响应(这也导致我的应用在应用审核过程中被拒绝)。因此,我不得不删除此功能。我不想放弃此安全功能,因此不得不自己解决问题。
这个想法是删除secureEntry功能,但您自己手动添加它。它确实起作用了:
可以这样做:
快速4种方式:
首先,如此处回答,将textContentType
设置为空:
if #available(iOS 10.0, *) {
passwordText.textContentType = UITextContentType("")
emailText.textContentType = UITextContentType("")
}
然后,声明一个String变量,该变量稍后将包含我们的textField实际内容:
var passwordValue = ""
在passwordTextField中添加一个目标,每次textField内容更改时都会调用该目标:
passwordText.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged)
现在这就是魔术,声明将处理文本替换的函数:
@objc func textFieldDidChange(_ textField: UITextField) {
if textField.text!.count > 1 {
// User did copy & paste
if passwordValue.count == 0 { // Pasted into an empty textField
passwordValue = String(textField.text!)
} else { // Pasted to a non empty textField
passwordValue += textField.text!.substring(from: passwordValue.count)
}
} else {
// User did input by keypad
if textField.text!.count > passwordValue.count { // Added chars
passwordValue += String(textField.text!.last!)
} else if textField.text!.count < passwordValue.count { // Removed chars
passwordValue = String(passwordValue.dropLast())
}
}
self.passwordText.text = String(repeating: "•", count: self.passwordText.text!.count)
}
最后,将textField的autocorrectionType
设置为.no
以删除预测性文本:
passwordText.autocorrectionType = .no
就这样,使用passwordValue
执行登录。
希望它会帮助某人。
更新
它也捕获粘贴的值,忘记了以前添加它。
答案 2 :(得分:8)
可以通过指定既不是用户名也不是密码的内容类型来禁用该功能。例如,如果用户应输入电子邮件地址,则可以使用
usernameTextField?.textContentType = .emailAddress
答案 3 :(得分:8)
您可以像这样添加UITextContentType的扩展名
extension UITextContentType {
public static let unspecified = UITextContentType("unspecified")
}
之后,你可以使用它
if #available(iOS 10.0, *) {
passwordField.textContentType = .unspecified
}
答案 4 :(得分:6)
ios11中的一个非常简单的方法对我有用。假设您的iboutlet是usernametextfield和passwordtextfield。在viewcontroller的viewDidLoad()函数中,使用以下代码
usernametextfield.textContentType = UITextContentType("")
passwordtextfield.textContentType = UITextContentType("")
在此之后,当您点按文本字段时,您将看不到自动填充附件选项。
答案 5 :(得分:5)
Objective-C
if (@available(iOS 10, *)){
self.tfEmail.textContentType = @"";
self.tfPassword.textContentType = @"";
}
这对我有用。
答案 6 :(得分:3)
默认情况下,为用户启用自动填充功能。 iOS会将所有密码保存在钥匙串中,并使其在应用程序的键盘中可用。 UITextView
和UITextField
会自动考虑使用自动填充密码。您可以通过指定既不是用户名也不是密码的内容类型来禁用,但如果内容类型信息已经存储在钥匙串中,它将显示在快速栏中。最好分配空的UITextContentType
类型,它不会显示快速栏。
示例:
if #available(iOS 10.0, *) {
self.textField.textContentType = UITextContentType("")
} else {
// Fallback on earlier versions
}
答案 7 :(得分:2)
在此主题中发生的疯狂工作人员。我在没有iOS的情况下向我提出密码,但只给我自动填充了电子邮件。就算有人需要它。经过不同的组合和不同类型的textContentType
,我已经按需完成了。
使用此代码可以正常工作。有email
或username
都没关系,它将使您根据自己的需求提出建议。因此,我禁用了附件自动填充视图,只在键盘的工具栏上保留了自动填充。
self.passwordField.isSecureTextEntry = true
if #available(iOS 11.0, *) {
self.emailField.textContentType = .username
self.emailField.keyboardType = .emailAddress
}
if #available(iOS 12.0, *) {
self.passwordField.textContentType = .password
self.passwordField.keyboardType = .default
}
答案 8 :(得分:2)
目标C版:
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"10.0")) {
self.passwordTextField.textContentType = @"";
self.confirmPasswordTextField.textContentType = @"";
}
,其中
#define SYSTEM_VERSION_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame)
#define SYSTEM_VERSION_GREATER_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending)
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedDescending)
答案 9 :(得分:1)
self.passwordTextField.autocorrectionType = NO;
它似乎不起作用,钥匙串标志仍在那里,
self.passwordTextField.textContentType = UITextContentTypeName;
上面的代码确实有效,但是如果用户设置了他们的Apple ID帐户,那么,通过将autocorrectionType设置为No,键盘上将显示苹果ID的名称,不能将其禁用,不确定Apple是否仍在提炼这个自动填充功能,现在很烦人。
答案 10 :(得分:1)
据我所知,Bem的答案在iOS 12中不起作用,Gal Shahar的答案无法解决某些极端情况(例如,如果用户一次删除多个字符)。我使用IBAction来解决此问题,因此完全不必检查iOS版本。我只是一个初学者,所以这可能不是“最佳”答案或最有效的答案,但这对我来说最有意义:
首先,取消选中情节提要中的“安全文本输入”,或通过密码UITextField将其设置为“ false” /“ NO”。这样可以防止iOS尝试自动填充。
然后,将您的密码UITextField链接到IBAction。我的电话是:
我编写的IBAction函数确定用户的起始密码与输入到密码UITextField中的密码之间的差异,并根据以下信息创建新密码:
class Login: UIViewController {
var password = ""
override func viewDidLoad() { super.viewDidLoad() }
@IBAction func editPasswordField(_ sender: UITextField) {
var input = Array(sender.text ?? "")
var oldPassword = Array(password)
var newPassword = Array("")
//if character(s) are simply deleted from "passwordField" (not replaced or added to), "cursorPosition" is used to determine which corresponding character(s) need to also be removed from "oldPassword"
//this is indicated by "input" comprising of only "•" (bullets) and being shorter in length than "oldPassword"
var onlyBullets = true
for char in input { if char != "•" { onlyBullets = false } }
if onlyBullets && input.count < oldPassword.count {
if let selectedRange = sender.selectedTextRange {
let cursorPosition = sender.offset(from: sender.beginningOfDocument, to: selectedRange.start)
let prefix = String(oldPassword.prefix(cursorPosition))
let suffix = String(oldPassword.suffix(input.count - cursorPosition))
input = Array(prefix + suffix)
} else { input = Array("") }
}
//if no changes were made via input, input would comprise solely of a number of bullets equal to the length of "oldPassword"
//therefore, the number of changes made to "oldPassword" via "input" can be measured with "bulletDifference" by calculating the number of characters in "input" that are NOT bullets
var bulletDifference = oldPassword.count
for char in input { if char == "•" { bulletDifference -= 1 } }
//the only way "bulletDifference" can be less than 0 is if a user copy-pasted a bullet into "input", which cannot be allowed because it breaks this function
//if a user pastes bullet(s) into "input", "input" is deleted
//an edge case not accounted for is pasting a mix of characters and bullets (i.e. "ex•mple") when "oldPassword.count" exceeds the number of bullets in the mixed input, but this does not cause crashes and therefore is not worth preventing
if bulletDifference < 0 {
bulletDifference = oldPassword.count
input = Array("")
}
//"bulletDifference" is used to remove every character from "oldPassword" that corresponds with a character in "input" that has been changed
//a changed character in "input" is indicated by the fact that it is not a bullet
//once "bulletDifference" equals the number of bullets deleted, this loop ends
var bulletsDeleted = 0
for i in 0..<input.count {
if bulletsDeleted == bulletDifference { break }
if input[i] != "•" {
oldPassword.remove(at: i - bulletsDeleted)
bulletsDeleted += 1
}
}
//what remains of "oldPassword" is used to substitute bullets in "input" for appropriate characters to create "newPassword"
//for example, if "oldPassword" is "AcbDE" and "input" is "•bc••", then "oldPassword" will get truncated to "ADE" and "newPassword" will equal "A" + "bc" + "DE", or "AbcDE"
var i = 0
for char in input {
if char == "•" {
newPassword.append(oldPassword[i])
i += 1
} else { newPassword.append(char) }
}
password = String(newPassword)
//"passwordField.text" is then converted into a string of bullets equal to the length of the new password to ensure password security in the UI
sender.text = String(repeating: "•", count: password.count)
}
}
赞赏建设性批评!
答案 11 :(得分:1)
这适用于ios 12和10:
else if(contractReferenceNumber != null) {
String alphanumeric = "^([0-9]|[a-z])+([0-9a-z]+)$";
Pattern pattern = Pattern.compile(alphanumeric);
Matcher matcher = pattern.matcher(contractReferenceNumber);
if(matcher.matches()) {
System.out.println("The reference number is alphanumeric");
}
else {
log.warn("Please enter valid reference number");
return ResponseEntity.badRequest().body(ciCustContractHdrDto);
}
}
答案 12 :(得分:1)
您可以通过在密码文本字段中指定虚拟textContentType
来“关闭”用户名/密码组合检测。
passwordFormField.textContentType = UITextContentType("dummy")
这会关闭密码字段和其前面的电子邮件字段的键符号,这样您就不会使用其中一个预定义值,并且可以避免在键盘附件视图中显示不相关的建议。
答案 13 :(得分:1)
你可以在这里尝试不同的答案,总结它可能删除accessoryview。但这留下了一些错误。
How to hide inputAccessoryView without dismissing keyboard
您可以尝试实现自定义键盘,仅用于密码字段。还尝试禁用文本字段的建议,我认为这也隐藏了accessoryView。
编辑: 苹果论坛在同一问题上尚无答案。此外,我在官方uitextfield文档中找不到任何相关内容。
答案 14 :(得分:0)
响应@Gal Shahar答案。
iOS 12 通过isSecureTextEntry
属性识别密码文本字段,而不仅仅是textContentType
属性。
绕过自动填充建议的方法。
isSecureTextEntry
属性设置为false。 self.passwordTextField.secureTextEntry = NO;
isSecureTextEntry
属性。- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
if (textField == self.passwordTextField && !self.passwordTextField.secureTextEntry) {
self.passwordTextField.secureTextEntry = YES;
}
return YES;
}
注意:-
不不要使用shouldBeginEditing
UITextField委托方法,它将仍然显示自动填充建议。
不不要使用textFieldDidChange
UITextField委托方法,它将自动删除第一个字符,因为它将在显示第一个字符后发生。 “ secureTextEntry”将清空该字段。
答案 15 :(得分:0)
我认为将所有形式的UITextField textContentType设置为UITextContentType("")
或.oneTimeCode
并不是一个干净的解决方案。启用/禁用isSecureTextEntry
仍然会给您带来同样的问题。
@Gal Shahar的回答很好,但仍然不够完美。掩码的字符与来自Apple的安全条目文本中使用的掩码的字符不同。它应该使用Unicode字符'BLACK CIRCLE'(U + 25CF)https://www.fileformat.info/info/unicode/char/25cf/index.htm
此外,它不处理光标移动。在中间插入文本时,它将光标位置移动到文本的末尾。选择和替换文本时,它将给您错误的值。
当您决定使用自定义isSecureEntryText来避免自动填充密码时,下面是代码:
Swift 5(简单版)
@IBOutlet weak var passwordTextField: UITextField!
var maskedPasswordChar: String = "●"
var passwordText: String = ""
var isSecureTextEntry: Bool = true {
didSet {
let selectedTextRange = passwordTextField.selectedTextRange
passwordTextField.text = isSecureTextEntry ? String(repeating: maskedPasswordChar, count: passwordText.count) : passwordText
passwordTextField.selectedTextRange = selectedTextRange
}
}
//this is UITextFieldDelegate
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if textField == passwordTextField {
//update password string
if let swiftRange = Range(range, in: passwordText) {
passwordText = passwordText.replacingCharacters(in: swiftRange, with: string)
} else {
passwordText = string
}
//replace textField text with masked password char
textField.text = isSecureTextEntry ? String(repeating: maskedPasswordChar, count: passwordText.count) : passwordText
//handle cursor movement
if let newPosition = textField.position(from: textField.beginningOfDocument, offset: range.location + string.utf16.count) {
textField.selectedTextRange = textField.textRange(from: newPosition, to: newPosition)
}
return false
}
return true
}
Swift 5(具有保护最后一个char动画的完整版本)
private struct Constants {
static let SecuringLastCharPasswordDelay = 1.5
}
@IBOutlet weak var passwordTextField: UITextField!
private var secureTextAnimationQueue: [String] = []
var maskedPasswordChar: String = "●"
var passwordText: String = ""
var isSecureTextEntry: Bool = true {
didSet {
secureTextAnimationQueue.removeAll()
let selectedTextRange = passwordTextField.selectedTextRange
passwordTextField.text = isSecureTextEntry ? String(repeating: maskedPasswordChar, count: passwordText.count) : passwordText
passwordTextField.selectedTextRange = selectedTextRange
}
}
//this is UITextFieldDelegate
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if textField == passwordTextField {
//update password string
if let swiftRange = Range(range, in: passwordText) {
passwordText = passwordText.replacingCharacters(in: swiftRange, with: string)
} else {
passwordText = string
}
//replace textField text with masked password char
updateTextFieldString(textField, shouldChangeCharactersIn: range, replacementString: string)
//handle cursor movement
if let newPosition = textField.position(from: textField.beginningOfDocument, offset: range.location + string.utf16.count) {
textField.selectedTextRange = textField.textRange(from: newPosition, to: newPosition)
}
return false
}
return true
}
private func updateTextFieldString(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) {
if isSecureTextEntry {
if string.count == .one, let text = textField.text {
let maskedText = String(repeating: maskedPasswordChar, count: text.count)
var newMaskedText = String()
if let swiftRange = Range(range, in: maskedText) {
newMaskedText = maskedText.replacingCharacters(in: swiftRange, with: string)
} else {
newMaskedText = text + maskedText
}
textField.text = newMaskedText
secureTextAnimationQueue.append(string)
asyncWorker.asyncAfter(deadline: .now() + Constants.SecuringLastCharPasswordDelay) { [weak self] in
self?.securingLastPasswordChar()
}
} else {
secureTextAnimationQueue.removeAll()
textField.text = String(repeating: maskedPasswordChar, count: passwordText.count)
}
} else {
textField.text = passwordText
}
}
private func securingLastPasswordChar() {
guard secureTextAnimationQueue.count > .zero, isSecureTextEntry else { return }
secureTextAnimationQueue.removeFirst()
if secureTextAnimationQueue.count == .zero {
let selectedTextRange = passwordTextField.selectedTextRange
passwordTextField.text = String(repeating: maskedPasswordChar, count: passwordText.count)
passwordTextField.selectedTextRange = selectedTextRange
}
}
答案 16 :(得分:0)
我已附上屏幕截图。您可以在情节提要中将内容类型更改为用户名,也可以通过编程方式进行。 您可以为UITextfield创建扩展。
func diableAutofill() {
self.autocorrectionType = .no
if #available(iOS 11.0, *) {
self.textContentType = .username
} else {
self.textContentType = .init("")
}
}
答案 17 :(得分:0)
感谢Apple,当isSecureTextEntry设置为YES时,本机方法找不到任何方法。 Gal Shahar的方法是禁用密码自动填充附件视图选项的唯一解决方案。
客观目标
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
迅速
textField(_:shouldChangeCharactersIn:replacementString:)
委托。并使用这样的简单代码。声明一个String变量,该变量稍后将包含我们的textField实际内容,我的是pswd。
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
//Thanks iOS13!!!
if(!_pswd)
{
_pswd = @"";
}
_pswd = [_pswd stringByReplacingCharactersInRange:range withString:string];
if (!buttonShowPassword.selected)
{
textField.text = [@"" stringByPaddingToLength:_pswd.length withString: @"•" startingAtIndex:0];
}
else
{
textField.text = _pswd;
}
return NO;
}
答案 18 :(得分:0)
对于SwiftUI,请执行以下操作:
SecureField("Password", text: "some text").disableAutocorrection(true)
答案 19 :(得分:0)
答案 20 :(得分:0)
将文本字段内容类型更改为
对象 C
if (@available(iOS 12.0, *)) {
self.curresntPasswordTxField.textContentType = UITextContentTypeOneTimeCode;
} else {
// Fallback on earlier versions
}
迅捷
self.curresntPasswordTxField.textContentType = .oneTimeCode
答案 21 :(得分:-1)
这对我有用:
注意:尝试将此代码放在密码,密码确认(如果适用)和电子邮件文本字段上。我没有将其放在电子邮件文本字段中,并且仍然弹出两个密码字段。
if #available(iOS 12, *) {
// iOS 12: Not the best solution, but it works.
cell.textField.textContentType = .oneTimeCode
} else {
// iOS 11: Disables the autofill accessory view.
cell.textField.textContentType = .init(rawValue: "")
}