Flutter电话号码格式化插件flutter_libphonenumber_web的使用
Flutter电话号码格式化插件flutter_libphonenumber_web的使用
flutter_libphonenumber_web
是 flutter_libphonenumber
在 Web 平台上的实现。它允许你在 Web 应用中格式化和解析电话号码。
完整示例代码
以下是一个完整的示例,展示了如何在 Flutter 应用中使用 flutter_libphonenumber_web
插件来格式化和解析电话号码。
// ignore_for_file: avoid_print
import 'dart:convert';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_libphonenumber_platform_interface/flutter_libphonenumber_platform_interface.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
[@override](/user/override)
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
late final _future = FlutterLibphonenumberPlatform.instance.init();
final phoneController = TextEditingController();
final countryController = TextEditingController(text: 'United States');
final manualFormatController = TextEditingController();
[@override](/user/override)
void initState() {
super.initState();
updatePlaceholderHint();
}
/// 结果当调用解析方法时。
String? parsedData;
/// 用于格式化为移动或固定电话
var _globalPhoneType = PhoneNumberType.mobile;
/// 使用国际或国内电话格式
var _globalPhoneFormat = PhoneNumberFormat.international;
/// 当前选择的国家
var _currentSelectedCountry = const CountryWithPhoneCode.us();
var _placeholderHint = '';
var _inputContainsCountryCode = true;
/// 保持光标在输入的末尾
var _shouldKeepCursorAtEndOfInput = true;
void updatePlaceholderHint() {
late String newPlaceholder;
if (_globalPhoneType == PhoneNumberType.mobile) {
if (_globalPhoneFormat == PhoneNumberFormat.international) {
newPlaceholder = _currentSelectedCountry.exampleNumberMobileInternational;
} else {
newPlaceholder = _currentSelectedCountry.exampleNumberMobileNational;
}
} else {
if (_globalPhoneFormat == PhoneNumberFormat.international) {
newPlaceholder = _currentSelectedCountry.exampleNumberFixedLineInternational;
} else {
newPlaceholder = _currentSelectedCountry.exampleNumberFixedLineNational;
}
}
/// 去除提示中的国家代码
if (!_inputContainsCountryCode) {
newPlaceholder = newPlaceholder.substring(_currentSelectedCountry.phoneCode.length + 2);
}
setState(() => _placeholderHint = newPlaceholder);
}
[@override](/user/override)
Widget build(final BuildContext context) {
return MaterialApp(
home: FutureBuilder<void>(
future: _future,
builder: (final context, final snapshot) {
if (snapshot.hasError) {
return Scaffold(
resizeToAvoidBottomInset: true,
appBar: AppBar(
title: const Text('flutter_libphonenumber'),
),
body: Center(
child: Text('error: ${snapshot.error}'),
),
);
} else if (snapshot.connectionState == ConnectionState.done) {
return GestureDetector(
onTap: () {
FocusScope.of(context).requestFocus(FocusNode());
},
child: Scaffold(
resizeToAvoidBottomInset: true,
appBar: AppBar(
title: const Text('flutter_libphonenumber'),
),
body: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: SingleChildScrollView(
padding: EdgeInsets.only(
bottom: max(
0,
24 - MediaQuery.of(context).padding.bottom,
),
),
child: Column(
children: [
const SizedBox(height: 10),
/// 获取所有区域代码
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
child: Column(
children: [
/// 打印区域数据
ElevatedButton(
child: const Text('打印所有区域数据'),
onPressed: () async {
final res = await FlutterLibphonenumberPlatform.instance.getAllSupportedRegions();
print(res['IT']);
print(res['US']);
print(res['BR']);
},
),
/// 间隔器
const SizedBox(height: 12),
/// 国家代码输入
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 24,
),
child: TextField(
controller: countryController,
keyboardType: TextInputType.phone,
onChanged: (final v) {
setState(() {});
},
textAlign: TextAlign.center,
onTap: () async {
final sortedCountries = CountryManager().countries
..sort((final a, final b) => (a.countryName ?? '').compareTo(b.countryName ?? ''));
final res = await showModalBottomSheet<CountryWithPhoneCode>(
context: context,
isScrollControlled: false,
builder: (final context) {
return ListView.builder(
padding: const EdgeInsets.symmetric(vertical: 16),
itemBuilder: (final context, final index) {
final item = sortedCountries[index];
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
Navigator.of(context).pop(item);
},
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
child: Row(
children: [
/// 电话代码
Expanded(
child: Text(
'+${item.phoneCode}',
textAlign: TextAlign.right,
),
),
/// 间隔器
const SizedBox(width: 16),
/// 名称
Expanded(
flex: 8,
child: Text(
item.countryName ?? '',
),
),
],
),
),
);
},
itemCount: sortedCountries.length,
);
},
);
print('新国家选择: $res');
if (res != null) {
setState(() {
_currentSelectedCountry = res;
});
updatePlaceholderHint();
countryController.text = res.countryName ?? '+ ${res.phoneCode}';
}
},
readOnly: true,
inputFormatters: const [],
),
),
],
),
),
/// 间隔器
const SizedBox(width: 20),
Expanded(
child: Column(
children: [
/// 移动或固定电话切换
Row(
children: [
Switch(
value: _globalPhoneType == PhoneNumberType.mobile ? true : false,
onChanged: (final val) {
setState(
() => _globalPhoneType = val == false
? PhoneNumberType.fixedLine
: PhoneNumberType.mobile,
);
updatePlaceholderHint();
},
),
/// 间隔器
const SizedBox(width: 5),
Flexible(
child: _globalPhoneType == PhoneNumberType.mobile
? const Text('格式化为移动电话')
: const Text('格式化为固定电话'),
),
],
),
/// 国际或国内格式切换
Row(
children: [
Switch(
value: _globalPhoneFormat == PhoneNumberFormat.national ? true : false,
onChanged: (final val) {
setState(
() => _globalPhoneFormat = val == false
? PhoneNumberFormat.international
: PhoneNumberFormat.national,
);
updatePlaceholderHint();
},
),
/// 间隔器
const SizedBox(width: 5),
Flexible(
child: _globalPhoneFormat == PhoneNumberFormat.national
? const Text('国内')
: const Text('国际'),
),
],
),
/// 格式化假定包含或不包含国家代码
Row(
children: [
Switch(
value: _inputContainsCountryCode,
onChanged: (final val) {
setState(
() => _inputContainsCountryCode = !_inputContainsCountryCode,
);
updatePlaceholderHint();
},
),
/// 间隔器
const SizedBox(width: 5),
Flexible(
child: _inputContainsCountryCode
? const Text('包含国家代码')
: const Text('不包含国家代码'),
),
],
),
/// 切换保持光标在同一位置,允许用户编辑输入中间部分。
Row(
children: [
Switch(
value: _shouldKeepCursorAtEndOfInput,
onChanged: (final val) {
setState(
() => _shouldKeepCursorAtEndOfInput = !_shouldKeepCursorAtEndOfInput,
);
updatePlaceholderHint();
},
),
/// 间隔器
const SizedBox(width: 5),
const Flexible(
child: Text('强制光标到末尾'),
),
],
),
],
),
),
],
),
/// 间隔器
const SizedBox(height: 10),
const Divider(),
const SizedBox(height: 10),
/// 边输边格式化
const Text(
'边输边格式化(同步使用掩码)',
),
/// 电话输入
SizedBox(
width: 160,
child: TextField(
textAlign: TextAlign.center,
keyboardType: TextInputType.phone,
controller: phoneController,
decoration: InputDecoration(
hintText: _placeholderHint,
),
inputFormatters: [
LibPhonenumberTextFormatter(
phoneNumberType: _globalPhoneType,
phoneNumberFormat: _globalPhoneFormat,
country: _currentSelectedCountry,
inputContainsCountryCode: _inputContainsCountryCode,
shouldKeepCursorAtEndOfInput: _shouldKeepCursorAtEndOfInput,
),
],
),
),
/// 间隔器
const SizedBox(height: 10),
const Text(
'如果国家代码不为空,电话号码将格式化为不包含国家代码。',
style: TextStyle(fontSize: 12),
textAlign: TextAlign.center,
),
/// 间隔器
const SizedBox(height: 20),
const Divider(),
const SizedBox(height: 20),
const Text(
'手动格式化/解析电话号码。\n异步使用 FlutterLibphonenumber().format()。\n同步使用 FlutterLibphonenumber().formatPhone。',
style: TextStyle(fontSize: 12),
textAlign: TextAlign.center,
),
/// 手动电话输入
SizedBox(
width: 180,
child: TextField(
keyboardType: TextInputType.phone,
textAlign: TextAlign.center,
controller: manualFormatController,
decoration: InputDecoration(
hintText: _placeholderHint,
),
),
),
/// 间隔器
const SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
/// 手动格式化电话输入
Flexible(
child: ElevatedButton(
child: const Text(
'格式化(异步)',
textAlign: TextAlign.center,
),
onPressed: () async {
// 异步格式化,使用原生调用 libphonenumber
final res = await FlutterLibphonenumberPlatform.instance.format(
manualFormatController.text,
_currentSelectedCountry.countryCode,
);
setState(
() => manualFormatController.text = res['formatted'] ?? '',
);
},
),
),
/// 间隔器
const SizedBox(width: 10),
Flexible(
child: ElevatedButton(
child: const Text(
'格式化(同步)',
textAlign: TextAlign.center,
),
onPressed: () async {
if (CountryManager().countries.isEmpty) {
print(
"警告:国家列表为空,这意味着 init 尚未运行。不能在 init 运行之前同步格式化。",
);
}
// 同步格式化,不使用原生调用 libphonenumber,仅使用 Dart 调用掩码输入
manualFormatController.text = FlutterLibphonenumberPlatform.instance.formatNumberSync(
manualFormatController.text,
country: _currentSelectedCountry,
phoneNumberType: _globalPhoneType,
phoneNumberFormat: _globalPhoneFormat,
inputContainsCountryCode: _inputContainsCountryCode,
);
},
),
),
/// 间隔器
const SizedBox(width: 10),
/// 手动格式化电话输入
Flexible(
child: ElevatedButton(
child: const Text(
'解析',
textAlign: TextAlign.center,
),
onPressed: () async {
try {
final res = await FlutterLibphonenumberPlatform.instance.parse(
manualFormatController.text,
region: _currentSelectedCountry.countryCode,
);
const JsonEncoder encoder = JsonEncoder.withIndent(' ');
setState(
() => parsedData = encoder.convert(res),
);
} catch (e) {
print(e);
setState(() => parsedData = null);
}
},
),
),
],
),
/// 间隔器
const SizedBox(height: 10),
Text(parsedData ?? '无效的号码'),
],
),
),
),
),
);
} else {
return Scaffold(
resizeToAvoidBottomInset: true,
appBar: AppBar(
title: const Text('flutter_libphonenumber'),
),
body: const Center(
child: CircularProgressIndicator(),
),
);
}
},
),
);
}
}
更多关于Flutter电话号码格式化插件flutter_libphonenumber_web的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter电话号码格式化插件flutter_libphonenumber_web的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是一个关于如何使用 flutter_libphonenumber_web
插件来格式化电话号码的示例代码。这个插件利用 Google 的 libphonenumber
库,可以在 Flutter 应用中对电话号码进行格式化和验证。
首先,确保在你的 pubspec.yaml
文件中添加 flutter_libphonenumber_web
依赖:
dependencies:
flutter:
sdk: flutter
flutter_libphonenumber_web: ^x.y.z # 请替换为最新版本号
然后运行 flutter pub get
来获取依赖。
接下来,在你的 Flutter 项目中,你可以按照以下方式使用 flutter_libphonenumber_web
插件:
import 'package:flutter/material.dart';
import 'package:flutter_libphonenumber_web/flutter_libphonenumber_web.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Phone Number Formatter',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: PhoneNumberFormatterScreen(),
);
}
}
class PhoneNumberFormatterScreen extends StatefulWidget {
@override
_PhoneNumberFormatterScreenState createState() => _PhoneNumberFormatterScreenState();
}
class _PhoneNumberFormatterScreenState extends State<PhoneNumberFormatterScreen> {
final TextEditingController _controller = TextEditingController();
String _formattedNumber = '';
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Phone Number Formatter'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
TextField(
controller: _controller,
decoration: InputDecoration(
labelText: 'Enter Phone Number',
border: OutlineInputBorder(),
),
keyboardType: TextInputType.phone,
),
SizedBox(height: 16),
ElevatedButton(
onPressed: () {
_formatPhoneNumber();
},
child: Text('Format Phone Number'),
),
SizedBox(height: 16),
Text(
'Formatted Number: $_formattedNumber',
style: TextStyle(fontSize: 18),
),
],
),
),
);
}
void _formatPhoneNumber() async {
final phoneUtil = PhoneNumberUtil();
try {
final number = await phoneUtil.parseAndKeepRawInput(_controller.text, 'US'); // 假设默认国家代码为美国
final formattedNumber = phoneUtil.format(number, PhoneNumberFormat.INTERNATIONAL);
setState(() {
_formattedNumber = formattedNumber;
});
} catch (e) {
// 处理解析错误
print('Error formatting phone number: $e');
}
}
}
在这个示例中,我们创建了一个简单的 Flutter 应用,用户可以输入一个电话号码,并点击按钮来格式化该号码。我们使用 flutter_libphonenumber_web
插件中的 PhoneNumberUtil
类来解析和格式化电话号码。
请注意,这个示例假设默认的国家代码是美国 ('US'
),你可以根据实际需求更改这个值。另外,这个插件只支持在 Web 平台上使用,如果你在移动平台上需要类似的功能,可以考虑使用 libphonenumber
的其他 Flutter 插件,如 flutter_libphonenumber
。
确保在测试时,你的 Flutter 应用运行在支持 Web 的环境中。