Маски ввода номера телефона на Flutter

от автора

Всем привет. Нужно поговорить немного про такую стандартную и обыденную часть любого приложения, как ввод номера телефона пользователя. Речь только о российских телефонах. Казалось бы, что может быть проще? Ставим в начало строки + или даже +7 и пользователь указывает телефон начиная с 9. Для удобства можно накинуть и маску и казалось бы все хорошо. Но нет иногда пользователи длоб…. смотрят не туда и пишут с 8 или с 7 и все. Без авторизации пользователь не может использовать сервис и дать нам денег на дошик на смузи. Посмотрим несколько примеров из других сервисов:

Как это работает в wildberries
Логика проста: ставим + а дальше пользователь сам поймет что вводить.

Логика проста: ставим + а дальше пользователь сам поймет что вводить.
Как это работает в Тинькофф

Задача

Мы делаем пакет для пользователей из России и пары случайных иностранцев. Наши требования:

  • Поле по умолчанию пустое. Пользователь сам решает что и как вводить

  • при вводе 7,8,9 должна работать маска российских номеров (Х (ХХХ) ХХХ-ХХ-ХХ),

  • в маску можно будет ввести и иностранный номер. Например +1

Время стучать по Клавиатуре

Для работы будем использовать наследника TextInputFormatter. Его можно добавить в любое текстовое поле в inputFormatters.А потом вытащить всю нужную нам информацию.

class RuPhoneInputFormatter extends TextInputFormatter{   @override   TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) {        } }

Для работы нам нужны

  1. переменная для форматированного значения

  2. флаг российски ли это номер

  3. метод форматирующий номер

  4. геттер чистого номера (номер без форматирования. Для российских начинается с 9, для иностранных c первой цифры в текстовом поле)

Добавляем нужные переменные и дефолтные значения (вдруг мы номер уже знаем)

class RuPhoneInputFormatter extends TextInputFormatter{   //форматированный телефон   String _formattedPhone = "";   //Российский ли номер   bool _isRu=false;    //Добавляем возможность указать номер по дефолту   RuPhoneInputFormatter({     String? initialText,   }) {     if (initialText != null) {       formatEditUpdate(           TextEditingValue.empty, TextEditingValue(text: initialText));     }   }      ///Иетод возвращает форматированнный телефон   String getMaskedPhone() {     return _formattedPhone;   }   ///возвращает чистый телефон. для России начинается с 9   String getClearPhone() {     if(_formattedPhone.isEmpty){       return '';     }     if(!_isRu){       return _formattedPhone.replaceAll(RegExp(r'\D'), '');     }     return _formattedPhone.replaceAll(RegExp(r'\D'), '').substring(         1,         (_formattedPhone.replaceAll(RegExp(r'\D'), '').length >= 11)             ? 11             : _formattedPhone.replaceAll(RegExp(r'\D'), '').length);   }   ///Проверяет заполнил ли пользователь телефон. Актуально только для Российских телефонов   bool isDone(){     if(!_isRu){       return true;     }     return (_formattedPhone.replaceAll(RegExp(r'\D'), '').length>10);   }   ///возвращает флаг Российски ли номер   get isRussian=>_isRu; }

Пишем метод для форматирования

метод должен проверять первые цифры и форматировать только если это 7,8,9

String _formattingPhone(String text){   //регулярка протиа букв. в телефоне только цифры     text=text.replaceAll(RegExp(r'\D'), '');     if(text.isNotEmpty){       String phone='';       //проверяем российски ли номер       if(['7','8','9'].contains(text[0])){         _isRu=true;         //если пользователь начал с 9, то добавим 7         if(text[0]=='9'){           text='7$text';         }         //Проверяем нужен ли +         String firstSymbols=(text[0]=='8') ? '8':'+7';         //само форматирование         phone='$firstSymbols ';         if(text.length>1){           phone+='(${text.substring(1,(text.length<4)?text.length:4)}';         }if(text.length>=5){           phone+=') ${text.substring(4,(text.length<7)?text.length:7)}';         }         if(text.length>=8){           phone+='-${text.substring(7,(text.length<9)?text.length:9)}';         }         if(text.length>=10){           phone+='-${text.substring(9,(text.length<11)?text.length:11)}';         }         return phone;       }else{         _isRu=false;         return '+$text';       }     }     return '';   }

Собираем все в кучу

Добавим код для удобства редактирования телефона

@override   TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) {     String text=newValue.text.replaceAll(RegExp(r'\D'), '');     int selectionStart=oldValue.selection.end;      //проверяем стерает ли пользователь все символы?     if(oldValue.text=='${newValue.text} '){       _formattedPhone='';       return TextEditingValue(           text: _formattedPhone,           selection: TextSelection(               baseOffset: _formattedPhone.length,               extentOffset: _formattedPhone.length,               affinity: newValue.selection.affinity,               isDirectional: newValue.selection.isDirectional           )       );     }      //проверяем редактирует ли пользователь телефон где то по середине?     if(selectionStart!=_formattedPhone.length){       _formattedPhone= _formattingPhone(text);       //если да, то не перекидываем курсов в самый конец        return TextEditingValue(           text: _formattedPhone,           selection: TextSelection(               baseOffset: newValue.selection.baseOffset,               extentOffset: newValue.selection.extentOffset,               affinity: newValue.selection.affinity,               isDirectional: newValue.selection.isDirectional           )       );     }      _formattedPhone= _formattingPhone(text);      //если пользователь просто вводит телефон,      //то переносим курсор в конец форматированной строки     return TextEditingValue(         text: _formattedPhone,         selection: TextSelection(             baseOffset: _formattedPhone.length,             extentOffset: _formattedPhone.length,             affinity: newValue.selection.affinity,             isDirectional: newValue.selection.isDirectional         )     );   }

Итоги

пример работы виджета. пользователь полностью свободен при вводе телефона. Так же сохранилась поддержка и иностранных телефонов.

пример работы виджета. пользователь полностью свободен при вводе телефона. Так же сохранилась поддержка и иностранных телефонов.

А что дальше?

в планах добавить маски всех телефонов стран СНГ.

Пакет

Для удобства все исходники тут

А еще есть пакет на pub.dev тут

Поддержать автора тут

Вдохновение черпал в видосике на Ютубе


ссылка на оригинал статьи https://habr.com/ru/articles/729216/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *