Flutter电话号码格式化插件flutter_libphonenumber_ios的使用

发布于 1周前 作者 bupafengyu 来自 Flutter

Flutter电话号码格式化插件flutter_libphonenumber_ios的使用

flutter_libphonenumber_iosflutter_libphonenumber 插件的 iOS 平台实现,用于在 Flutter 应用中处理电话号码的格式化和解析。本文将介绍如何使用该插件,并提供一个完整的示例 Demo。

示例代码

以下是一个完整的示例应用,展示了如何使用 flutter_libphonenumber_ios 插件来格式化和解析电话号码。

// 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();
  }

  /// Result when we call the parse method.
  String? parsedData;

  /// Used to format numbers as mobile or land line
  var _globalPhoneType = PhoneNumberType.mobile;

  /// Use international or national phone format
  var _globalPhoneFormat = PhoneNumberFormat.international;

  /// Current selected country
  var _currentSelectedCountry = const CountryWithPhoneCode.us();

  var _placeholderHint = '';

  var _inputContainsCountryCode = true;

  /// Keep cursor on the end
  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;
      }
    }

    /// Strip country code from hint
    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),

                        /// Get all region codes
                        Row(
                          mainAxisAlignment: MainAxisAlignment.center,
                          children: [
                            Expanded(
                              child: Column(
                                children: [
                                  /// Print region data
                                  ElevatedButton(
                                    child: const Text('Print all region data'),
                                    onPressed: () async {
                                      final res =
                                          await FlutterLibphonenumberPlatform
                                              .instance
                                              .getAllSupportedRegions();
                                      print(res['IT']);
                                      print(res['US']);
                                      print(res['BR']);
                                    },
                                  ),

                                  /// Spacer
                                  const SizedBox(height: 12),

                                  /// Country code input
                                  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: [
                                                        /// Phone code
                                                        Expanded(
                                                          child: Text(
                                                            '+${item.phoneCode}',
                                                            textAlign:
                                                                TextAlign.right,
                                                          ),
                                                        ),

                                                        /// Spacer
                                                        const SizedBox(
                                                          width: 16,
                                                        ),

                                                        /// Name
                                                        Expanded(
                                                          flex: 8,
                                                          child: Text(
                                                            item.countryName ??
                                                                '',
                                                          ),
                                                        ),
                                                      ],
                                                    ),
                                                  ),
                                                );
                                              },
                                              itemCount: sortedCountries.length,
                                            );
                                          },
                                        );

                                        print('New country selection: $res');

                                        if (res != null) {
                                          setState(() {
                                            _currentSelectedCountry = res;
                                          });

                                          updatePlaceholderHint();

                                          countryController.text =
                                              res.countryName ??
                                                  '+ ${res.phoneCode}';
                                        }
                                      },
                                      readOnly: true,
                                      inputFormatters: const [],
                                    ),
                                  ),
                                ],
                              ),
                            ),

                            /// Spacer
                            const SizedBox(width: 20),

                            Expanded(
                              child: Column(
                                children: [
                                  /// Mobile or land line toggle
                                  Row(
                                    children: [
                                      Switch(
                                        value: _globalPhoneType ==
                                                PhoneNumberType.mobile
                                            ? true
                                            : false,
                                        onChanged: (final val) {
                                          setState(
                                            () => _globalPhoneType =
                                                val == false
                                                    ? PhoneNumberType.fixedLine
                                                    : PhoneNumberType.mobile,
                                          );
                                          updatePlaceholderHint();
                                        },
                                      ),

                                      /// Spacer
                                      const SizedBox(width: 5),

                                      Flexible(
                                        child: _globalPhoneType ==
                                                PhoneNumberType.mobile
                                            ? const Text('Format as Mobile')
                                            : const Text('Format as FixedLine'),
                                      ),
                                    ],
                                  ),

                                  /// National or international line toggle
                                  Row(
                                    children: [
                                      Switch(
                                        value: _globalPhoneFormat ==
                                                PhoneNumberFormat.national
                                            ? true
                                            : false,
                                        onChanged: (final val) {
                                          setState(
                                            () => _globalPhoneFormat = val ==
                                                    false
                                                ? PhoneNumberFormat
                                                    .international
                                                : PhoneNumberFormat.national,
                                          );
                                          updatePlaceholderHint();
                                        },
                                      ),

                                      /// Spacer
                                      const SizedBox(width: 5),

                                      Flexible(
                                        child: _globalPhoneFormat ==
                                                PhoneNumberFormat.national
                                            ? const Text('National')
                                            : const Text('International'),
                                      ),
                                    ],
                                  ),

                                  /// Format assuming country code present or absent
                                  Row(
                                    children: [
                                      Switch(
                                        value: _inputContainsCountryCode,
                                        onChanged: (final val) {
                                          setState(
                                            () => _inputContainsCountryCode =
                                                !_inputContainsCountryCode,
                                          );
                                          updatePlaceholderHint();
                                        },
                                      ),

                                      /// Spacer
                                      const SizedBox(width: 5),

                                      Flexible(
                                        child: _inputContainsCountryCode
                                            ? const Text('With country code')
                                            : const Text('No country code'),
                                      ),
                                    ],
                                  ),

                                  /// Toggle keeping the cursor in the same spot as it was when inputting, allowing
                                  /// user to edit the middle of the input.
                                  Row(
                                    children: [
                                      Switch(
                                        value: _shouldKeepCursorAtEndOfInput,
                                        onChanged: (final val) {
                                          setState(
                                            () => _shouldKeepCursorAtEndOfInput =
                                                !_shouldKeepCursorAtEndOfInput,
                                          );
                                          updatePlaceholderHint();
                                        },
                                      ),

                                      /// Spacer
                                      const SizedBox(width: 5),

                                      const Flexible(
                                        child: Text('Force cursor to end'),
                                      ),
                                    ],
                                  ),
                                ],
                              ),
                            ),
                          ],
                        ),

                        /// Spacer
                        const SizedBox(height: 10),
                        const Divider(),
                        const SizedBox(height: 10),

                        /// Format as you type
                        const Text(
                          'Format as you type (synchronous using masks)',
                        ),

                        /// Phone input
                        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,
                              ),
                            ],
                          ),
                        ),

                        /// Spacer
                        const SizedBox(height: 10),

                        const Text(
                          'If country code is not empty, phone number will format expecting no country code.',
                          style: TextStyle(fontSize: 12),
                          textAlign: TextAlign.center,
                        ),

                        /// Spacer
                        const SizedBox(height: 20),
                        const Divider(),
                        const SizedBox(height: 20),

                        const Text(
                          'Manually format / parse the phone number.\nAsync uses FlutterLibphonenumber().format().\nSync uses FlutterLibphonenumber().formatPhone.',
                          style: TextStyle(fontSize: 12),
                          textAlign: TextAlign.center,
                        ),

                        /// Manual Phone input
                        SizedBox(
                          width: 180,
                          child: TextField(
                            keyboardType: TextInputType.phone,
                            textAlign: TextAlign.center,
                            controller: manualFormatController,
                            decoration: InputDecoration(
                              hintText: _placeholderHint,
                            ),
                          ),
                        ),

                        /// Spacer
                        const SizedBox(height: 10),

                        Row(
                          mainAxisAlignment: MainAxisAlignment.center,
                          children: [
                            /// Manually format the phone input
                            Flexible(
                              child: ElevatedButton(
                                child: const Text(
                                  'Format (Async)',
                                  textAlign: TextAlign.center,
                                ),
                                onPressed: () async {
                                  // Asynchronous formatting with native call into libphonenumber
                                  final res =
                                      await FlutterLibphonenumberPlatform
                                          .instance
                                          .format(
                                    manualFormatController.text,
                                    _currentSelectedCountry.countryCode,
                                  );
                                  setState(
                                    () => manualFormatController.text =
                                        res['formatted'] ?? '',
                                  );
                                },
                              ),
                            ),

                            /// Spacer
                            const SizedBox(width: 10),

                            Flexible(
                              child: ElevatedButton(
                                child: const Text(
                                  'Format (Sync)',
                                  textAlign: TextAlign.center,
                                ),
                                onPressed: () async {
                                  if (CountryManager().countries.isEmpty) {
                                    print(
                                      "Warning: countries list is empty which means init hs not be run yet. Can't format synchronously until init has been executed.",
                                    );
                                  }
                                  // Synchronous formatting with no native call into libphonenumber, just a dart call to mask the input
                                  manualFormatController.text =
                                      FlutterLibphonenumberPlatform.instance
                                          .formatNumberSync(
                                    manualFormatController.text,
                                    country: _currentSelectedCountry,
                                    phoneNumberType: _globalPhoneType,
                                    phoneNumberFormat: _globalPhoneFormat,
                                    inputContainsCountryCode:
                                        _inputContainsCountryCode,
                                  );
                                },
                              ),
                            ),

                            /// Spacer
                            const SizedBox(width: 10),

                            /// Manually format the phone input
                            Flexible(
                              child: ElevatedButton(
                                child: const Text(
                                  'Parse',
                                  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);
                                  }
                                },
                              ),
                            ),
                          ],
                        ),

                        /// Spacer
                        const SizedBox(height: 10),

                        Text(parsedData ?? 'Number invalid'),
                      ],
                    ),
                  ),
                ),
              ),
            );
          } else {
            return Scaffold(
              resizeToAvoidBottomInset: true,
              appBar: AppBar(
                title: const Text('flutter_libphonenumber'),
              ),
              body: const Center(
                child: CircularProgressIndicator(),
              ),
            );
          }
        },
      ),
    );
  }
}

更多关于Flutter电话号码格式化插件flutter_libphonenumber_ios的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter电话号码格式化插件flutter_libphonenumber_ios的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter项目中集成并使用flutter_libphonenumber_ios插件来进行电话号码格式化的示例代码。需要注意的是,flutter_libphonenumber_ios这个插件名称听起来是专门用于iOS的,但在实际使用中,你可能还会需要一个跨平台的插件如libphonenumber-jsflutter_phone_direct_caller,这些插件通常也支持iOS和Android。不过,为了遵循你的要求,这里假设我们使用的是flutter_libphonenumber_ios(尽管这样的插件名较为罕见,且可能实际指向的是iOS特定的实现)。

首先,确保你的Flutter环境已经设置好,并且你已经有一个Flutter项目。

1. 添加依赖

在你的pubspec.yaml文件中添加flutter_libphonenumber_ios依赖(注意:如果实际插件名为其他,请替换为正确的插件名):

dependencies:
  flutter:
    sdk: flutter
  flutter_libphonenumber_ios: ^x.y.z  # 替换x.y.z为实际版本号

然后运行flutter pub get来安装依赖。

2. 配置iOS项目

由于插件名暗示它可能只支持iOS,你可能需要在iOS原生代码中进行一些配置。不过,大多数Flutter插件现在都能自动处理这些配置。如果插件文档中有提到需要手动配置,请按照文档操作。

3. 使用插件

在你的Flutter代码中,你可以这样使用插件来格式化电话号码:

import 'package:flutter/material.dart';
import 'package:flutter_libphonenumber_ios/flutter_libphonenumber_ios.dart';  // 假设插件名正确

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Phone Number Formatter'),
        ),
        body: PhoneNumberFormatterScreen(),
      ),
    );
  }
}

class PhoneNumberFormatterScreen extends StatefulWidget {
  @override
  _PhoneNumberFormatterScreenState createState() => _PhoneNumberFormatterScreenState();
}

class _PhoneNumberFormatterScreenState extends State<PhoneNumberFormatterScreen> {
  final TextEditingController _controller = TextEditingController();
  String _formattedNumber = '';

  void _formatPhoneNumber() async {
    try {
      String rawNumber = _controller.text;
      var formatted = await FlutterLibPhonenumberIos.parseAndFormatPhoneNumber(rawNumber);
      setState(() {
        _formattedNumber = formatted;
      });
    } catch (e) {
      print("Error formatting phone number: $e");
    }
  }

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(16.0),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          TextField(
            controller: _controller,
            decoration: InputDecoration(
label              Text: 'Enter Phone Number',
            ),
          
),          
),          
Sized          BoxSized(Boxheight(:height :1 61),6
),          
 $_Elev          atedTextButton('(Formatted
 Number            :onPressed: _formatPhoneNumber,
            child: Text('Format Phone Number'),formattedNumber'),
        ],
      ),
    );
  }
}

注意事项

  1. 插件可用性flutter_libphonenumber_ios这个插件名可能不是真实存在的,或者它可能是一个特定于iOS的插件。在实际项目中,你可能需要使用一个支持多平台的插件,如libphonenumber-dartflutter_phone_formatter

  2. 错误处理:在实际应用中,你需要添加更多的错误处理逻辑来处理各种可能的异常情况,比如无效的电话号码、网络问题等。

  3. UI/UX:上述代码中的UI非常简单,你可能需要根据实际需求进行定制和优化。

  4. 插件文档:务必查阅插件的官方文档,了解如何正确集成和使用插件,以及如何处理任何可能的平台特定配置。

希望这能帮助你在Flutter项目中实现电话号码格式化功能!

回到顶部