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

Flutter中TabBar切换当前索引时如何实现选中项高度动态变化

问题原因

你当前的实现没有绑定Tab选中索引的状态监听,也没有根据动态变化的选中索引给所有Tab项统一应用样式规则,所以选中逻辑只能对固定索引起效,无法适配全量切换场景。

实现方案

核心思路是手动管控TabController实例,实时监听选中索引变化,通过状态驱动每个Tab项的尺寸渲染,加上动画组件实现平滑的放大聚焦效果,步骤如下:

  • 手动初始化TabController,添加索引变化监听,用状态变量记录当前选中的Tab索引
  • 遍历生成所有Tab项,每个Tab项根据自身索引和当前选中索引的匹配状态,动态设置高度
  • 用AnimatedContainer包裹Tab内容,实现尺寸切换的过渡动画,避免生硬跳变
  • 调整TabBar默认内边距配置,避免自定义尺寸的Tab出现布局溢出
完整可运行代码
import 'package:flutter/material.dart';

void main() {
  runApp(const MaterialApp(home: MyApp()));
}

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> with TickerProviderStateMixin {
  late TabController _tabController;
  // 记录当前选中的Tab索引,默认选中第一个
  int _selectedIndex = 0;

  @override
  void initState() {
    super.initState();
    _tabController = TabController(length: 3, vsync: this);
    // 监听Tab切换事件
    _tabController.addListener(() {
      if (_tabController.indexIsChanging) {
        setState(() {
          _selectedIndex = _tabController.index;
        });
      }
    });
  }

  @override
  void dispose() {
    _tabController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          backgroundColor: Colors.transparent,
          toolbarHeight: 120,
          bottom: TabBar(
            controller: _tabController,
            // 清除默认内边距,适配自定义Tab尺寸
            labelPadding: EdgeInsets.zero,
            indicatorPadding: EdgeInsets.zero,
            indicator: BoxDecoration(
              border: Border.all(width: 1, color: Colors.deepOrange),
              borderRadius: BorderRadius.circular(10),
              color: Colors.transparent,
            ),
            // 动态生成3个Tab项
            tabs: List.generate(3, (index) {
              return AnimatedContainer(
                duration: const Duration(milliseconds: 200),
                curve: Curves.easeInOut,
                // 选中项高度80,未选中项高度50,可自行调整尺寸差
                height: _selectedIndex == index ? 80 : 50,
                padding: const EdgeInsets.symmetric(horizontal: 8),
                child: Card(
                  child: Image(
                    image: const AssetImage("assets/box.png"),
                    fit: BoxFit.contain,
                  ),
                ),
              );
            }),
          ),
        ),
        body: TabBarView(
          controller: _tabController,
          children: const [
            AmazonBox(),
            AmazonGift(),
            AmazonSave(),
          ],
        ),
      ),
    );
  }
}

// 补全示例缺失的页面组件,实际使用替换为你的业务组件即可
class AmazonBox extends StatelessWidget {
  const AmazonBox({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return const Center(child: Text("AmazonBox页面"));
  }
}

class AmazonGift extends StatelessWidget {
  const AmazonGift({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return const Center(child: Text("AmazonGift页面"));
  }
}

class AmazonSave extends StatelessWidget {
  const AmazonSave({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return const Center(child: Text("AmazonSave页面"));
  }
}
自定义调整说明
  • 可以修改AnimatedContainer的height参数差值,调整选中放大的幅度
  • 可以修改duration参数调整动画时长,替换curve参数调整动画插值效果
  • 如果需要宽度也同步放大,可以给AnimatedContainer加宽度变化的逻辑,或者直接用Transform.scale做整体缩放效果

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 06:21:14