iOS 11 wyłączyć opcję automatycznego uzupełniania hasła w widoku akcesoriów?

83

Na razie chciałbym zrezygnować z nowej opcji, którą daje iOS 11, czyli sugerowania haseł w aplikacji. Kiedy uruchamiam aplikację na iOS 11, dostaję opcję autouzupełniania na górze klawiatury, a moja nazwa użytkownika i pole tekstowe hasła nawet się nie pojawiają.

Moje pytanie brzmi: jak mogę wyłączyć nową funkcję autouzupełniania hasła, aby klawisz na klawiaturze nie był w ogóle wyświetlany, a ogólne zachowanie jest takie samo jak w przypadku wersji przed iOS 11?

wprowadź opis obrazu tutaj

zumzum
źródło
Spróbuj ustawić właściwość pola nazwy użytkownika i hasła textContentTypena .textContentType- Powinno to powiedzieć iOS 11, że twoje pola nie są polami nazwy użytkownika / hasła (mimo że są) i uniemożliwić wyświetlenie widoku akcesoriów; Coś w rodzaju `self.passwordField.textContentType = .textContentType`
Paulw11
@zumzum czy masz jakieś rozwiązanie. udostępnij
Nazmul Hasan
2
Dla mnie to też jest problem. Funkcja autouzupełniania pojawia się w polach rejestracji, co nie jest pożądane. Chciałbym, żeby byli tylko na polach do logowania. Dziwne rzeczy.
Brad Root,
2
Wygląda na to, że na iOS12 pojawia się ponownie. Jak to rozwiązałeś?
dolar2048
W iOS12 nadal się pojawia. Masz jakiś pomysł ?
Emrah Akgül

Odpowiedzi:

80

iOS 11 i 12 i 13 - Swift 4.2 i 5 (zaktualizowane):

if #available(iOS 12, *) {
    // iOS 12 & 13: 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: "")
}

Wyjaśnienie iOS 11 :

Upewnij się, że skonfigurowałeś wszystkie UITextFieldobiekty w ten sposób.

Jeśli masz na przykład UITextFieldobiekt, w którym użytkownik musi wprowadzić swój adres e-mail i inny, w którym użytkownik musi wprowadzić swoje hasło, przypisz UITextContentType("")do obu swoich textContentTypewłaściwości. W przeciwnym razie nie będzie działać, a widok akcesoriów automatycznego wypełniania będzie nadal wyświetlany.

Baran Emre
źródło
1
Jest dostępny z iOS 10, a nie iOS 11.
matm
@GalShahar Nie mogę tego teraz przetestować, ale oto moja sugestia: iOS 12 wprowadza nowy, UITextContentTypektóry nazywa się newPassword (patrz: developer.apple.com/documentation/uikit/uitextcontenttype/ ... ). Spróbuj ustawić typ zawartości pól tekstowych hasła na ten typ. Wydaje mi się, że iOS nie pokaże wtedy widoku akcesoriów autouzupełniania, ponieważ użytkownik jest zmuszony ustawić nowe hasło i nie używać / uzyskiwać dostępu do hasła, które zostało ustawione wcześniej, za pomocą widoku akcesoriów autouzupełniania. W tej chwili to tylko teoria. Nie jestem pewien, czy to zadziała, ale daj mi znać, czy zadziała!
Baran Emre
Okej, zapomnijcie o tym, co napisałem o iOS 12. Ustawienie UITextContentType na newPasswordnie działa. Wypróbowałem rozwiązanie @GalShahar, ale mi się nie podobało. Zamiast ja ustawienie UITextContentTypesię oneTimeCode . Na razie to działa.
Baran Emre
W przypadku iOS 12 isSecureTextEntryoprócz ustawienia UITextContentTypena oneTimeCode. Możemy ustawić isSecureTextEntrycokolwiek chcemy, gdy zaczną wpisywać pole tekstowe.
da1
@ DA1 Jesteśmy ustawienie .isSecureTextEntryaby trueprzed ustawieniem textContentTypesię .oneTimeCodei działa zgodnie z oczekiwaniami. Nie wiem, jak wygląda Twój kod, ale podczas inicjalizacji pola tekstowego kolejność ustawiania jego właściwości nie jest ważna.
Baran Emre
16

Wygląda na to, że iOS 12 rozpoznaje hasło textFields również po isSecureTextEntrywłaściwości, a nie tylko po textContentTypewłaściwości, więc zniknięcie tego widoku akcesoriów nie jest naprawdę możliwe, chyba że oboje ustawicie textContentType na nic i usuniecie funkcję secureEntry (i spowoduje to lukę bezpieczeństwa w aplikacji) następnie uniemożliwia systemowi iOS 12 rozpoznanie textField jako hasło textField i wyświetlenie tego denerwującego widoku akcesoriów.

W moim przypadku akcesorium spowodowało błąd, który powodował, że moja aplikacja nie odpowiadała po dotknięciu (co również spowodowało odrzucenie mojej aplikacji w procesie przeglądu aplikacji). Musiałem więc usunąć tę funkcję. Nie chciałem rezygnować z tej funkcji bezpieczeństwa, więc musiałem sam rozwiązywać problemy.

Chodzi o to, aby usunąć funkcję secureEntry, ale dodać ją ręcznie. Zadziałało:

wprowadź opis obrazu tutaj


Można to zrobić w ten sposób:

Swift 4-drożny:

Najpierw, zgodnie z odpowiedzią tutaj, ustaw textContentTypena nic:

if #available(iOS 10.0, *) {
    passwordText.textContentType = UITextContentType("")
    emailText.textContentType = UITextContentType("")
}

Następnie zadeklaruj zmienną typu String, która później będzie zawierała prawdziwą zawartość textField:

var passwordValue = ""

Dodaj cel do passwordTextField, który będzie wywoływany za każdym razem, gdy zmieni się zawartość textField:

passwordText.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged)

Teraz właśnie to zrobi magię, zadeklaruj funkcję, która będzie obsługiwać zamiany tekstu:

@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)
}

Wreszcie Set textField to autocorrectionTypeaby .nousunąć tekst predykcyjną:

passwordText.autocorrectionType = .no

To wszystko, użyj, passwordValueaby zalogować się.

Mam nadzieję, że to komuś pomoże.

AKTUALIZACJA

Łapie również wklejone wartości, zapomniałem go wcześniej dodać.

Gal Shahar
źródło
2
Wspaniały! Niezły hack kolego! Szkoda, że ​​iOS sprawia, że ​​hakujemy, zamiast zapewniać czystsze sposoby robienia najbardziej podstawowych rzeczy. To powinna być akceptowana odpowiedź.
sandpat
9

Funkcję można wyłączyć, określając typ zawartości, który nie jest nazwą użytkownika ani hasłem. Na przykład, jeśli użytkownik powinien wprowadzić adres e-mail, możesz użyć

usernameTextField?.textContentType = .emailAddress
gebirgsbärbel
źródło
2
Co ciekawe, nad polem hasła mam pole adresu e-mail, a pole adresu e-mail oferuje automatyczne uzupełnianie.
Brad Root,
1
@BradRoot zmień również swoje pole hasła textContentype! jeśli Twój e-mail jest już zapisany w pęku kluczy, wyświetli informacje na pasku szybkiego dostępu, więc lepiej dla użytkownika .nickname lub wypróbuj ten kod, jeśli #available (iOS 10.0, *) {self.passwordTextField.textContentType = UITextContentType.init (rawValue: " ")} else {// Powrót do wcześniejszych wersji}
Sahil,
8

Możesz dodać rozszerzenie dla UITextContentType w ten sposób

extension UITextContentType {
    public static let unspecified = UITextContentType("unspecified")
}

potem możesz go użyć

if #available(iOS 10.0, *) {
    passwordField.textContentType = .unspecified
}
Michaił Zinow
źródło
7

w odpowiedzi na @Gal Shahar Answer.

iOS 12 rozpoznaje hasła textFields według isSecureTextEntrywłaściwości, a nie tylko według textContentTypewłaściwości.

Droga dookoła, aby ominąć sugestię automatycznego wypełniania.

  1. ustaw isSecureTextEntry właściwość na false.

self.passwordTextField.secureTextEntry = NO;

  1. Dodaj metodę delegata UITextField i włącz isSecureTextEntry właściwość.
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    if (textField == self.passwordTextField && !self.passwordTextField.secureTextEntry) {
        self.passwordTextField.secureTextEntry = YES;
    }

    return YES;
}

UWAGA: - NIE używaj shouldBeginEditingmetody delegata UITextField, nadal będzie wyświetlać sugestię automatycznego wypełniania. Czy NIE Zastosowanie textFieldDidChangemetody delegata UITextField Będzie Autousuwanie pierwszy charachter jak będzie to się stało po wyświetleniu pierwszego charachter. „SecureTextEntry” spowoduje opróżnienie pola.

popielaty
źródło
1
To nie tylko rozwiązuje omawiany problem, ale także rozwiązuje problem błędnego odczytania wysokości klawiatury z UIKeyboardWillShowNotification podczas początkowego dotknięcia pola hasła. Świetna odpowiedź.
ekashking
6

Bardzo proste podejście w ios11 zadziałało. Załóżmy, że twoje iboutlets to usernametextfield i passwordtextfield. W funkcji viewDidLoad () kontrolera widoku, która przechowuje oba zewnętrzne, użyj następującego kodu

usernametextfield.textContentType = UITextContentType("")
passwordtextfield.textContentType = UITextContentType("")

Po tym nie zobaczysz opcji automatycznego uzupełniania po dotknięciu pól tekstowych.

Ammad
źródło
5

Cel C

if (@available(iOS 10, *)){
    self.tfEmail.textContentType = @"";
    self.tfPassword.textContentType = @"";
}

To zadziałało dla mnie.

Matheus Domingos
źródło
3

Autouzupełnianie jest domyślnie włączone dla użytkowników. iOS zapisuje wszystkie hasła w pęku kluczy i udostępnia je na klawiaturze w Twoich aplikacjach. UITextViewi UITextFieldautomatycznie uwzględniane jako hasło autouzupełniania. możesz wyłączyć, określając typ zawartości, który nie jest nazwą użytkownika ani hasłem, ale jeśli informacje o typie zawartości są już zapisane w pęku kluczy, zostaną wyświetlone na pasku szybkiego dostępu. więc lepiej przypisać pusty UITextContentTypetyp i nie wyświetli się pasek szybkiego dostępu.

Przykład:

  if #available(iOS 10.0, *) {
  self.textField.textContentType = UITextContentType("")
  } else {
  // Fallback on earlier versions
 }
Sahil
źródło
3

To zadziałało dla iOS 12 i 10:

if (@available(iOS 10, *)) {
    passwordTextField.textContentType = UITextContentTypeStreetAddressLine2;
}

if (@available(iOS 12, *)) {
    passwordTextField.textContentType = UITextContentTypeOneTimeCode;
}
no_fate
źródło
2

Możesz „wyłączyć” wykrywanie kombinacji nazwy użytkownika / hasła, przypisując atrapę textContentTypedo pola tekstowego hasła.

passwordFormField.textContentType = UITextContentType("dummy")

Spowoduje to wyłączenie symbolu klucza zarówno dla pola hasła, jak i pola adresu e-mail, które je poprzedzało, dzięki czemu nie używasz jednej z predefiniowanych wartości i unikasz wyświetlania niepowiązanych sugestii w widoku akcesoriów klawiatury.

Miguel Cabeça
źródło
Czy to nadal działa w przypadku najnowszej wersji beta iOS 12?
pfandrade
Nie. W iOS 12 wykrywa to pole jako nowe pole hasła i sugeruje nowe silne hasło (nowa funkcja iOS 12). W rzeczywistości chcę tego zachowania w moim przypadku, więc newPasswordoznaczam to pole hasła nowym UITextContentType iOS 12 . Nie wiem jednak, jak uniknąć tego nowego zachowania.
Miguel Cabeça
W przypadku iOS 12 beta, jeśli używasz: textContentType = UITextContentType.oneTimeCode. Wtedy nie ma pęku kluczy na klawiaturze. Wydaje się, że działa dobrze dla mnie bez żadnych skutków ubocznych. Jeśli używasz .newPassword, to również działa, ale po zakończeniu z hasłem pojawi się monit o zapisanie hasła.
Daniel Jones,
2

Wersja celu C:

if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"10.0")) {
    self.passwordTextField.textContentType = @"";
    self.confirmPasswordTextField.textContentType = @"";
}

gdzie

#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)
Denis Kutlubaev
źródło
2

Możesz tutaj wypróbować różne odpowiedzi , z których wywnioskować, że prawdopodobnie można usunąć widok akcesoriów. Ale to pozostawia kilka błędów.

Możesz spróbować zaimplementować niestandardową klawiaturę, tylko dla pól haseł. Spróbuj także wyłączyć sugestie dla twojego pola tekstowego, myślę, że to również ukrywa accessoryView.

EDYCJA: Nadal brak odpowiedzi na forach Apple na to samo pytanie. Nie mogłem też znaleźć nic na ten temat w oficjalnej UITextFielddokumentacji .

Rishabh
źródło
2

Szalony personel w tym temacie. Zrobiłem bez iOS, proponując mi hasło, ale dałem mi autouzupełnianie tylko dla e-maili. Tylko jeśli ktoś tego potrzebuje. Po różnych kombinacjach i różnych typach textContentTypezrobiłem to tak, jak chciałem.

  1. Pole tekstowe e-maila z autouzupełnianiem iOS sugeruje coś.
  2. Pole tekstowe Hasło bez systemu iOS proponuje mi nowe hasło, ale uzupełnia je hasłem, jeśli wybiorę je z pola tekstowego e-maila.
  3. Pole tekstowe hasła do bezpiecznego wprowadzania tekstu.

I z tym kodem zadziałało. Nie ma znaczenia, czy masz, emailczy usernameteż zaproponuje Ci to, czego potrzebujesz. Więc wyłączyłem widok autouzupełniania akcesoriów i zostawiłem tylko autouzupełnianie na pasku narzędzi klawiatury.

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
}
Ivan Tkachenko
źródło
1

Z tego, co wiem, odpowiedź Bema nie działa w iOS 12, a odpowiedź Gal Shahar nie uwzględnia niektórych skrajnych przypadków (na przykład, jeśli użytkownik usuwa wiele znaków jednocześnie). Obejrzałem to za pomocą IBAction, eliminując w ten sposób konieczność sprawdzania wersji iOS. Jestem tylko początkującym, więc to może nie być „najlepsza” odpowiedź lub najbardziej wydajna, ale miała dla mnie największy sens:

Najpierw usuń zaznaczenie opcji „Bezpieczne wprowadzanie tekstu” w serii ujęć lub ustaw ją na „fałsz” / „NIE” za pomocą kodu hasła UITextField. Uniemożliwi to systemowi iOS próbę autouzupełniania.

Następnie połącz swoje hasło UITextField z IBAction. Mój jest wezwany:

  • Rozpoczęła się edycja
  • Edycja się zmieniła
  • Edycja się skończyła

Napisana przeze mnie funkcja IBAction określa różnice między hasłem początkowym użytkownika a tym, co zostało wprowadzone do hasła UITextField i tworzy nowe hasło na podstawie tych informacji:

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)
    }
}

Konstruktywna krytyka jest mile widziana!

Escargot
źródło
1

Ok, mogę potwierdzić, że na iOS 14 działają bez problemów:

// once this property is declared, textField.keyboardType does
// not seem to have any effect in showing the autofill

textField.textContentType = UITextContentType.oneTimeCode
textField.keyboardType = UIKeyboardType.emailAddress

UITextField.textContentType

Paul D.
źródło
0
self.passwordTextField.autocorrectionType = NO;

Wygląda na to, że nie działa, znak pęku kluczy wciąż tam jest,

self.passwordTextField.textContentType = UITextContentTypeName;

Powyższy kod działa, ale jeśli użytkownicy skonfigurują swoje konto Apple ID, wtedy nazwa identyfikatora Apple zostanie wyświetlona na klawiaturze, której nie można wyłączyć, ustawiając autocorrectionType na Nie, nie jestem pewien, czy Apple nadal udoskonala tę funkcję autouzupełniania , teraz jest dość wadliwy.

Roger Han
źródło
1
Ten typ „odpowiedzi” powinien być zarezerwowany dla sekcji komentarzy, ponieważ nie zawiera rzeczywistej odpowiedzi ani linku do żadnej dokumentacji referencyjnej firmy Apple itp. Witamy w SO!
stktrc
nie ma jeszcze rozwiązania. Żadne z wymienionych tutaj nie działało dobrze.
zumzum
0

To zadziałało dla mnie:

UWAGA: spróbuj umieścić ten kod w haśle, potwierdzeniu hasła (jeśli dotyczy) ORAZ w polach tekstowych wiadomości e-mail. Nie umieszczałem go w polu tekstowym e-maila i nadal pojawiał się w dwóch polach hasła.

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: "")
}
Paul Lehn
źródło
1
To jest to samo, co odpowiedź Bema.
Eric Aya
0

Myślę, że ustawienie całego tekstu UITextField textContentType w formularzu na UITextContentType("")lub .oneTimeCodenie jest czystym rozwiązaniem. Włącz / wyłączisSecureTextEntry nadal powoduje ten sam problem.

Odpowiedź @Gal Shahar jest ładna, ale nadal nie jest doskonała. Zamaskowany znak nie jest tym samym, co znak zamaskowany, który jest używany w tekście bezpiecznego wprowadzania z Apple. Powinien używać znaku Unicode „BLACK CIRCLE” (U + 25CF) https://www.fileformat.info/info/unicode/char/25cf/index.htm

Nie obsługuje również ruchu kursora. Zmieni pozycję kursora na koniec tekstu podczas wstawiania tekstu w środku. Poda złą wartość podczas wybierania i zastępowania tekstu.

Jeśli zdecydujesz się użyć niestandardowego isSecureEntryText, aby uniknąć autouzupełniania hasła, oto kod:

Swift 5 (wersja prosta)

@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 (KOMPLETNA wersja z zabezpieczeniem animacji ostatniego znaku)

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
    }
}
Sandy Akbar
źródło
0

wprowadź opis obrazu tutaj

Załączam zrzut ekranu. możesz zmienić typ zawartości jako nazwę użytkownika w serii ujęć lub możesz to zrobić programowo. możesz stworzyć rozszerzenie dla UITextfield.

func diableAutofill() {
        self.autocorrectionType = .no
        if #available(iOS 11.0, *) {
            self.textContentType = .username
        } else {
            self.textContentType = .init("")
        }
    }
siddhant
źródło
0

Dzięki Apple nie mogłem znaleźć sposobu na natywne metody, gdy isSecureTextEntry jest ustawione na YES. Sposób Gal Shahara to jedyne rozwiązanie umożliwiające wyłączenie opcji automatycznego uzupełniania hasła w widoku akcesoriów. Ale łatwiej to zrobić

cel C

-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string

szybki

textField(_:shouldChangeCharactersIn:replacementString:)

delegat. I użyj prostego kodu, takiego jak ten. Zadeklaruj zmienną typu String, która później będzie zawierała prawdziwą zawartość textField, moja to 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;
    }
Batuhan Altun
źródło
0

dla SwiftUI wykonaj następujące czynności:

 SecureField("Password", text: "some text").disableAutocorrection(true)
Payam Khaninejad
źródło