countrify 2.2.0 copy "countrify: ^2.2.0" to clipboard
countrify: ^2.2.0 copied to clipboard

A beautiful, customizable country picker for Flutter. 250 countries, 5,300+ states and 150,000+ cities, 5 display modes, rich theming, flag images, phone codes, 132 language translations, 40+ utilities.

example/lib/main.dart

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

void main() => runApp(const CountrifyExampleApp());

class CountrifyExampleApp extends StatelessWidget {
  const CountrifyExampleApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Countrify Example',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorSchemeSeed: Colors.blue,
        useMaterial3: true,
      ),
      home: const HomePage(),
    );
  }
}

class HomePage extends StatelessWidget {
  const HomePage({super.key});

  @override
  Widget build(BuildContext context) {
    return DefaultTabController(
      length: 5,
      child: Scaffold(
        appBar: AppBar(
          title: const Text('Countrify'),
          bottom: const TabBar(
            isScrollable: true,
            tabs: [
              Tab(text: 'Phone Input'),
              Tab(text: 'Country Picker'),
              Tab(text: 'Theming'),
              Tab(text: 'Localization'),
              Tab(text: 'Building Blocks'),
            ],
          ),
        ),
        body: const TabBarView(
          children: [
            PhoneInputTab(),
            CountryPickerTab(),
            ThemingTab(),
            LocalizationTab(),
            BuildingBlocksTab(),
          ],
        ),
      ),
    );
  }
}

// ---------------------------------------------------------------------------
// Tab 1: Phone Input
// ---------------------------------------------------------------------------

class PhoneInputTab extends StatefulWidget {
  const PhoneInputTab({super.key});

  @override
  State<PhoneInputTab> createState() => _PhoneInputTabState();
}

class _PhoneInputTabState extends State<PhoneInputTab> {
  String _phoneNumber = '';
  String _countryName = 'United States';
  String _dialCode = '+1';

  @override
  Widget build(BuildContext context) {
    return ListView(
      padding: const EdgeInsets.all(24),
      children: [
        PhoneNumberField(
          initialCountryCode: CountryCode.us,
          style: CountrifyFieldStyle.defaultStyle().copyWith(
            fillColor: const Color(0xFFF0F4FF),
            focusedFillColor: const Color(0xFFE3ECFF),
            hintText: 'Enter phone number',
          ),
          onChanged: (phoneNumber, country) {
            debugPrint('Phone: +${country.callingCodes.first}$phoneNumber');
            setState(() {
              _phoneNumber = phoneNumber;
              _countryName = country.name;
              _dialCode = '+${country.callingCodes.first}';
            });
          },
        ),
        const SizedBox(height: 24),
        Card(
          child: Padding(
            padding: const EdgeInsets.all(16),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(
                  'Selected country: $_countryName',
                  style: Theme.of(context).textTheme.bodyLarge,
                ),
                const SizedBox(height: 8),
                Text(
                  'Number: $_dialCode $_phoneNumber',
                  style: Theme.of(context).textTheme.bodyLarge,
                ),
              ],
            ),
          ),
        ),
      ],
    );
  }
}

// ---------------------------------------------------------------------------
// Tab 2: Country Picker
// ---------------------------------------------------------------------------

class CountryPickerTab extends StatefulWidget {
  const CountryPickerTab({super.key});

  @override
  State<CountryPickerTab> createState() => _CountryPickerTabState();
}

class _CountryPickerTabState extends State<CountryPickerTab> {
  String _selectedCountry = 'None';
  CountryPickerMode _pickerMode = CountryPickerMode.dropdown;

  @override
  Widget build(BuildContext context) {
    return ListView(
      padding: const EdgeInsets.all(24),
      children: [
        Wrap(
          spacing: 8,
          runSpacing: 8,
          children: [
            _modeButton('Dropdown', CountryPickerMode.dropdown),
            _modeButton('Bottom Sheet', CountryPickerMode.bottomSheet),
            _modeButton('Dialog', CountryPickerMode.dialog),
            _modeButton('Full Screen', CountryPickerMode.fullScreen),
          ],
        ),
        const SizedBox(height: 24),
        CountryDropdownField(
          key: ValueKey(_pickerMode),
          pickerMode: _pickerMode,
          style: CountrifyFieldStyle.defaultStyle().copyWith(
            labelText: 'Select a country',
          ),
          onChanged: (country) {
            setState(() {
              _selectedCountry = country.name;
            });
          },
        ),
        const SizedBox(height: 16),
        Text(
          'Selected: $_selectedCountry',
          style: Theme.of(context).textTheme.titleMedium,
        ),
      ],
    );
  }

  Widget _modeButton(String label, CountryPickerMode mode) {
    final isSelected = _pickerMode == mode;
    return FilledButton(
      onPressed: () => setState(() => _pickerMode = mode),
      style: FilledButton.styleFrom(
        backgroundColor:
            isSelected ? Theme.of(context).colorScheme.primary : Colors.grey,
      ),
      child: Text(label),
    );
  }
}

// ---------------------------------------------------------------------------
// Tab 3: Theming
// ---------------------------------------------------------------------------

class ThemingTab extends StatefulWidget {
  const ThemingTab({super.key});

  @override
  State<ThemingTab> createState() => _ThemingTabState();
}

class _ThemingTabState extends State<ThemingTab> {
  int _selectedTheme = 0;
  static const _themeLabels = ['Default', 'Dark', 'Material 3'];

  CountryPickerTheme get _currentTheme {
    switch (_selectedTheme) {
      case 1:
        return CountryPickerTheme.darkTheme();
      case 2:
        return CountryPickerTheme.material3Theme();
      default:
        return CountryPickerTheme.defaultTheme();
    }
  }

  @override
  Widget build(BuildContext context) {
    return ListView(
      padding: const EdgeInsets.all(24),
      children: [
        Wrap(
          spacing: 8,
          children: List.generate(_themeLabels.length, (i) {
            return ChoiceChip(
              label: Text(_themeLabels[i]),
              selected: _selectedTheme == i,
              onSelected: (_) => setState(() => _selectedTheme = i),
            );
          }),
        ),
        const SizedBox(height: 24),
        PhoneNumberField(
          initialCountryCode: CountryCode.us,
          theme: _currentTheme,
          style: CountrifyFieldStyle.defaultStyle().copyWith(
            hintText: 'Themed phone field',
          ),
          onChanged: (phone, country) {
            debugPrint('Phone: $phone, Country: ${country.name}');
          },
        ),
      ],
    );
  }
}

// ---------------------------------------------------------------------------
// Tab 4: Localization
// ---------------------------------------------------------------------------

class LocalizationTab extends StatefulWidget {
  const LocalizationTab({super.key});

  @override
  State<LocalizationTab> createState() => _LocalizationTabState();
}

class _LocalizationTabState extends State<LocalizationTab> {
  String _selectedLocale = 'en';

  static const _locales = <String, String>{
    'en': 'English',
    'ar': 'Arabic',
    'fr': 'French',
    'es': 'Spanish',
    'de': 'German',
    'zh': 'Chinese',
    'ja': 'Japanese',
  };

  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Padding(
          padding: const EdgeInsets.fromLTRB(24, 24, 24, 16),
          child: DropdownButtonFormField<String>(
            initialValue: _selectedLocale,
            decoration: const InputDecoration(
              labelText: 'Language',
              border: OutlineInputBorder(),
            ),
            items: _locales.entries
                .map((e) => DropdownMenuItem(
                      value: e.key,
                      child: Text(e.value),
                    ))
                .toList(),
            onChanged: (value) {
              if (value != null) setState(() => _selectedLocale = value);
            },
          ),
        ),
        Expanded(
          child: CountryPicker(
            key: ValueKey(_selectedLocale),
            pickerType: CountryPickerType.inline,
            config: CountryPickerConfig(locale: _selectedLocale),
            onCountrySelected: (country) {
              debugPrint('Selected: ${country.name}');
            },
          ),
        ),
      ],
    );
  }
}

// ---------------------------------------------------------------------------
// Tab 5: Building Blocks
// ---------------------------------------------------------------------------

class BuildingBlocksTab extends StatelessWidget {
  const BuildingBlocksTab({super.key});

  @override
  Widget build(BuildContext context) {
    final us = CountryUtils.getCountryByCode(CountryCode.us)!;
    final gb = CountryUtils.getCountryByCode(CountryCode.gb)!;
    final jp = CountryUtils.getCountryByCode(CountryCode.jp)!;
    final br = CountryUtils.getCountryByCode(CountryCode.br)!;

    return ListView(
      padding: const EdgeInsets.all(24),
      children: [
        Text('CountryFlag', style: Theme.of(context).textTheme.titleMedium),
        const SizedBox(height: 12),
        Wrap(
          spacing: 16,
          runSpacing: 8,
          children: [
            CountryFlag(country: us, size: const Size(48, 36)),
            CountryFlag(country: gb, size: const Size(48, 36)),
            CountryFlag(country: jp, size: const Size(48, 36)),
            CountryFlag(country: br, size: const Size(48, 36)),
          ],
        ),
        const SizedBox(height: 32),
        Text(
          'CountrySearchBar',
          style: Theme.of(context).textTheme.titleMedium,
        ),
        const SizedBox(height: 12),
        CountrySearchBar(
          hintText: 'Search countries...',
          onChanged: (query) => debugPrint('Search: $query'),
        ),
        const SizedBox(height: 32),
        Text(
          'CountryListTile',
          style: Theme.of(context).textTheme.titleMedium,
        ),
        const SizedBox(height: 12),
        CountryListTile(
          country: us,
          isSelected: true,
          onTap: (country) => debugPrint('Tapped: ${country.name}'),
        ),
        CountryListTile(
          country: gb,
          onTap: (country) => debugPrint('Tapped: ${country.name}'),
        ),
        CountryListTile(
          country: jp,
          onTap: (country) => debugPrint('Tapped: ${country.name}'),
        ),
        CountryListTile(
          country: br,
          onTap: (country) => debugPrint('Tapped: ${country.name}'),
        ),
      ],
    );
  }
}
35
likes
0
points
1.71k
downloads

Publisher

verified publishergocodeable.com

Weekly Downloads

A beautiful, customizable country picker for Flutter. 250 countries, 5,300+ states and 150,000+ cities, 5 display modes, rich theming, flag images, phone codes, 132 language translations, 40+ utilities.

Homepage
Repository (GitHub)
View/report issues

Topics

#country-picker #country #state #city #widget

License

unknown (license)

Dependencies

flutter

More

Packages that depend on countrify