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

Flutter分类栏添加点击事件及对应内容切换实现咨询

Flutter分类栏点击切换内容实现方案

核心思路

要实现分类点击切换内容,需要状态管理记录当前选中的分类,再根据选中分类过滤并展示对应内容。具体步骤如下:


步骤1:将StatelessWidget改为StatefulWidget

因为需要维护选中状态和内容展示的变化,StatelessWidget无法保存状态,所以改成带状态的组件。

步骤2:添加状态变量

在状态类中定义两个关键变量:

  • selectedCategoryIndex:记录当前选中的分类索引,默认选中第一个(All)
  • contentData:模拟不同分类对应的内容数据,可根据实际需求替换为真实数据

步骤3:为分类栏添加点击事件

用InkWell包裹分类的Container,点击时更新selectedCategoryIndex,同时通过颜色变化反馈选中状态。

步骤4:根据选中分类展示对应内容

根据selectedCategoryIndex过滤contentData,动态生成对应分类的内容项。


完整修改后的代码

import 'package:flutter/material.dart';

var category = [
  'All',
  'Events',
  'Activities',
  'Restaurants',
  'Malls',
];

// 模拟内容数据,每个item包含分类标识和展示内容
final List<Map<String, dynamic>> contentData = [
  {'category': 'All', 'title': '全城热门推荐', 'color': Colors.deepPurple},
  {'category': 'Events', 'title': '音乐节', 'color': Colors.orange},
  {'category': 'Events', 'title': '艺术展览', 'color': Colors.orange},
  {'category': 'Activities', 'title': '户外徒步', 'color': Colors.green},
  {'category': 'Activities', 'title': '亲子乐园', 'color': Colors.green},
  {'category': 'Restaurants', 'title': '海鲜餐厅', 'color': Colors.red},
  {'category': 'Restaurants', 'title': '网红咖啡馆', 'color': Colors.red},
  {'category': 'Malls', 'title': '购物广场A', 'color': Colors.blue},
  {'category': 'Malls', 'title': '奥特莱斯', 'color': Colors.blue},
];

class PostScreen1 extends StatefulWidget {
  @override
  State<PostScreen1> createState() => _PostScreen1State();
}

class _PostScreen1State extends State<PostScreen1> {
  // 默认选中第一个分类(All)
  int selectedCategoryIndex = 0;

  @override
  Widget build(BuildContext context) {
    // 根据选中的分类过滤内容
    List<Map<String, dynamic>> filteredContent = contentData.where((item) {
      if (selectedCategoryIndex == 0) { // 选中All时展示所有内容
        return true;
      }
      return item['category'] == category[selectedCategoryIndex];
    }).toList();

    return Scaffold(
      body: SafeArea(
        child: CustomScrollView(
          slivers: [
            SliverAppBar(
              backgroundColor: Colors.deepPurple,
              expandedHeight: 300,
              floating: false,
              pinned: true,
              flexibleSpace: FlexibleSpaceBar(
                title: const Text('Jubail'),
                background: Image.asset(
                  'assets/images/image1.jpg',
                  fit: BoxFit.cover,
                ),
              ),
            ),
            // 分类栏
            const SliverToBoxAdapter(
              child: SizedBox(height: 15),
            ),
            SliverToBoxAdapter(
              child: SingleChildScrollView(
                scrollDirection: Axis.horizontal,
                child: Padding(
                  padding: const EdgeInsets.all(8),
                  child: Row(
                    children: [
                      for (int i = 0; i < category.length; i++)
                        InkWell(
                          onTap: () {
                            // 点击时更新选中索引,触发UI重建
                            setState(() {
                              selectedCategoryIndex = i;
                            });
                          },
                          child: Container(
                            margin: const EdgeInsets.symmetric(horizontal: 5),
                            padding: const EdgeInsets.all(15),
                            // 根据选中状态切换背景色
                            decoration: BoxDecoration(
                              color: selectedCategoryIndex == i
                                  ? Colors.deepPurple
                                  : const Color.fromARGB(255, 126, 84, 199),
                              borderRadius: BorderRadius.circular(14),
                              boxShadow: [
                                BoxShadow(
                                  color: const Color.fromARGB(255, 247, 246, 248),
                                  blurRadius: 4,
                                ),
                              ],
                            ),
                            child: Text(
                              category[i],
                              style: const TextStyle(
                                fontSize: 16,
                                fontWeight: FontWeight.w500,
                                color: Colors.white,
                              ),
                            ),
                          ),
                        ),
                    ],
                  ),
                ),
              ),
            ),
            // 内容区域:根据过滤后的内容动态生成
            SliverList(
              delegate: SliverChildBuilderDelegate(
                (context, index) {
                  final item = filteredContent[index];
                  return Padding(
                    padding: const EdgeInsets.all(15),
                    child: ClipRRect(
                      borderRadius: BorderRadius.circular(20),
                      child: Container(
                        height: 200,
                        color: item['color'],
                        child: Stack(
                          children: [
                            Positioned(
                              top: 10,
                              right: 10,
                              child: InkWell(
                                onTap: () {},
                                child: Container(
                                  padding: const EdgeInsets.all(10),
                                  decoration: BoxDecoration(
                                    color: Colors.white,
                                    borderRadius: BorderRadius.circular(15),
                                    boxShadow: [
                                      BoxShadow(
                                        color: Colors.black26,
                                        blurRadius: 6,
                                      ),
                                    ],
                                  ),
                                  child: const Icon(
                                    Icons.favorite_border_outlined,
                                    color: Color.fromARGB(255, 53, 31, 142),
                                    size: 20,
                                  ),
                                ),
                              ),
                            ),
                            // 添加内容标题,方便区分不同分类的内容
                            Center(
                              child: Text(
                                item['title'],
                                style: const TextStyle(
                                  fontSize: 20,
                                  color: Colors.white,
                                  fontWeight: FontWeight.bold,
                                ),
                              ),
                            ),
                          ],
                        ),
                      ),
                    ),
                  );
                },
                childCount: filteredContent.length,
              ),
            ),
          ],
        ),
      ),
    );
  }
}

关键说明

  • 状态管理:通过setState更新选中索引,触发UI重新渲染,实现分类切换的视觉反馈和内容更新。
  • 内容过滤:使用where方法根据选中的分类过滤内容,选中All时展示全部内容。
  • 交互反馈:分类按钮的背景色会随选中状态变化,让用户清晰知道当前选中的分类。
  • 内容优化:把原本重复的内容改成SliverList动态生成,更符合Flutter的性能优化原则,也方便维护。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 19:40:55