You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中点击分区后基于ID筛选展示对应地点列表的实现需求

Flutter 实现分区点击筛选地点功能

实现核心逻辑

  • 维护选中分区ID的状态,点击分区时更新该状态
  • 根据选中ID过滤LocationLists中对应的数据
  • 将过滤后的数据传入GridView.builder展示

方式一:基础 StatefulWidget 实现

直接在页面内部管理选中状态,适合简单场景:

import 'package:flutter/material.dart';
// 导入你的 DivisionClass 和 Locations 类

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

  @override
  State<LocationFilterScreen> createState() => _LocationFilterScreenState();
}

class _LocationFilterScreenState extends State<LocationFilterScreen> {
  String? _selectedDivisionId;
  final DivisionLists _divisionData = DivisionLists();
  final LocationLists _locationData = LocationLists();

  @override
  Widget build(BuildContext context) {
    // 过滤对应ID的地点数据
    final filteredLocations = _selectedDivisionId == null
        ? _locationData.locationList
        : _locationData.locationList
            .where((loc) => loc.id == _selectedDivisionId)
            .toList();

    return Scaffold(
      appBar: AppBar(title: const Text('分区地点筛选')),
      body: Column(
        children: [
          // 横向分区选择栏
          SizedBox(
            height: 80,
            child: ListView.builder(
              scrollDirection: Axis.horizontal,
              padding: const EdgeInsets.symmetric(horizontal: 8),
              itemCount: _divisionData.divisionList.length,
              itemBuilder: (ctx, index) {
                final division = _divisionData.divisionList[index];
                return Padding(
                  padding: const EdgeInsets.symmetric(horizontal: 8),
                  child: GestureDetector(
                    onTap: () => setState(() => _selectedDivisionId = division.id),
                    child: Container(
                      padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
                      decoration: BoxDecoration(
                        color: _selectedDivisionId == division.id ? Colors.blue : Colors.grey.shade200,
                        borderRadius: BorderRadius.circular(20),
                      ),
                      child: Text(
                        division.divisionName!,
                        style: TextStyle(
                          color: _selectedDivisionId == division.id ? Colors.white : Colors.black,
                          fontWeight: FontWeight.bold,
                        ),
                      ),
                    ),
                  ),
                );
              },
            ),
          ),
          // 地点展示 GridView
          Expanded(
            child: GridView.builder(
              padding: const EdgeInsets.all(16),
              gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
                crossAxisCount: 2,
                crossAxisSpacing: 16,
                mainAxisSpacing: 16,
                childAspectRatio: 0.8,
              ),
              itemCount: filteredLocations.length,
              itemBuilder: (ctx, index) {
                final location = filteredLocations[index];
                return Card(
                  elevation: 4,
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Expanded(
                        child: Image.network(
                          location.dImageUrl!,
                          fit: BoxFit.cover,
                          width: double.infinity,
                        ),
                      ),
                      Padding(
                        padding: const EdgeInsets.all(8),
                        child: Text(
                          location.locationName!,
                          style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
                        ),
                      ),
                      Padding(
                        padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
                        child: Text(
                          location.locationDescription!,
                          style: const TextStyle(fontSize: 12, color: Colors.grey),
                          maxLines: 2,
                          overflow: TextOverflow.ellipsis,
                        ),
                      ),
                    ],
                  ),
                );
              },
            ),
          ),
        ],
      ),
    );
  }
}

方式二:结合 Provider 全局状态管理

适合需要跨页面共享选中状态的场景:

1. 扩展 LocationLists 添加过滤方法

class LocationLists with ChangeNotifier {
  final List<Locations> _locationlists = [
    // 你的地点数据
  ];

  List<Locations> get locationList => _locationlists;

  // 根据分区ID过滤地点
  List<Locations> getFilteredLocations(String? divisionId) {
    if (divisionId == null) return _locationlists;
    return _locationlists.where((loc) => loc.id == divisionId).toList();
  }
}

2. 创建筛选状态管理类

class FilterState with ChangeNotifier {
  String? _selectedDivisionId;

  String? get selectedDivisionId => _selectedDivisionId;

  void updateSelectedDivision(String? id) {
    _selectedDivisionId = id;
    notifyListeners();
  }
}

3. 在 main.dart 注册 Provider

void main() {
  runApp(
    MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (_) => DivisionLists()),
        ChangeNotifierProvider(create: (_) => LocationLists()),
        ChangeNotifierProvider(create: (_) => FilterState()),
      ],
      child: const MyApp(),
    ),
  );
}

4. 实现筛选页面

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

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

  @override
  Widget build(BuildContext context) {
    final divisionData = Provider.of<DivisionLists>(context);
    final locationData = Provider.of<LocationLists>(context);
    final filterState = Provider.of<FilterState>(context);

    final filteredLocations = locationData.getFilteredLocations(filterState.selectedDivisionId);

    return Scaffold(
      appBar: AppBar(title: const Text('分区地点筛选')),
      body: Column(
        children: [
          // 横向分区选择栏
          SizedBox(
            height: 80,
            child: ListView.builder(
              scrollDirection: Axis.horizontal,
              padding: const EdgeInsets.symmetric(horizontal: 8),
              itemCount: divisionData.divisionList.length,
              itemBuilder: (ctx, index) {
                final division = divisionData.divisionList[index];
                return Padding(
                  padding: const EdgeInsets.symmetric(horizontal: 8),
                  child: GestureDetector(
                    onTap: () => filterState.updateSelectedDivision(division.id),
                    child: Container(
                      padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
                      decoration: BoxDecoration(
                        color: filterState.selectedDivisionId == division.id ? Colors.blue : Colors.grey.shade200,
                        borderRadius: BorderRadius.circular(20),
                      ),
                      child: Text(
                        division.divisionName!,
                        style: TextStyle(
                          color: filterState.selectedDivisionId == division.id ? Colors.white : Colors.black,
                          fontWeight: FontWeight.bold,
                        ),
                      ),
                    ),
                  ),
                );
              },
            ),
          ),
          // 地点展示 GridView
          Expanded(
            child: GridView.builder(
              padding: const EdgeInsets.all(16),
              gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
                crossAxisCount: 2,
                crossAxisSpacing: 16,
                mainAxisSpacing: 16,
                childAspectRatio: 0.8,
              ),
              itemCount: filteredLocations.length,
              itemBuilder: (ctx, index) {
                final location = filteredLocations[index];
                return Card(
                  elevation: 4,
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Expanded(
                        child: Image.network(
                          location.dImageUrl!,
                          fit: BoxFit.cover,
                          width: double.infinity,
                        ),
                      ),
                      Padding(
                        padding: const EdgeInsets.all(8),
                        child: Text(
                          location.locationName!,
                          style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
                        ),
                      ),
                      Padding(
                        padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
                        child: Text(
                          location.locationDescription!,
                          style: const TextStyle(fontSize: 12, color: Colors.grey),
                          maxLines: 2,
                          overflow: TextOverflow.ellipsis,
                        ),
                      ),
                    ],
                  ),
                );
              },
            ),
          ),
        ],
      ),
    );
  }
}

内容的提问来源于stack exchange,提问作者NoobInCode

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 07:20:36