phone_text_field
一個功能完整的 Flutter 插件,支援國際電話號碼輸入、驗證、格式化與國家選擇,並具備本地化支援。
電話號碼文字欄位是 Flutter 插件,可讓您解析、驗證、格式化國際電話號碼,並提供其他實用功能與地區化支援。
{"sdk":"flutter"}{"sdk":"flutter"}{"sdk":"flutter"}^3.0.0^5.4.4^2.4.8以下為英文專案原文快照,最新內容請造訪 GitHub。
Pub Version Flutter Platform License GitHub Stars
A comprehensive Flutter package for international phone number input with validation, formatting, and country selection. Perfect for apps requiring phone number collection with proper validation and beautiful UI.
🌐 Try the Interactive Web Demo - Experience all features in your browser!
📱 Mobile Demo: Clone and run the example app to see it in action on mobile devices.
Phone Text Field Demo
Add this to your pubspec.yaml:
dependencies:
phone_text_field: ^1.0.0 # Use latest version
flutter pub get
import 'package:phone_text_field/phone_text_field.dart';
PhoneTextField(
onChanged: (phoneNumber) {
print('Complete number: ${phoneNumber.completeNumber}');
print('Country: ${phoneNumber.countryISOCode}');
},
)
class MyForm extends StatefulWidget {
@override
_MyFormState createState() => _MyFormState();
}
class _MyFormState extends State<MyForm> {
final _phoneController = TextEditingController();
final _formKey = GlobalKey<FormState>();
@override
Widget build(BuildContext context) {
return Form(
key: _formKey,
child: PhoneTextField(
controller: _phoneController,
isRequired: true,
autovalidateMode: AutovalidateMode.onUserInteraction,
decoration: const InputDecoration(
labelText: 'Phone Number',
border: OutlineInputBorder(),
),
onChanged: (phoneNumber) {
// Handle phone number changes
},
),
);
}
@override
void dispose() {
_phoneController.dispose();
super.dispose();
}
}
PhoneTextField(
initialCountryCode: 'AE',
decoration: const InputDecoration(
filled: true,
labelText: 'Phone Number',
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(12)),
),
prefixIcon: Icon(Icons.phone),
),
searchFieldInputDecoration: const InputDecoration(
filled: true,
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(12)),
),
suffixIcon: Icon(Icons.search),
hintText: 'Search country',
),
countryViewOptions: CountryViewOptions.countryCodeWithFlag,
onChanged: (phoneNumber) {
debugPrint('Phone: ${phoneNumber.completeNumber}');
},
)
PhoneTextField(
locale: const Locale('ar'),
decoration: const InputDecoration(
filled: true,
labelText: 'رقم الهاتف',
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(12)),
),
prefixIcon: Icon(Icons.phone),
),
searchFieldInputDecoration: const InputDecoration(
filled: true,
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(12)),
),
suffixIcon: Icon(Icons.search),
hintText: 'بحث عن بالاسم او الرمز',
),
dialogTitle: 'اختر الدولة',
initialCountryCode: 'AE',
onChanged: (phoneNumber) {
debugPrint('رقم الهاتف: ${phoneNumber.completeNumber}');
},
)
PhoneTextField(
isRequired: true,
invalidNumberMessage: 'Please enter a valid phone number',
autovalidateMode: AutovalidateMode.onUserInteraction,
decoration: const InputDecoration(
labelText: 'Phone Number *',
border: OutlineInputBorder(),
helperText: 'Enter your phone number with country code',
),
onChanged: (phoneNumber) {
if (phoneNumber.isValid) {
print('Valid number: ${phoneNumber.completeNumber}');
}
},
)
// Flag only
PhoneTextField(
countryViewOptions: CountryViewOptions.countryFlagOnly,
onChanged: (phoneNumber) {},
)
// Country name with flag
PhoneTextField(
countryViewOptions: CountryViewOptions.countryNameWithFlag,
onChanged: (phoneNumber) {},
)
// Country code only
PhoneTextField(
countryViewOptions: CountryViewOptions.countryCodeOnly,
onChanged: (phoneNumber) {},
)
| Property | Type | Default | Description |
|---|---|---|---|
onChanged |
Function(PhoneNumber) |
required | Callback when phone number changes |
controller |
TextEditingController? |
null |
Controller for form integration |
initialCountryCode |
String? |
null |
Initial country code (e.g., 'US', 'AE') |
initialValue |
String? |
null |
Initial phone number value |
decoration |
InputDecoration? |
null |
Input field decoration |
searchFieldInputDecoration |
InputDecoration? |
null |
Country search field decoration |
locale |
Locale? |
null |
Localization (ar, en, fr) |
isRequired |
bool |
false |
Whether the field is required |
invalidNumberMessage |
String? |
null |
Custom validation error message |
countryViewOptions |
CountryViewOptions |
countryCodeWithFlag |
How to display countries |
dialogTitle |
String? |
null |
Custom dialog title |
autovalidateMode |
AutovalidateMode? |
null |
When to validate input |
class PhoneNumber {
String completeNumber; // Full international number
String countryISOCode; // Country code (US, AE, etc.)
String countryCode; // Dial code (+1, +971, etc.)
String number; // Local number
bool isValid; // Validation status
}
enum CountryViewOptions {
countryCodeOnly, // +1
countryNameOnly, // United States
countryFlagOnly, // 🇺🇸
countryCodeWithFlag, // 🇺🇸 +1
countryNameWithFlag, // 🇺🇸 United States
}
class PhoneForm extends StatefulWidget {
@override
_PhoneFormState createState() => _PhoneFormState();
}
class _PhoneFormState extends State<PhoneForm> {
final _formKey = GlobalKey<FormState>();
final _phoneController = TextEditingController();
PhoneNumber? _phoneNumber;
@override
Widget build(BuildContext context) {
return Form(
key: _formKey,
child: Column(
children: [
PhoneTextField(
controller: _phoneController,
isRequired: true,
autovalidateMode: AutovalidateMode.onUserInteraction,
decoration: const InputDecoration(
labelText: 'Phone Number *',
border: OutlineInputBorder(),
),
onChanged: (phoneNumber) {
setState(() {
_phoneNumber = phoneNumber;
});
},
),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate() &&
_phoneNumber?.isValid == true) {
// Process valid phone number
print('Valid phone: ${_phoneNumber!.completeNumber}');
}
},
child: const Text('Submit'),
),
],
),
);
}
@override
void dispose() {
_phoneController.dispose();
super.dispose();
}
}
// Using Provider
class PhoneProvider extends ChangeNotifier {
PhoneNumber? _phoneNumber;
PhoneNumber? get phoneNumber => _phoneNumber;
void updatePhone(PhoneNumber phoneNumber) {
_phoneNumber = phoneNumber;
notifyListeners();
}
}
// In your widget
Consumer<PhoneProvider>(
builder: (context, phoneProvider, child) {
return PhoneTextField(
onChanged: (phoneNumber) {
phoneProvider.updatePhone(phoneNumber);
},
);
},
)
Problem: Controller property was commented out, causing integration issues with forms.
// Before (broken)
// final TextEditingController? controller;
// After (fixed)
final TextEditingController? controller;
Problem: When editing US/Canada numbers, flag would incorrectly switch between countries. Solution: Improved country selection logic to preserve originally selected country when multiple countries share the same dial code.
Problem: Chinese numbers were validated as 12 digits instead of 11.
// Before
'CN': {minLength: 12, maxLength: 12}
// After
'CN': {minLength: 11, maxLength: 11}
You can test these fixes in the example app or the live demo:
13812345678This package supports 200+ countries with proper validation rules including:
The package supports multiple languages:
| Language | Locale | Status |
|---|---|---|
| English | en |
✅ Full Support |
| Arabic | ar |
✅ Full Support |
| French | fr |
✅ Full Support |
Contributions for additional languages are welcome! Check our contribution guide for details.
| Platform | Status | Notes |
|---|---|---|
| 📱 iOS | ✅ Full Support | iOS 9.0+ |
| 🤖 Android | ✅ Full Support | API 16+ |
| 🌐 Web | ✅ Full Support | All modern browsers |
| 🖥️ macOS | ✅ Full Support | macOS 10.11+ |
| 🖥️ Windows | ✅ Full Support | Windows 10+ |
| 🐧 Linux | ✅ Full Support | Any distribution |
Run the comprehensive example app:
cd example
flutter run
Experience the full demo in your browser:
cd example
flutter run -d chrome
|
Country Selection
🌍 Country Selection Easy country selection with search functionality |
Phone Input
📱 Phone Input Clean phone number input with validation |
|
Arabic Localization
🇸🇦 Arabic Localization Full RTL support with Arabic text |
Validation
✅ Validation & Error Handling Real-time validation with error messages |
Phone Text Field Demo
Interactive demo showing all features in action
|
International Support
🌍 International 200+ countries with proper validation rules |
Customizable Design
🎨 Customizable Material 3 design with flexible styling |
Localization Support
🌐 Localized Arabic, English, French support |
Validation System
✅ Validation Real-time validation with custom messages |
| ✨ Feature | 📷 Preview | 📝 Description |
|---|---|---|
| 🌍 International | Country flags | 200+ countries with proper validation rules |
| 🎨 Customizable | Styled input | Material 3 design with flexible styling |
| 🌐 Localized | Arabic UI | Arabic, English, French support |
| ✅ Validation | Error states | Real-time validation with custom messages |
We welcome contributions! Here's how you can help:
git checkout -b feature/amazing-featureflutter testgit commit -m "feat: add amazing feature"git push origin feature/amazing-feature# Clone the repository
git clone https://github.com/MohamedAbd0/phone_text_field.git
cd phone_text_field
# Install dependencies
flutter pub get
# Run tests
flutter test
# Run example app
cd example
flutter run
This project is licensed under the MIT License - see the LICENSE file for details.
Mohamed Abdo
If this package helped you, please:
GitHub stars Pub points Pub popularity GitHub issues GitHub pull requests
Made with ❤️ by Mohamed Abdo