Flutter如何实现自定义数据地址选择器

在Flutter中如何实现一个自定义的数据地址选择器?我需要实现一个类似三级联动的选择器,可以自由配置省市区的数据源,同时支持自定义UI样式(比如修改选中项的颜色、字体大小等)。目前尝试使用DropdownButton发现无法满足需求,是否有更合适的组件或方案?最好能提供完整的实现思路和关键代码示例。

2 回复

Flutter中实现自定义地址选择器,常用方法:

  1. 使用第三方库如city_pickersflutter_picker
  2. 自定义组件:结合showModalBottomSheetListView实现级联选择
  3. 数据源:加载本地JSON或调用API获取省市区数据
  4. 通过GestureDetectorAnimationController实现滑动交互

核心步骤:准备数据、构建UI、处理选择事件、返回结果。

更多关于Flutter如何实现自定义数据地址选择器的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


在Flutter中实现自定义数据地址选择器,可以通过以下步骤完成:

1. 数据结构设计

首先定义地址数据模型:

class Address {
  final String code;
  final String name;
  final List<Address>? children;
  
  Address({required this.code, required this.name, this.children});
}

2. 核心实现方案

方案一:使用第三方库

推荐使用flutter_picker库快速实现:

dependencies:
  flutter_picker: ^2.1.7
import 'package:flutter_picker/flutter_picker.dart';

void showAddressPicker(BuildContext context) {
  Picker(
    adapter: PickerDataAdapter<String>(pickerdata: [
      ['北京', '上海', '广州'],
      ['朝阳区', '海淀区', '西城区'],
      ['街道1', '街道2', '街道3']
    ]),
    onConfirm: (Picker picker, List value) {
      print(value); // 选中的索引
      print(picker.getSelectedValues()); // 选中的值
    }
  ).showDialog(context);
}

方案二:自定义实现

使用ListViewGridView构建级联选择器:

class AddressPicker extends StatefulWidget {
  @override
  _AddressPickerState createState() => _AddressPickerState();
}

class _AddressPickerState extends State<AddressPicker> {
  List<Address> provinces = [];
  List<Address> cities = [];
  List<Address> areas = [];
  
  Address? selectedProvince;
  Address? selectedCity;
  Address? selectedArea;

  @override
  Widget build(BuildContext context) {
    return Row(
      children: [
        // 省份选择
        Expanded(
          child: ListView.builder(
            itemCount: provinces.length,
            itemBuilder: (ctx, index) => ListTile(
              title: Text(provinces[index].name),
              onTap: () => _onProvinceSelected(provinces[index]),
            ),
          ),
        ),
        // 城市选择
        Expanded(
          child: ListView.builder(
            itemCount: cities.length,
            itemBuilder: (ctx, index) => ListTile(
              title: Text(cities[index].name),
              onTap: () => _onCitySelected(cities[index]),
            ),
          ),
        ),
        // 区域选择
        Expanded(
          child: ListView.builder(
            itemCount: areas.length,
            itemBuilder: (ctx, index) => ListTile(
              title: Text(areas[index].name),
              onTap: () => _onAreaSelected(areas[index]),
            ),
          ),
        ),
      ],
    );
  }

  void _onProvinceSelected(Address province) {
    setState(() {
      selectedProvince = province;
      cities = province.children ?? [];
      areas = [];
    });
  }

  void _onCitySelected(Address city) {
    setState(() {
      selectedCity = city;
      areas = city.children ?? [];
    });
  }

  void _onAreaSelected(Address area) {
    setState(() {
      selectedArea = area;
    });
    // 返回选择结果
    Navigator.pop(context, {
      'province': selectedProvince,
      'city': selectedCity,
      'area': selectedArea
    });
  }
}

3. 数据加载

可以从本地JSON文件或API加载地址数据:

Future<void> loadAddressData() async {
  String data = await rootBundle.loadString('assets/address.json');
  List<dynamic> jsonList = json.decode(data);
  provinces = jsonList.map((item) => Address.fromJson(item)).toList();
}

4. 使用方式

ElevatedButton(
  onPressed: () async {
    final result = await showModalBottomSheet(
      context: context,
      builder: (ctx) => AddressPicker(),
    );
    print(result);
  },
  child: Text('选择地址'),
)

优化建议

  • 添加搜索功能
  • 支持定位当前城市
  • 添加选中状态样式
  • 使用Provider或Bloc进行状态管理

这种方法既保持了灵活性,又能满足自定义需求,可以根据具体业务场景调整UI样式和交互逻辑。

回到顶部