Created
January 5, 2022 17:30
-
-
Save AleksandarSavic95/a1128f99393f61f0d0ebea6740fb153f to your computer and use it in GitHub Desktop.
Flutter TextInputFormatter for credit card number and expiry date
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Modified from https://youtu.be/4v4l6E8Sbj8?t=1025 (at around 17:05) | |
import 'package:flutter/services.dart'; | |
/// A [TextInputFormatter] for the credit card number. Adds space after every four characters. | |
class CreditCardInputFormatter extends TextInputFormatter { | |
final separator = ' '; | |
@override | |
TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) { | |
return textManipulation( | |
oldValue, | |
newValue, | |
textInputFormatter: FilteringTextInputFormatter.digitsOnly, | |
formatPattern: (filteredString) { | |
var buffer = StringBuffer(); | |
for (var i = 0; i < filteredString.length; i++) { | |
buffer.write(filteredString[i]); | |
if ((i + 1) % 4 == 0) { | |
buffer.write(separator); | |
} | |
} | |
return buffer.toString(); | |
}, | |
); | |
} | |
} | |
/// A [TextInputFormatter] for the expiry date of a credit card. Adds " / " after the first two characters. | |
class ExpiryDateInputFormatter extends TextInputFormatter { | |
final separator = ' / '; | |
@override | |
TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) { | |
return textManipulation( | |
oldValue, | |
newValue, | |
textInputFormatter: FilteringTextInputFormatter.digitsOnly, | |
formatPattern: (filteredString) { | |
return filteredString.length >= 2 | |
? filteredString.substring(0, 2) + separator + filteredString.substring(2, filteredString.length) | |
: filteredString; | |
}, | |
); | |
} | |
} | |
TextEditingValue textManipulation( | |
TextEditingValue oldValue, | |
TextEditingValue newValue, { | |
required String Function(String filteredString) formatPattern, | |
required TextInputFormatter textInputFormatter, | |
}) { | |
// Remove all invalid characters | |
newValue = textInputFormatter.formatEditUpdate(oldValue, newValue); | |
var cursorPosition = newValue.selection.end; | |
print(cursorPosition); | |
final textWithSeparators = formatPattern(newValue.text); | |
if (textWithSeparators == newValue.text) { | |
return newValue; | |
} | |
bool isUserInput(String s) => newValue.text.contains(s); | |
// Count number of inserted characters in the new string (up until the current cursor position) | |
int insertedCharactersCount = 0; | |
int initialCharactersCount = 0; | |
for (var i = 0; i < textWithSeparators.length && initialCharactersCount < cursorPosition; i++) { | |
final character = textWithSeparators[i]; | |
if (isUserInput(character)) { | |
initialCharactersCount++; | |
} else { | |
insertedCharactersCount++; | |
} | |
} | |
// Adjust cursor position according to number of inserted characters | |
cursorPosition += insertedCharactersCount; | |
return newValue.copyWith( | |
text: textWithSeparators, | |
selection: TextSelection.collapsed(offset: cursorPosition), | |
composing: TextRange.empty, | |
); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment