UITextField zur Währungseingabe

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • UITextField zur Währungseingabe

    Moin zusammen!

    Wieder einmal ein Tipp, falls jemand die gleiche Aufgabe zu lösen hat ... und mit der Bitte um Verbesserungsvorschläge, wenn Ihr welche habt:

    Meine App braucht ein Feld zur Eingabe von Preisen in der aktuellen Währung des Gerätes. Was mir so vorschwebte:
    • Eingaben sollte über eine rein numerische Tastatur ohne Dezimalzeichen erfolgen
    • Die Anzeige wird permanent während der Eingabe aktualisiert und beinhaltet Währungszeichen, Dezimalzeichen und Tausendertrennung
    • Eingaben werden von rechts nach links "durchgeschoben": "1234" ergibt also nacheinander die Werte "0,01 €", "0,12 €", "1,23 €" und "12,34 €".
    • Gelöscht wird auch wieder von rechts
    • Das Ganze muss natürlich robust gegen Fehleingaben, Einfügen aus der Zwischenablage etc. sein
    Ich habe im Web einige Ansätze gefunden, aber alle basierten auf Zeichenketten-Operationen, mit Abhängigkeiten von z. B. den Währungseinstellungen. Mir schwebte ein mathematischer Ansatz vor: Multiplikation / Division mit 10 und entsprechendes Hinzufügen von (potentiellen Nachkomma-) Stellen bzw. Runden. Um Rundungsungenauigkeiten bei Fließkommazahlen zu vermeiden, nutze ich NSDecimal-Funktionen

    C-Quellcode

    1. - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
    2. {
    3. if (textField == self.priceField)
    4. {
    5. // Handle price inputs by overwriting user edity with a currency formated string
    6. NSNumberFormatter *priceFormatter = [[NSNumberFormatter alloc] init];
    7. priceFormatter.numberStyle = NSNumberFormatterCurrencyStyle;
    8. NSNumber *oldPriceNumber = [priceFormatter numberFromString:self.priceField.text];
    9. NSDecimal oldPrice = (oldPriceNumber) ? oldPriceNumber.decimalValue : [NSDecimalNumber zero].decimalValue;
    10. NSDecimal newPrice;
    11. NSDecimalCopy(&newPrice, &oldPrice);
    12. if (string.length > 0)
    13. {
    14. // Check if a number was added, otherwise do nothing
    15. NSCharacterSet *noDigits = [[NSCharacterSet decimalDigitCharacterSet] invertedSet];
    16. if ([string rangeOfCharacterFromSet:noDigits].location == NSNotFound)
    17. {
    18. // Shift the price to the left (multiply by 10) and add the entered digit as the smallest fraction supported by the local currency
    19. NSDecimal enteredValue = [NSDecimalNumber decimalNumberWithString:string].decimalValue;
    20. NSDecimalMultiplyByPowerOf10(&enteredValue, &enteredValue, -priceFormatter.maximumFractionDigits, NSRoundPlain);
    21. NSDecimalMultiplyByPowerOf10(&newPrice, &newPrice, 1, NSRoundPlain);
    22. NSDecimalAdd(&newPrice, &newPrice, &enteredValue, NSRoundPlain);
    23. }
    24. }
    25. else
    26. {
    27. // Backspace, so remove the last digit by shifting the price right (multiply by 0.1), round down to the fraction digits of the local currency
    28. NSDecimalMultiplyByPowerOf10(&newPrice, &newPrice, -1, NSRoundPlain);
    29. NSDecimalRound(&newPrice, &newPrice, priceFormatter.maximumFractionDigits, NSRoundDown);
    30. }
    31. NSDecimalNumber *newPriceNumber = [NSDecimalNumber decimalNumberWithDecimal:newPrice];
    32. self.priceField.text = [priceFormatter stringFromNumber:newPriceNumber];
    33. self.article.price = newPriceNumber;
    34. return NO;
    35. }
    36. return YES;
    37. }
    Alles anzeigen
    Ein ungewünschtes Positionieren des Cursors verhinderte ich durch Setzen der selectedTextRange über eine neue UITextFieldDelegate-Methode von iOS 13 - interessanterweise ist deren Dokumentation leer:

    C-Quellcode

    1. - (void)textFieldDidChangeSelection:(UITextField *)textField
    2. {
    3. if (textField == self.priceField)
    4. {
    5. // Don't allow selection / cursor positioning within price / quantity textfields; always set the cursor to the end
    6. if ([textField.selectedTextRange.start isEqual:textField.endOfDocument] && [textField.selectedTextRange.end isEqual:textField.endOfDocument]) return;
    7. textField.selectedTextRange = [textField textRangeFromPosition:textField.endOfDocument toPosition:textField.endOfDocument];
    8. }
    9. }
    Anmerkungen, Korrekturen & Verbesserungsvorschläge sind ausdrücklich willkommen :)

    Mattes ... entspannt im Dänemark-Urlaub
    Diese Seite bleibt aus technischen Gründen unbedruckt.
  • Hallo Mattes!

    Eine von mir genutzte App für das Protokollieren von Ausgaben und Online-Banking (von mir nicht genutzt)
    hatte nach jeder Änderung den Cursor ans Ende des Feldes positioniert. Ich habe mich immer geärgert, wenn ich
    etwas korrigieren musste. Dadurch dass du die Positionierung schon "verhinderst", entgehst du diesem Problem.
    Zumindest halte ich deine Lösung für konsistent, auch wenn ich diese Einschränkung seitens der App
    nicht unbedingt gut finde. Da es immer nur kurze Eingaben sind, ist es aber auch zu verschmerzen,

    Anregungen:
    - Falls nicht vorhanden: vielleicht ist ein Button zum Löschen der kompletten Eingabe gut. Dann kann man
    Tippfehler am Anfang der Zahl, die aber erst später auffallen, schneller korrigieren.
    - Wenn der Cursor nicht angezeigt wird, kommt man nicht auf die Idee, den zu verschieben. Beim
    Taschenrechner ist das doch auch ohne!

    Grüße in den Urlaub!
    Marco
  • Hi Marco,

    Danke für Dein Feedback, Du sprichst wichtige Punkte an:

    marcoo schrieb:

    Eine von mir genutzte App für das Protokollieren von Ausgaben und Online-Banking (von mir nicht genutzt) hatte nach jeder Änderung den Cursor ans Ende des Feldes positioniert. Ich habe mich immer geärgert, wenn ich etwas korrigieren musste.
    Ich hatte auch überlegt, eine freie Cursor-Positionierung zuzulassen und diesen nur als Default an's Ende zu setzen. Ich gebe offen zu, dass ich mir die komplexere Behandlung der Eingabe - mit Einfügungen an variablen Stellen - ersparen wollte. Schöngeredet habe ich es mir dann mit dem Argument der "konsistenten Bedienung": Ich habe die Erfahrung machen müssen, dass flexible Funktionen, die ich gut und richtig fand, viele Benutzer eher verwirrten. Jetzt kann man leicht erfassen, was bei Eingaben passiert. Bei der Länge "normal" hoher Preise m. E. zu verschmerzen.

    marcoo schrieb:

    - Falls nicht vorhanden: vielleicht ist ein Button zum Löschen der kompletten Eingabe gut. Dann kann man Tippfehler am Anfang der Zahl, die aber erst später auffallen, schneller korrigieren.
    Die Möglichkeit besteht ganz normal über den clearButtonMode.

    marcoo schrieb:

    - Wenn der Cursor nicht angezeigt wird, kommt man nicht auf die Idee, den zu verschieben. Beim Taschenrechner ist das doch auch ohne!
    Ja, das habe ich auch überlegt - ohne direkt eine Lösung zu haben. Dann habe ich den Gedanken aber wieder verworfen, da so m. E. eine klare Rückmeldung fehlte, welches UITextField nun den Fokus hat: Die View hat mehrere Eingabemöglichkeiten zzgl. weiterer Elemente ... da hilft der Cursor, das aktuelle Eingabefeld zu erkennen. 100% zufrieden bin ich noch nicht, vielleicht bringt der familieninterne UAT noch Verbesserungen :)

    Mattes
    Diese Seite bleibt aus technischen Gründen unbedruckt.