Flutter世界国家信息插件world_countries的使用

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

Flutter世界国家信息插件world_countries的使用

概述

world_countries 是一个基于ISO标准且完全测试过的包,提供了关于世界各国、货币、语言等信息。这些信息以编译时、树可摇动的常量密封类形式提供,并支持自定义选择器。这是一个在 sealed_countries 包基础上的Flutter封装,扩展了所有国家、货币、语言的数据,如代码、名称、翻译等,并提供了用于显示国家、语言、货币列表和选择器的现成小部件。国旗是通过优化的 CustomPainter 创建的,底层依赖于 world_flags 包。

目录

特性

该包提供了以下现成的小部件和类:

  • CountryPicker - 显示世界各国列表的选择器小部件。
  • PhoneCodePicker - 显示电话区号列表的选择器小部件。
  • CurrencyPicker - 显示法定货币列表的选择器小部件。
  • LanguagePicker - 显示自然语言列表的选择器小部件。

你也可以通过扩展 BasicPicker 来创建自己的选择器。

  • TypedLocaleDelegate - 用于自动翻译选择器的区域设置委托。提供包括所有 GlobalMaterialLocalizationsGlobalCupertinoLocalizations 区域设置在内的翻译。
  • PickersThemeData, FlagThemeData, CountryTileThemeData, CurrencyTileThemeDataLanguageTileThemeData 是主题扩展,可以在 ThemeData 中使用,以指定全局选择器主题或瓷砖主题(例如国家标志调整或构建器)。

演示

要预览示例中的演示,可以访问 此网页 使用 Chrome 浏览器(版本 119 或更高)。请允许最多 10 秒的时间进行初始字体和数据缓存。

注意:请记住,演示是使用 Flutter WASM 构建的,处于非常早期的 alpha 阶段,因此性能可能受到影响。

开始使用

要使用此包,你需要 Flutter 版本 3.19+。在你的 pubspec.yaml 文件中添加 world_countries 作为依赖项。

dependencies:
  world_countries: any

用法

你可以直接使用提供的小部件,或者使用它们的方法:

  • searchSuggestions(用于 SearchAnchorsuggestionsBuilder
  • showInModalBottomSheet
  • showInSearch
  • showInDialog

本地化

为了自动翻译选择器,只需在你的应用小部件中添加委托:

MaterialApp(localizationsDelegates: [TypedLocaleDelegate()])

然后你也可以通过 context.maybeLocale 获取器从上下文中提取此委托数据(从 BuildContext 中)。

你还可以通过提供翻译参数来强制选择器使用特定的区域设置(例如,translation: IsoLocale.withTranslationsCache(LangEng()) 将显示英文名称)。

包还提供了对 TypedLocaleIsoLocale 类的访问,允许你使用类型安全版本的默认 Locale。你也可以在 translation()maybeTranslation() 方法中利用它们(可以与国家/货币/语言数据一起使用)。

示例

以下是一个完整的示例代码,展示了如何使用 world_countries 包中的小部件:

import "dart:async" show unawaited;
import "package:flutter/material.dart";
import "package:flutter_localizations/flutter_localizations.dart";
import "package:world_countries/world_countries.dart";

void main() => runApp(
  MaterialApp(
    home: const MainPage(),
    theme: ThemeData(
      extensions: const <ThemeExtension>[
        PickersThemeData(primary: true), // 指定全局选择器主题。
        FlagThemeData(
          decoration: BoxDecoration(borderRadius: BorderRadius.all(Radius.circular(4))),
        ),
      ],
    ),
    localizationsDelegates: const [
      GlobalMaterialLocalizations.delegate,
      GlobalCupertinoLocalizations.delegate,
      TypedLocaleDelegate(
        localeMapResolution: [
          LocaleEntry(
            Locale("pt", "BR"),
            IsoLocale(LangPor(), country: CountryPrt()),
          ),
        ],
      ),
    ],
    supportedLocales: [
      for (final locale in kMaterialSupportedLanguages) Locale(locale),
      const Locale("pt", "PT"),
      const Locale("pt", "BR"),
    ],
  ),
);

class MainPage extends StatefulWidget {
  const MainPage({
    super.key,
    this.basicPicker = const CountryPicker(disabled: [CountryAbw()]),
  });

  final CountryPicker basicPicker;

  @override
  State<MainPage> createState() => _MainPageState();
}

class _MainPageState extends State<MainPage> with SingleTickerProviderStateMixin {
  late CountryPicker picker = widget.basicPicker.copyWith(onSelect: onSelect);

  void onSelect(WorldCountry newCountry) {
    debugPrint("New country selected: $selectedCountry");
    setState(
      () => picker = picker.copyWith(
        chosen: selectedCountry == newCountry ? const [] : [newCountry],
      ),
    );
  }

  void onFabPressed({bool isLongPress = false}) {
    final phonePicker = PhoneCodePicker.fromCountryPicker(picker);
    unawaited(
      isLongPress
          ? phonePicker.showInDialog(context)
          : phonePicker.showInModalBottomSheet(context),
    );
  }

  void onAppBarSearchLongPressed() => unawaited(picker.showInSearch(context));

  WorldCountry? get selectedCountry => picker.chosen?.firstOrNull;

  @override
  Widget build(BuildContext context) => Scaffold(
    appBar: AppBar(
      actions: [
        SearchAnchor(
          isFullScreen: false,
          viewConstraints: const BoxConstraints(minWidth: 220, maxWidth: 320),
          builder: (_, controller) => GestureDetector(
            onLongPress: onAppBarSearchLongPressed,
            child: IconButton(
              onPressed: controller.openView,
              icon: const Icon(Icons.search),
            ),
          ),
          suggestionsBuilder: picker.searchSuggestions,
        ),
      ],
    ),
    body: Center(
      child: MaybeWidget(
        selectedCountry?.maybeTranslation(BasicLocale(LangEng()))?.name,
        Text.new,
        orElse: const Text(
          "Please select country by pressing on the search icon",
        ),
      ),
    ),
    floatingActionButton: GestureDetector(
      onLongPress: () => onFabPressed(isLongPress: true),
      child: FloatingActionButton(
        onPressed: onFabPressed,
        child: const Icon(Icons.search),
      ),
    ),
  );
}

更多用法示例,请参见 /example 文件夹。

数据

选择器提供了大量关于国家、语言和货币的信息:

  • PhoneCodePickerCountryPicker 处理 WorldCountry 数据。
  • LanguagePicker - 处理 NaturalLanguage 和脚本数据。
  • CurrencyPicker - 处理 FiatCurrency 数据。

附加信息

有关使用此包的更多信息,请查阅API文档。如果你有任何问题或建议,请在GitHub仓库中提交。欢迎提交PR或提出想法。如果你喜欢这个包,请给它一个星标或点赞。

参考资料和致谢

此包受 MIT 许可证保护。详情请参阅 LICENSE。此包的依赖项受其各自的许可证保护(可以在各自的文件夹下的 LICENSE 和 NOTICE 文件中找到)。


常见问题

我不喜欢选择器中默认的瓷砖UI

答:每个选择器都有一个 itemBuilder 参数,提供对特定列表项属性的访问。例如,这是如何在 CountryPicker 中仅显示表情符号旗帜:

CountryPicker(
  itemBuilder: (country, {isDense}) => EmojiFlag.platformDefault(country.item),
);

为什么我应该使用这个包而不是其他任何国家/货币/语言选择器包?

  • 每个旗帜都是一个小部件:此包不使用沉重的SVG或其他资产来显示选择器中的国家旗帜。所有旗帜都是声明式优化的 CustomPainter。这意味着你不必担心预缓存、增加应用大小、平台依赖的旗帜外观等问题。并且由于它是小部件,你可以随时更改其外观——形状、装饰、宽高比等。例如,如何轻松更改基于资产的旗帜的宽高比而不拉伸/缩小它们。
  • 完全无障碍:所有选择器都经过精心设计,考虑了无障碍性,确保与屏幕阅读器和辅助技术无缝集成。
  • 最新的旗帜:此包确保准确及时的旗帜表示,反映当前设计。与其他包或表情符号/字体集不同,这些包或集通常使用过时的旗帜,此包提供最新型号的旗帜(例如,2013年的阿富汗旗帜在这里正确显示为2021年的设计)。
  • 密封类:此包以密封类的形式提供数据,允许你创建自己的实例并像处理现有实例一样处理它们(例如,这在枚举或常规类中是不可能的(不会失去其密封性质),你还可以覆盖现有数据或添加新数据等)。
  • 无第三方依赖:此包没有第三方依赖,确保你不会遇到任何依赖冲突问题(甚至没有 meta,因为这一点)。
  • 丰富的数据:此包提供的数据比任何其他包都多,加上大量的翻译(所有 GlobalMaterialLocalizationsGlobalCupertinoLocalizations 区域设置和更多)。
  • 类型安全:此包中的契约和类型非常强大,确保你的代码是强类型且定义明确。
  • 高代码覆盖率:此包的代码几乎有100%的测试覆盖率,近5000个测试(150+在此包中,4828+在底层Dart包中)确保可靠性和稳定性。
  • 全面的文档:此包为每个非代码生成的公共成员提供完整文档,通常带有示例,确保清晰易用。
  • 行业采用:此包被多家欧洲公司积极用于生产,确保其在实际场景中的有效性和稳健性。
  • MIT许可:此包及其源代码发布在 MIT 许可下,这是一种宽松的许可,允许用户使用、修改和分发代码,而无需担心法律影响。MIT 许可被认为是大多数其他开源许可更好的选择,因为它提供了灵活性,允许用户将代码纳入他们的项目中,而不必担心法律后果。

更多关于Flutter世界国家信息插件world_countries的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter世界国家信息插件world_countries的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是一个关于如何在Flutter项目中使用world_countries插件来获取和显示世界国家信息的代码案例。这个插件可以帮助你获取国家的名称、代码、区域、货币等信息。

首先,你需要在pubspec.yaml文件中添加world_countries依赖:

dependencies:
  flutter:
    sdk: flutter
  world_countries: ^2.0.0  # 请注意版本号,使用最新的稳定版本

然后运行flutter pub get来获取依赖。

接下来,你可以在你的Flutter项目中使用这个插件。以下是一个简单的示例,展示如何获取并显示所有国家的名称和代码:

import 'package:flutter/material.dart';
import 'package:world_countries/world_countries.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'World Countries Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: WorldCountriesScreen(),
    );
  }
}

class WorldCountriesScreen extends StatefulWidget {
  @override
  _WorldCountriesScreenState createState() => _WorldCountriesScreenState();
}

class _WorldCountriesScreenState extends State<WorldCountriesScreen> {
  List<Country> countries = [];

  @override
  void initState() {
    super.initState();
    loadCountries();
  }

  Future<void> loadCountries() async {
    countries = await WorldCountries.getAllCountries();
    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('World Countries'),
      ),
      body: countries.isEmpty
          ? Center(child: CircularProgressIndicator())
          : ListView.builder(
              itemCount: countries.length,
              itemBuilder: (context, index) {
                Country country = countries[index];
                return ListTile(
                  title: Text('${country.name} (${country.code})'),
                  subtitle: Text('Region: ${country.region}, Currency: ${country.currency}'),
                );
              },
            ),
    );
  }
}

在这个示例中:

  1. WorldCountries.getAllCountries()方法用于异步获取所有国家的列表。
  2. initState方法中调用loadCountries来加载国家数据,并在数据加载完成后调用setState来更新UI。
  3. 使用ListView.builder来构建一个滚动列表,显示每个国家的名称、代码、区域和货币信息。

你可以根据需要进一步自定义和扩展这个示例,例如添加搜索功能、筛选特定区域的国家、显示更多国家信息等。这个插件提供了丰富的国家数据,你可以查阅其文档以了解更多可用属性和方法。

回到顶部