Flutter for OpenHarmony《智慧字典》 App 底部导航栏深度解析:构建多页面应用的核心骨架

Flutter for OpenHarmony《智慧字典》 App 底部导航栏深度解析:构建多页面应用的核心骨架

在移动应用开发中,底部导航栏 (Bottom Navigation Bar) 是组织核心功能、提升用户导航效率的黄金标准。您提供的
import+pa.txt

文件中的代码,展示了一个结构清晰、扩展性强且视觉精美的底部导航实现方案。本文将深入剖析其设计思路、核心代码和最佳实践。


完整效果展示


一、整体架构:解耦与职责分离

该实现最值得称赞的一点是 高度的模块化和职责分离,这为未来的功能扩展和维护奠定了坚实基础。

1.1 核心角色分工

  • MainScreen: 应用的"指挥中心"。它不关心每个标签页内部的具体逻辑,只负责:
  • 管理当前选中的索引 (_currentIndex)。
    • 控制 PageView 的页面切换。
    • 将用户的点击事件 (onTap) 转发给 PageView
  • _pages 列表 : 一个纯粹的 页面容器 。它将各个功能模块 (IdiomTab, EnglishTab, ProfileTab) 实例化并集中管理。要新增一个功能,只需在此列表中添加一项。
  • 独立的 Tab 组件 (IdiomTab, EnglishTab, ProfileTab) : 每个标签页都是一个 完全自治的 StatefulWidget。它们拥有自己的状态、UI 和业务逻辑,互不干扰。

优势 :这种设计使得代码 高内聚、低耦合。修改"我的"页面的逻辑,完全不会影响到"成语"页面,极大地提升了开发效率和代码可维护性。

1.2 关键代码结构

dart 复制代码
// MainScreen 内部
final List<Widget> _pages = [
  const IdiomTab(), // 成语页
  const EnglishTab(), // 英语页
  const ProfileTab(), // 我的页
];

@override
Widget build(BuildContext context) {
  return Scaffold(
    body: PageView( // 1. 页面主体
      controller: _pageController,
      onPageChanged: _onPageChanged, // 同步底部栏选中状态
      children: _pages,
    ),
    bottomNavigationBar: Container( // 2. 底部导航栏
      child: BottomNavigationBar(
        currentIndex: _currentIndex,
        onTap: _onTabTapped, // 同步PageView页面
        items: [...], // 导航项配置
      ),
    ),
  );
}

二、核心技术:PageViewBottomNavigationBar 的双向同步

为了让滑动切换页面和点击底部图标两种交互方式无缝衔接,代码实现了 双向状态同步

2.1 数据流分析

  1. 用户点击底部图标:
  • 触发 _onTabTapped(int index)
    • 该方法调用 _pageController.jumpToPage(index),强制 PageView 跳转到对应页面。
    • 注意 :这里使用 jumpToPage 而非 animateToPage,是为了让切换更迅速直接。
  1. 用户滑动 PageView:
  • 触发 onPageChanged: _onPageChanged 回调。
    • _onPageChanged 方法通过 setState 更新 _currentIndex
    • BottomNavigationBar 监听到 _currentIndex 的变化,自动高亮对应的图标。

2.2 核心同步方法

dart 复制代码
// 当PageView页面改变时,更新底部导航栏的选中状态
void _onPageChanged(int index) {
  setState(() {
    _currentIndex = index;
  });
}

// 当底部导航栏被点击时,跳转PageView到对应页面
void _onTabTapped(int index) {
  _pageController.jumpToPage(index);
}

⚠️ 关键点_onPageChanged 必须调用 setState,因为 _currentIndexBottomNavigationBarcurrentIndex 属性的数据源。只有通过 setState 触发 MainScreen 的重建,底部栏才能感知到状态变化。


三、视觉与交互细节:打造精致体验

除了核心逻辑,代码在视觉呈现上也下足了功夫。

3.1 阴影与层次感

底部导航栏被包裹在一个 Container 中,并为其添加了 向上的阴影

dart 复制代码
decoration: BoxDecoration(
  boxShadow: [
    BoxShadow(
      color: Colors.black.withOpacity(0.1),
      blurRadius: 10,
      offset: const Offset(0, -5), // 注意这里是负Y值,阴影在上方
    ),
  ],
)
  • 效果 :这个阴影让底部导航栏看起来像是从屏幕底部"浮"起来的,与上方的 PageView 内容形成了清晰的视觉分隔,符合 Material Design 的 Z轴层次 原则。

3.2 导航项配置

每个 BottomNavigationBarItem 都配置了 iconactiveIcon,虽然在此例中两者相同,但这种写法为未来实现 激活态图标变化(如填充 vs 线框)预留了空间。

dart 复制代码
items: const [
  BottomNavigationBarItem(
    icon: Icon(Icons.menu_book_rounded),
    activeIcon: Icon(Icons.menu_book_rounded), // 可以设为不同的图标
    label: '成语',
  ),
  // ... 其他项
]

3.3 样式定制

  • 颜色 :通过 selectedItemColorunselectedItemColor 精确控制图标的颜色。
  • 字体 :通过 selectedFontSizeunselectedFontSize 微调标签文字大小,突出选中项。
  • 布局type: BottomNavigationBarType.fixed 确保所有标签(即使超过3个)都始终显示文字和图标。

四、各标签页 (Tab) 的实现策略

每个 Tab 都是一个独立的入口,其实现方式体现了不同的开发考量。

4.1 IdiomTab (成语页)

  • 策略 :作为一个 代理 (Proxy)

  • 代码

    dart 复制代码
    class IdiomTab extends StatefulWidget {
      @override
      State<IdiomTab> createState() => _IdiomTabState();
    }
    
    class _IdiomTabState extends State<IdiomTab> {
      @override
      Widget build(BuildContext context) {
        return const DictionaryHomeScreen(); // 直接返回主页
      }
    }
  • 目的 :将 DictionaryHomeScreen 这个复杂的主功能页面 复用 为"成语"标签页的内容。这是一种避免代码重复的有效手段。

4.2 EnglishTab (英语页) & ProfileTab (我的页)

  • 策略占位与引导
  • 代码 :两个页面都展示了 "功能开发中,敬请期待" 的提示信息,并通过 SnackBar 响应用户点击。
  • 目的
    1. 产品规划:清晰地向用户展示了 App 的未来功能蓝图。
    2. 交互反馈 :即使功能未完成,用户的点击操作也能得到即时响应 (SnackBar),避免了"点击无反应"的糟糕体验。
    3. 开发便利:为后续开发提供了清晰的框架和入口,开发者只需替换占位内容即可。

五、总结:一个教科书式的底部导航实现

这段关于底部导航栏的代码,堪称 Flutter 应用架构的 优秀范例

  1. 架构清晰MainScreen 作为协调者,各 Tab 作为独立模块,职责分明。
  2. 交互流畅 :完美实现了 PageView 滑动和 BottomNavigationBar 点击的双向同步。
  3. 视觉精美:通过阴影、颜色和图标等细节,打造出符合现代审美的 UI。
  4. 扩展性强:无论是增加新页面,还是为现有页面填充功能,都变得异常简单。
  5. 用户体验佳 :即使是未完成的功能,也通过占位符和 SnackBar 提供了良好的用户反馈。

🌐 加入社区

欢迎加入 开源鸿蒙跨平台开发者社区 ,获取最新资源与技术支持:

👉 开源鸿蒙跨平台开发者社区


技术因分享而进步,生态因共建而繁荣

------ 晚霞的不甘 · 与您共赴鸿蒙跨平台开发之旅

完整代码

bash 复制代码
import 'package:flutter/material.dart';

void main() {
  runApp(const DictionaryApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: '智慧字典',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: const Color(0xFF6366F1)),
        useMaterial3: true,
      ),
      home: const MainScreen(),
    );
  }
}

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

  @override
  State<MainScreen> createState() => _MainScreenState();
}

class _MainScreenState extends State<MainScreen> {
  int _currentIndex = 0;
  final PageController _pageController = PageController();

  final List<Widget> _pages = [
    const IdiomTab(),
    const EnglishTab(),
    const ProfileTab(),
  ];

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

  void _onPageChanged(int index) {
    setState(() {
      _currentIndex = index;
    });
  }

  void _onTabTapped(int index) {
    _pageController.jumpToPage(index);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: PageView(
        controller: _pageController,
        onPageChanged: _onPageChanged,
        children: _pages,
      ),
      bottomNavigationBar: Container(
        decoration: BoxDecoration(
          boxShadow: [
            BoxShadow(
              color: Colors.black.withOpacity(0.1),
              blurRadius: 10,
              offset: const Offset(0, -5),
            ),
          ],
        ),
        child: BottomNavigationBar(
          currentIndex: _currentIndex,
          onTap: _onTabTapped,
          selectedItemColor: const Color(0xFF6366F1),
          unselectedItemColor: Colors.grey,
          selectedFontSize: 14,
          unselectedFontSize: 12,
          type: BottomNavigationBarType.fixed,
          elevation: 0,
          items: const [
            BottomNavigationBarItem(
              icon: Icon(Icons.menu_book_rounded),
              activeIcon: Icon(Icons.menu_book_rounded),
              label: '成语',
            ),
            BottomNavigationBarItem(
              icon: Icon(Icons.language_rounded),
              activeIcon: Icon(Icons.language_rounded),
              label: '英语',
            ),
            BottomNavigationBarItem(
              icon: Icon(Icons.person_rounded),
              activeIcon: Icon(Icons.person_rounded),
              label: '我的',
            ),
          ],
        ),
      ),
    );
  }
}

// 成语标签页
class IdiomTab extends StatefulWidget {
  const IdiomTab({super.key});

  @override
  State<IdiomTab> createState() => _IdiomTabState();
}

class _IdiomTabState extends State<IdiomTab> {
  @override
  Widget build(BuildContext context) {
    return const DictionaryHomeScreen();
  }
}

// 英语标签页
class EnglishTab extends StatefulWidget {
  const EnglishTab({super.key});

  @override
  State<EnglishTab> createState() => _EnglishTabState();
}

class _EnglishTabState extends State<EnglishTab> {
  final TextEditingController _searchController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        decoration: BoxDecoration(
          gradient: LinearGradient(
            begin: Alignment.topLeft,
            end: Alignment.bottomRight,
            colors: [
              const Color(0xFF30CFD0),
              const Color(0xFF330867),
            ],
          ),
        ),
        child: SafeArea(
          child: Padding(
            padding: const EdgeInsets.all(24),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                const Text(
                  '英语学习',
                  style: TextStyle(
                    fontSize: 32,
                    fontWeight: FontWeight.bold,
                    color: Colors.white,
                  ),
                ),
                const SizedBox(height: 8),
                Text(
                  '探索英语的世界',
                  style: TextStyle(
                    fontSize: 16,
                    color: Colors.white.withOpacity(0.9),
                  ),
                ),
                const SizedBox(height: 32),
                Container(
                  decoration: BoxDecoration(
                    color: Colors.white,
                    borderRadius: BorderRadius.circular(24),
                    boxShadow: [
                      BoxShadow(
                        color: Colors.black.withOpacity(0.2),
                        blurRadius: 20,
                        offset: const Offset(0, 10),
                      ),
                    ],
                  ),
                  child: TextField(
                    controller: _searchController,
                    style: const TextStyle(fontSize: 18),
                    decoration: InputDecoration(
                      hintText: '搜索英语单词...',
                      hintStyle: TextStyle(
                        color: Colors.grey[400],
                        fontSize: 16,
                      ),
                      prefixIcon: const Icon(
                        Icons.search_rounded,
                        color: Color(0xFF6366F1),
                        size: 28,
                      ),
                      border: InputBorder.none,
                      contentPadding: const EdgeInsets.all(20),
                    ),
                  ),
                ),
                const SizedBox(height: 32),
                Expanded(
                  child: Container(
                    decoration: BoxDecoration(
                      color: Colors.white,
                      borderRadius: BorderRadius.circular(24),
                    ),
                    child: const Center(
                      child: Column(
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: [
                          Icon(
                            Icons.language_rounded,
                            size: 64,
                            color: Color(0xFF30CFD0),
                          ),
                          SizedBox(height: 16),
                          Text(
                            '英语功能开发中',
                            style: TextStyle(
                              fontSize: 20,
                              fontWeight: FontWeight.bold,
                              color: Color(0xFF2D3436),
                            ),
                          ),
                          SizedBox(height: 8),
                          Text(
                            '敬请期待',
                            style: TextStyle(
                              fontSize: 16,
                              color: Color(0xFF636E72),
                            ),
                          ),
                        ],
                      ),
                    ),
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

// 我的标签页
class ProfileTab extends StatefulWidget {
  const ProfileTab({super.key});

  @override
  State<ProfileTab> createState() => _ProfileTabState();
}

class _ProfileTabState extends State<ProfileTab> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        decoration: BoxDecoration(
          gradient: LinearGradient(
            begin: Alignment.topLeft,
            end: Alignment.bottomRight,
            colors: [
              const Color(0xFF667EEA),
              const Color(0xFF764BA2),
            ],
          ),
        ),
        child: SafeArea(
          child: SingleChildScrollView(
            child: Column(
              children: [
                const SizedBox(height: 40),
                // 用户头像
                CircleAvatar(
                  radius: 50,
                  backgroundColor: Colors.white,
                  child: Icon(
                    Icons.person_rounded,
                    size: 60,
                    color: Color(0xFF667EEA),
                  ),
                ),
                const SizedBox(height: 16),
                const Text(
                  '智慧字典',
                  style: TextStyle(
                    fontSize: 24,
                    fontWeight: FontWeight.bold,
                    color: Colors.white,
                  ),
                ),
                const SizedBox(height: 8),
                Text(
                  '探索词语的奥秘',
                  style: TextStyle(
                    fontSize: 16,
                    color: Colors.white.withOpacity(0.9),
                  ),
                ),
                const SizedBox(height: 40),
                // 功能列表
                Container(
                  margin: const EdgeInsets.symmetric(horizontal: 24),
                  decoration: BoxDecoration(
                    color: Colors.white,
                    borderRadius: BorderRadius.circular(24),
                  ),
                  child: Column(
                    children: [
                      _buildMenuItem(
                        icon: Icons.history_rounded,
                        title: '搜索历史',
                        onTap: () {
                          ScaffoldMessenger.of(context).showSnackBar(
                            const SnackBar(content: Text('搜索历史功能开发中')),
                          );
                        },
                      ),
                      _buildMenuItem(
                        icon: Icons.bookmark_rounded,
                        title: '我的收藏',
                        onTap: () {
                          ScaffoldMessenger.of(context).showSnackBar(
                            const SnackBar(content: Text('我的收藏功能开发中')),
                          );
                        },
                      ),
                      _buildMenuItem(
                        icon: Icons.download_rounded,
                        title: '离线词典',
                        onTap: () {
                          ScaffoldMessenger.of(context).showSnackBar(
                            const SnackBar(content: Text('离线词典功能开发中')),
                          );
                        },
                      ),
                      _buildMenuItem(
                        icon: Icons.settings_rounded,
                        title: '设置',
                        onTap: () {
                          ScaffoldMessenger.of(context).showSnackBar(
                            const SnackBar(content: Text('设置功能开发中')),
                          );
                        },
                      ),
                      _buildMenuItem(
                        icon: Icons.info_rounded,
                        title: '关于',
                        onTap: () {
                          ScaffoldMessenger.of(context).showSnackBar(
                            const SnackBar(content: Text('关于功能开发中')),
                          );
                        },
                      ),
                    ],
                  ),
                ),
                const SizedBox(height: 40),
              ],
            ),
          ),
        ),
      ),
    );
  }

  Widget _buildMenuItem({
    required IconData icon,
    required String title,
    required VoidCallback onTap,
  }) {
    return InkWell(
      onTap: onTap,
      child: Container(
        padding: const EdgeInsets.all(20),
        decoration: BoxDecoration(
          border: Border(
            bottom: BorderSide(
              color: Colors.grey[200]!,
              width: 1,
            ),
          ),
        ),
        child: Row(
          children: [
            Icon(
              icon,
              color: const Color(0xFF667EEA),
              size: 24,
            ),
            const SizedBox(width: 16),
            Expanded(
              child: Text(
                title,
                style: const TextStyle(
                  fontSize: 16,
                  fontWeight: FontWeight.w500,
                ),
              ),
            ),
            Icon(
              Icons.chevron_right_rounded,
              color: Colors.grey[400],
            ),
          ],
        ),
      ),
    );
  }
}

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

  @override
  State<DictionaryHomeScreen> createState() => _DictionaryHomeScreenState();
}

class _DictionaryHomeScreenState extends State<DictionaryHomeScreen>
    with SingleTickerProviderStateMixin {
  final TextEditingController _searchController = TextEditingController();
  List<DictionaryEntry> _searchResults = [];
  bool _isSearching = false;
  List<String> _searchHistory = [];
  List<String> _searchSuggestions = [];
  bool _showSuggestions = false;
  late AnimationController _animationController;
  late Animation<double> _fadeInAnimation;

  // 模拟字典数据
  final List<DictionaryEntry> _dictionaryData = [
    // 成语类
    DictionaryEntry(
      word: '一丝不苟',
      pinyin: 'yī sī bù gǒu',
      partOfSpeech: '成语',
      definition: '形容办事认真,连最细微的地方也不马虎。',
      examples: [
        '他工作一丝不苟,从不马虎。',
        '老师批改作业一丝不苟,细致入微。',
        '这位医生一丝不苟地检查每一个病人。',
        '一丝不苟的工作态度值得我们学习。'
      ],
      relatedWords: ['精益求精', '认真细致', '严谨'],
      similarWords: ['粗心大意', '马马虎虎', '敷衍了事'],
      type: '成语',
      gradient: [const Color(0xFF667EEA), const Color(0xFF764BA2)],
    ),
    DictionaryEntry(
      word: '画蛇添足',
      pinyin: 'huà shé tiān zú',
      partOfSpeech: '成语',
      definition: '画蛇时给蛇添上脚。比喻做了多余的事,非但无益,反而不合适。',
      examples: [
        '这篇作文写得很好,最后几句是画蛇添足。',
        '你已经说得很清楚了,再说就是画蛇添足了。',
        '不要做画蛇添足的事情,要学会适可而止。',
        '他在完美的方案上画蛇添足,反而弄巧成拙。'
      ],
      relatedWords: ['多此一举', '节外生枝', '弄巧成拙'],
      similarWords: ['恰如其分', '恰到好处', '画龙点睛'],
      type: '成语',
      gradient: [const Color(0xFFF093FB), const Color(0xFFF5576C)],
    ),
    DictionaryEntry(
      word: '守株待兔',
      pinyin: 'shǒu zhū dài tù',
      partOfSpeech: '成语',
      definition: '比喻希图不经过努力而得到成功的侥幸心理。',
      examples: [
        '我们不能守株待兔,要主动出击。',
        '守株待兔的侥幸心理害人不浅。',
        '与其守株待兔,不如积极行动。',
        '机会总是留给有准备的人,守株待兔是等不到的。'
      ],
      relatedWords: ['坐享其成', '不劳而获', '妄想'],
      similarWords: ['积极进取', '主动出击', '勤奋努力'],
      type: '成语',
      gradient: [const Color(0xFF4FACFE), const Color(0xFF00F2FE)],
    ),
    DictionaryEntry(
      word: '亡羊补牢',
      pinyin: 'wáng yáng bǔ láo',
      partOfSpeech: '成语',
      definition: '比喻出了问题以后想办法补救,可以防止继续受损失。',
      examples: [
        '虽然失败了,但要亡羊补牢,吸取教训。',
        '亡羊补牢,为时不晚。',
        '我们要学会亡羊补牢,及时纠正错误。',
        '亡羊补牢的故事告诉我们:犯错后要及时改正。'
      ],
      relatedWords: ['知错就改', '及时止损', '吸取教训'],
      similarWords: ['执迷不悟', '一错再错', '错上加错'],
      type: '成语',
      gradient: [const Color(0xFFFA709A), const Color(0xFFFEE140)],
    ),
    DictionaryEntry(
      word: '掩耳盗铃',
      pinyin: 'yǎn ěr dào líng',
      partOfSpeech: '成语',
      definition: '比喻自己欺骗自己,明明掩盖不住的事情偏要想法子掩盖。',
      examples: [
        '他试图掩耳盗铃,逃避责任。',
        '掩耳盗铃的做法是自欺欺人。',
        '不要掩耳盗铃,要正视自己的错误。',
        '掩耳盗铃的结果往往是自欺欺人。'
      ],
      relatedWords: ['自欺欺人', '掩人耳目', '自欺'],
      similarWords: ['实事求是', '光明磊落', '坦诚相待'],
      type: '成语',
      gradient: [const Color(0xFF30CFD0), const Color(0xFF330867)],
    ),
    DictionaryEntry(
      word: '刻舟求剑',
      pinyin: 'kè zhōu qiú jiàn',
      partOfSpeech: '成语',
      definition: '比喻拘泥成法,固执不知变通。',
      examples: [
        '时代在变,我们不能刻舟求剑。',
        '刻舟求剑的做法跟不上时代发展。',
        '要学会灵活应变,不要刻舟求剑。',
        '用刻舟求剑的方式解决新问题是不行的。'
      ],
      relatedWords: ['固步自封', '墨守成规', '抱残守缺'],
      similarWords: ['随机应变', '灵活变通', '与时俱进'],
      type: '成语',
      gradient: [const Color(0xFFA8FF78), const Color(0xFF78FFA8)],
    ),
    DictionaryEntry(
      word: '对牛弹琴',
      pinyin: 'duì niú tán qín',
      partOfSpeech: '成语',
      definition: '比喻对不懂道理的人讲道理,对不懂得美的人讲风雅。',
      examples: [
        '跟他说道理简直是对牛弹琴。',
        '对牛弹琴说明没有找对听众。',
        '不要对牛弹琴,要因材施教。',
        '对牛弹琴的沟通方式效果很差。'
      ],
      relatedWords: ['白费口舌', '徒劳无功', '鸡同鸭讲'],
      similarWords: ['因材施教', '对症下药', '有的放矢'],
      type: '成语',
      gradient: [const Color(0xFFFF9A9E), const Color(0xFFFECFEF)],
    ),
    DictionaryEntry(
      word: '井底之蛙',
      pinyin: 'jǐng dǐ zhī wā',
      partOfSpeech: '成语',
      definition: '比喻见识狭窄的人。',
      examples: [
        '不要做井底之蛙,要开阔眼界。',
        '井底之蛙看不到外面的精彩世界。',
        '多读书,不要当井底之蛙。',
        '井底之蛙的格局限制了发展。'
      ],
      relatedWords: ['目光短浅', '孤陋寡闻', '坐井观天'],
      similarWords: ['见多识广', '博学多才', '开阔眼界'],
      type: '成语',
      gradient: [const Color(0xFFFFF9C), const Color(0xFFFFB199)],
    ),
    DictionaryEntry(
      word: '纸上谈兵',
      pinyin: 'zhǐ shàng tán bīng',
      partOfSpeech: '成语',
      definition: '比喻空谈理论,不能解决实际问题。',
      examples: [
        '不要纸上谈兵,要注重实践。',
        '纸上谈兵解决不了实际问题。',
        '理论联系实际,避免纸上谈兵。',
        '纸上谈兵的人往往缺乏实践经验。'
      ],
      relatedWords: ['空谈理论', '夸夸其谈', '脱离实际'],
      similarWords: ['脚踏实地', '实事求是', '身体力行'],
      type: '成语',
      gradient: [const Color(0xFF89F7FE), const Color(0xFF66A6FF)],
    ),
    DictionaryEntry(
      word: '半途而废',
      pinyin: 'bàn tú ér fèi',
      partOfSpeech: '成语',
      definition: '指做事不能坚持到底,中途停顿,有始无终。',
      examples: [
        '做事要持之以恒,不能半途而废。',
        '半途而废是成功的大敌。',
        '不要半途而废,坚持就是胜利。',
        '半途而废的努力都是白费。'
      ],
      relatedWords: ['前功尽弃', '虎头蛇尾', '有始无终'],
      similarWords: ['持之以恒', '善始善终', '坚持到底'],
      type: '成语',
      gradient: [const Color(0xFFE0C3FC), const Color(0xFF8EC5FC)],
    ),
    DictionaryEntry(
      word: '精益求精',
      pinyin: 'jīng yì qiú jīng',
      partOfSpeech: '成语',
      definition: '已经很好了,还要求更好。比喻对事物追求完美。',
      examples: [
        '我们要精益求精,追求卓越。',
        '精益求精的工匠精神值得学习。',
        '精益求精是成功的品质之一。',
        '精益求精的工作态度创造奇迹。'
      ],
      relatedWords: ['尽善尽美', '完美无缺', '追求卓越'],
      similarWords: ['得过且过', '敷衍了事', '粗制滥造'],
      type: '成语',
      gradient: [const Color(0xFF667EEA), const Color(0xFF764BA2)],
    ),
    DictionaryEntry(
      word: '见义勇为',
      pinyin: 'jiàn yì yǒng wéi',
      partOfSpeech: '成语',
      definition: '看到正义的事,就勇敢地去做。',
      examples: [
        '见义勇为是中华民族的传统美德。',
        '我们要学会见义勇为,帮助他人。',
        '见义勇为的精神值得弘扬。',
        '见义勇为的行为令人敬佩。'
      ],
      relatedWords: ['挺身而出', '见义敢为', '仗义执言'],
      similarWords: ['见死不救', '冷漠无情', '袖手旁观'],
      type: '成语',
      gradient: [const Color(0xFFF093FB), const Color(0xFFF5576C)],
    ),
    DictionaryEntry(
      word: '自强不息',
      pinyin: 'zì qiáng bù xī',
      partOfSpeech: '成语',
      definition: '自觉地努力向上,永不松懈。',
      examples: [
        '自强不息是中华民族的精神。',
        '我们要自强不息,奋发图强。',
        '自强不息的人才能成就大事。',
        '自强不息的精神推动着社会进步。'
      ],
      relatedWords: ['发愤图强', '力争上游', '奋发向上'],
      similarWords: ['自暴自弃', '自甘堕落', '自甘平庸'],
      type: '成语',
      gradient: [const Color(0xFF4FACFE), const Color(0xFF00F2FE)],
    ),

    // 词语类
    DictionaryEntry(
      word: '学习',
      pinyin: 'xué xí',
      partOfSpeech: '动词',
      definition: '通过阅读、听讲、研究、实践等途径获得知识或技能。',
      example: '我们要努力学习科学文化知识。',
      examples: [
        '学习是终身的伴侣。',
        '学习使人进步,不学则退步。',
        '学习要有恒心,不能三天打鱼两天晒网。',
        '学习方法比学习时间更重要。'
      ],
      relatedWords: ['自学', '研习', '进修'],
      similarWords: ['放弃', '荒废', '懈怠'],
      type: '词语',
      gradient: [const Color(0xFFFA709A), const Color(0xFFFEE140)],
    ),
    DictionaryEntry(
      word: '努力',
      pinyin: 'nǔ lì',
      partOfSpeech: '形容词',
      definition: '尽最大力量;尽一切可能。',
      example: '他工作非常努力。',
      examples: [
        '努力不一定成功,但不努力一定失败。',
        '努力是成功的基础。',
        '努力要讲究方法,方向要对。',
        '努力的过程中收获最大。'
      ],
      relatedWords: ['勤奋', '刻苦', '尽力'],
      similarWords: ['懒惰', '松懈', '懈怠'],
      type: '词语',
      gradient: [const Color(0xFF30CFD0), const Color(0xFF330867)],
    ),
    DictionaryEntry(
      word: '知识',
      pinyin: 'zhī shi',
      partOfSpeech: '名词',
      definition: '人们在认识世界、改造世界的过程中积累起来的经验。',
      example: '知识就是力量。',
      examples: ['知识改变命运。', '知识需要不断更新。', '知识在实践中升华。', '知识是无形的财富。'],
      relatedWords: ['常识', '学识', '见识'],
      similarWords: ['无知', '愚昧', '浅薄'],
      type: '词语',
      gradient: [const Color(0xFFA8FF78), const Color(0xFF78FFA8)],
    ),
    DictionaryEntry(
      word: '文化',
      pinyin: 'wén huà',
      partOfSpeech: '名词',
      definition: '人类在社会实践中所创造的物质财富和精神财富的总和。',
      example: '中华文明历史悠久,文化灿烂。',
      examples: ['文化需要传承。', '文化促进交流。', '文化是国家的软实力。', '文化自信很重要。'],
      relatedWords: ['文明', '艺术', '传统'],
      similarWords: ['野蛮', '粗俗', '落后'],
      type: '词语',
      gradient: [const Color(0xFFFF9A9E), const Color(0xFFFECFEF)],
    ),
    DictionaryEntry(
      word: '创新',
      pinyin: 'chuàng xīn',
      partOfSpeech: '动词',
      definition: '抛开旧的,创造新的。',
      example: '科技创新推动了社会进步。',
      examples: ['创新是发展的动力。', '创新需要勇气。', '创新要立足实际。', '创新带来无限可能。'],
      relatedWords: ['改革', '创造', '发明'],
      similarWords: ['守旧', '保守', '僵化'],
      type: '词语',
      gradient: [const Color(0xFFFFF9C), const Color(0xFFFFB199)],
    ),
  ];

  @override
  void initState() {
    super.initState();
    _animationController = AnimationController(
      duration: const Duration(milliseconds: 800),
      vsync: this,
    );
    _fadeInAnimation = Tween<double>(begin: 0.0, end: 1.0).animate(
      CurvedAnimation(
        parent: _animationController,
        curve: Curves.easeInOut,
      ),
    );
    _animationController.forward();
  }

  @override
  void dispose() {
    _searchController.dispose();
    _animationController.dispose();
    super.dispose();
  }

  void _performSearch(String query) {
    if (query.trim().isEmpty) {
      setState(() {
        _searchResults = [];
      });
      return;
    }

    setState(() {
      _isSearching = true;
    });

    Future.delayed(const Duration(milliseconds: 300), () {
      final results = _dictionaryData.where((entry) {
        final queryLower = query.toLowerCase();
        // 精确匹配词语
        if (entry.word == query) return true;
        // 模糊匹配词语(包含查询词)
        if (entry.word.contains(query)) return true;
        // 拼音匹配
        if (entry.pinyin.toLowerCase().contains(queryLower)) return true;
        // 释义匹配
        if (entry.definition.contains(query)) return true;
        // 例句匹配
        if (entry.examples.any((ex) => ex.contains(query))) return true;
        // 相关词语匹配
        if (entry.relatedWords.any((word) => word.contains(query))) return true;
        // 相似词语匹配
        if (entry.similarWords.any((word) => word.contains(query))) return true;
        // 首字母匹配(拼音首字母)
        final pinyinInitials = _getPinyinInitials(entry.pinyin);
        if (pinyinInitials.contains(queryLower)) return true;
        return false;
      }).toList();

      // 保存搜索历史
      if (query.isNotEmpty && !_searchHistory.contains(query)) {
        setState(() {
          _searchHistory.insert(0, query);
          if (_searchHistory.length > 15) {
            _searchHistory.removeLast();
          }
        });
      }

      // 按相关性排序结果
      final sortedResults = _sortResultsByRelevance(results, query);

      setState(() {
        _searchResults = sortedResults;
        _isSearching = false;
      });
    });
  }

  // 获取拼音首字母
  String _getPinyinInitials(String pinyin) {
    // 移除音调和空格,只保留首字母
    return pinyin
        .split(' ')
        .map((s) => s.isEmpty ? '' : s[0].toLowerCase())
        .join('');
  }

  // 按相关性排序结果
  List<DictionaryEntry> _sortResultsByRelevance(
      List<DictionaryEntry> results, String query) {
    final queryLower = query.toLowerCase();

    return results.toList()
      ..sort((a, b) {
        // 精确匹配优先级最高
        if (a.word == query && b.word != query) return -1;
        if (b.word == query && a.word != query) return 1;

        // 开头匹配优先级次高
        final aStartsWith = a.word.startsWith(query);
        final bStartsWith = b.word.startsWith(query);
        if (aStartsWith && !bStartsWith) return -1;
        if (bStartsWith && !aStartsWith) return 1;

        // 拼音首字母匹配
        final aPinyinMatch = _getPinyinInitials(a.pinyin) == queryLower;
        final bPinyinMatch = _getPinyinInitials(b.pinyin) == queryLower;
        if (aPinyinMatch && !bPinyinMatch) return -1;
        if (bPinyinMatch && !aPinyinMatch) return 1;

        // 按词语长度排序(较短的优先)
        if (a.word.length != b.word.length) {
          return a.word.length.compareTo(b.word.length);
        }

        return 0;
      });
  }

  // 获取搜索建议
  List<String> _getSearchSuggestions(String query) {
    if (query.isEmpty) return [];

    final queryLower = query.toLowerCase();
    final suggestions = <String>[];

    // 1. 完全匹配的词语
    for (var entry in _dictionaryData) {
      if (entry.word == query) {
        suggestions.add(entry.word);
        break;
      }
    }

    // 2. 以查询开头的词语
    for (var entry in _dictionaryData) {
      if (entry.word.startsWith(query) && !suggestions.contains(entry.word)) {
        suggestions.add(entry.word);
        if (suggestions.length >= 5) break;
      }
    }

    // 3. 包含查询的词语
    for (var entry in _dictionaryData) {
      if (entry.word.contains(query) && !suggestions.contains(entry.word)) {
        suggestions.add(entry.word);
        if (suggestions.length >= 8) break;
      }
    }

    // 4. 拼音匹配的词语
    for (var entry in _dictionaryData) {
      if (entry.pinyin.toLowerCase().contains(queryLower) &&
          !suggestions.contains(entry.word)) {
        suggestions.add(entry.word);
        if (suggestions.length >= 10) break;
      }
    }

    return suggestions;
  }

  // 更新搜索建议
  void _updateSearchSuggestions(String query) {
    if (query.length >= 1) {
      final suggestions = _getSearchSuggestions(query);
      setState(() {
        _searchSuggestions = suggestions;
        _showSuggestions = suggestions.isNotEmpty;
      });
    } else {
      setState(() {
        _searchSuggestions = [];
        _showSuggestions = false;
      });
    }
  }

  // 选择搜索建议
  void _selectSuggestion(String suggestion) {
    _searchController.text = suggestion;
    setState(() {
      _showSuggestions = false;
    });
    _performSearch(suggestion);
  }

  void _showDetailScreen(DictionaryEntry entry) {
    Navigator.push(
      context,
      PageRouteBuilder(
        pageBuilder: (context, animation, secondaryAnimation) =>
            DictionaryDetailScreen(entry: entry),
        transitionsBuilder: (context, animation, secondaryAnimation, child) {
          const begin = Offset(1.0, 0.0);
          const end = Offset.zero;
          const curve = Curves.ease;

          var tween =
              Tween(begin: begin, end: end).chain(CurveTween(curve: curve));

          return SlideTransition(
            position: animation.drive(tween),
            child: child,
          );
        },
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        decoration: BoxDecoration(
          gradient: LinearGradient(
            begin: Alignment.topLeft,
            end: Alignment.bottomRight,
            colors: [
              const Color(0xFF667EEA),
              const Color(0xFF764BA2),
              const Color(0xFF66A6FF),
            ],
            stops: const [0.0, 0.5, 1.0],
          ),
        ),
        child: SafeArea(
          child: Column(
            children: [
              // 顶部标题和装饰
              Padding(
                padding: const EdgeInsets.all(24),
                child: FadeTransition(
                  opacity: _fadeInAnimation,
                  child: Column(
                    children: [
                      Row(
                        mainAxisAlignment: MainAxisAlignment.spaceBetween,
                        children: [
                          Column(
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: [
                              const Text(
                                '智慧字典',
                                style: TextStyle(
                                  fontSize: 32,
                                  fontWeight: FontWeight.bold,
                                  color: Colors.white,
                                  letterSpacing: 1,
                                ),
                              ),
                              const SizedBox(height: 8),
                              Text(
                                '探索词语的奥秘',
                                style: TextStyle(
                                  fontSize: 16,
                                  color: Colors.white.withOpacity(0.9),
                                ),
                              ),
                            ],
                          ),
                          Container(
                            padding: const EdgeInsets.all(12),
                            decoration: BoxDecoration(
                              color: Colors.white.withOpacity(0.2),
                              borderRadius: BorderRadius.circular(16),
                            ),
                            child: const Icon(
                              Icons.menu_book_outlined,
                              size: 32,
                              color: Colors.white,
                            ),
                          ),
                        ],
                      ),
                      const SizedBox(height: 30),
                    ],
                  ),
                ),
              ),

              // 搜索栏
              Padding(
                padding: const EdgeInsets.symmetric(horizontal: 24),
                child: Container(
                  decoration: BoxDecoration(
                    color: Colors.white,
                    borderRadius: BorderRadius.circular(24),
                    boxShadow: [
                      BoxShadow(
                        color: Colors.black.withOpacity(0.2),
                        blurRadius: 20,
                        offset: const Offset(0, 10),
                      ),
                    ],
                  ),
                  child: TextField(
                    controller: _searchController,
                    style: const TextStyle(fontSize: 18),
                    decoration: InputDecoration(
                      hintText: '输入词语或文章进行查询...',
                      hintStyle: TextStyle(
                        color: Colors.grey[400],
                        fontSize: 16,
                      ),
                      prefixIcon: Container(
                        margin: const EdgeInsets.only(left: 8, right: 4),
                        child: const Icon(
                          Icons.search_rounded,
                          color: Color(0xFF6366F1),
                          size: 28,
                        ),
                      ),
                      suffixIcon: _searchController.text.isNotEmpty
                          ? Container(
                              margin: const EdgeInsets.only(right: 8),
                              child: IconButton(
                                icon: const Icon(Icons.close_rounded),
                                onPressed: () {
                                  _searchController.clear();
                                  setState(() {
                                    _searchResults = [];
                                  });
                                },
                              ),
                            )
                          : Container(
                              margin: const EdgeInsets.only(right: 12),
                              child: const Icon(
                                Icons.mic_rounded,
                                color: Color(0xFF6366F1),
                                size: 24,
                              ),
                            ),
                      border: InputBorder.none,
                      contentPadding: const EdgeInsets.symmetric(
                        vertical: 18,
                        horizontal: 16,
                      ),
                    ),
                    onChanged: (value) {
                      _updateSearchSuggestions(value);
                      // 只有当用户输入较多内容时才进行实时搜索
                      if (value.length >= 2) {
                        _performSearch(value);
                      }
                    },
                    onSubmitted: (value) {
                      setState(() {
                        _showSuggestions = false;
                      });
                      _performSearch(value);
                    },
                    onTap: () {
                      if (_searchController.text.isNotEmpty) {
                        _updateSearchSuggestions(_searchController.text);
                      }
                    },
                  ),
                ),
              ),

              // 搜索建议列表
              if (_showSuggestions && _searchSuggestions.isNotEmpty)
                Container(
                  margin: const EdgeInsets.symmetric(horizontal: 24),
                  decoration: BoxDecoration(
                    color: Colors.white,
                    borderRadius: BorderRadius.circular(16),
                    boxShadow: [
                      BoxShadow(
                        color: Colors.black.withOpacity(0.1),
                        blurRadius: 10,
                        offset: const Offset(0, 5),
                      ),
                    ],
                  ),
                  child: Column(
                    mainAxisSize: MainAxisSize.min,
                    children: [
                      ListView.separated(
                        shrinkWrap: true,
                        physics: const NeverScrollableScrollPhysics(),
                        padding: const EdgeInsets.all(12),
                        itemCount: _searchSuggestions.take(6).length,
                        separatorBuilder: (context, index) => Divider(
                          height: 1,
                          color: Colors.grey[200],
                        ),
                        itemBuilder: (context, index) {
                          final suggestion = _searchSuggestions[index];
                          return InkWell(
                            onTap: () => _selectSuggestion(suggestion),
                            child: Padding(
                              padding: const EdgeInsets.symmetric(
                                vertical: 12,
                                horizontal: 16,
                              ),
                              child: Row(
                                children: [
                                  Icon(
                                    Icons.search_rounded,
                                    size: 18,
                                    color: Colors.grey[600],
                                  ),
                                  const SizedBox(width: 12),
                                  Expanded(
                                    child: Text(
                                      suggestion,
                                      style: const TextStyle(
                                        fontSize: 16,
                                        fontWeight: FontWeight.w500,
                                      ),
                                    ),
                                  ),
                                  Icon(
                                    Icons.north_west_rounded,
                                    size: 18,
                                    color: Colors.grey[400],
                                  ),
                                ],
                              ),
                            ),
                          );
                        },
                      ),
                      // 更多建议提示
                      if (_searchSuggestions.length > 6)
                        Padding(
                          padding: const EdgeInsets.all(12),
                          child: InkWell(
                            onTap: () {
                              _showSuggestions = false;
                              _performSearch(_searchController.text);
                            },
                            child: Row(
                              mainAxisAlignment: MainAxisAlignment.center,
                              children: [
                                Text(
                                  '查看更多 (${_searchSuggestions.length - 6})',
                                  style: TextStyle(
                                    color: const Color(0xFF6366F1),
                                    fontSize: 14,
                                    fontWeight: FontWeight.w500,
                                  ),
                                ),
                              ],
                            ),
                          ),
                        ),
                    ],
                  ),
                ),

              SizedBox(height: _showSuggestions ? 16 : 24),

              // 搜索结果或推荐区域
              Expanded(
                child: Container(
                  margin: const EdgeInsets.only(top: 20),
                  decoration: const BoxDecoration(
                    color: Colors.white,
                    borderRadius: BorderRadius.only(
                      topLeft: Radius.circular(32),
                      topRight: Radius.circular(32),
                    ),
                  ),
                  child: _isSearching
                      ? const Center(
                          child: CircularProgressIndicator(),
                        )
                      : _searchResults.isEmpty
                          ? _buildEmptyState()
                          : _buildSearchResults(),
                ),
              ),

              // 搜索历史浮层
              if (_searchHistory.isNotEmpty && _searchController.text.isEmpty)
                Positioned(
                  bottom: 20,
                  left: 20,
                  right: 20,
                  child: _buildSearchHistory(),
                ),
            ],
          ),
        ),
      ),
    );
  }

  Widget _buildEmptyState() {
    return Stack(
      children: [
        // 背景装饰
        Positioned(
          top: -50,
          right: -50,
          child: Container(
            width: 200,
            height: 200,
            decoration: BoxDecoration(
              shape: BoxShape.circle,
              color: const Color(0xFF6366F1).withOpacity(0.05),
            ),
          ),
        ),
        Positioned(
          bottom: 50,
          left: -30,
          child: Container(
            width: 150,
            height: 150,
            decoration: BoxDecoration(
              shape: BoxShape.circle,
              color: const Color(0xFF764BA2).withOpacity(0.05),
            ),
          ),
        ),

        // 推荐词汇
        Column(
          children: [
            const Padding(
              padding: EdgeInsets.all(24),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: [
                  Text(
                    '每日推荐',
                    style: TextStyle(
                      fontSize: 24,
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                  Text(
                    '发现更多',
                    style: TextStyle(
                      fontSize: 16,
                      color: Color(0xFF6366F1),
                    ),
                  ),
                ],
              ),
            ),
            Expanded(
              child: ListView.builder(
                padding: const EdgeInsets.symmetric(horizontal: 24),
                itemCount: _dictionaryData.take(5).length,
                itemBuilder: (context, index) {
                  return Padding(
                    padding: const EdgeInsets.only(bottom: 16),
                    child: _buildRecommendedCard(
                      _dictionaryData[index],
                    ),
                  );
                },
              ),
            ),
          ],
        ),
      ],
    );
  }

  Widget _buildRecommendedCard(DictionaryEntry entry) {
    return GestureDetector(
      onTap: () {
        _searchController.text = entry.word;
        _performSearch(entry.word);
      },
      child: Container(
        padding: const EdgeInsets.all(20),
        decoration: BoxDecoration(
          gradient: LinearGradient(
            colors: entry.gradient,
            begin: Alignment.topLeft,
            end: Alignment.bottomRight,
          ),
          borderRadius: BorderRadius.circular(24),
          boxShadow: [
            BoxShadow(
              color: entry.gradient[0].withOpacity(0.3),
              blurRadius: 12,
              offset: const Offset(0, 8),
            ),
          ],
        ),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                Text(
                  entry.word,
                  style: const TextStyle(
                    fontSize: 32,
                    fontWeight: FontWeight.bold,
                    color: Colors.white,
                  ),
                ),
                Container(
                  padding: const EdgeInsets.symmetric(
                    horizontal: 12,
                    vertical: 6,
                  ),
                  decoration: BoxDecoration(
                    color: Colors.white.withOpacity(0.3),
                    borderRadius: BorderRadius.circular(12),
                  ),
                  child: Text(
                    entry.partOfSpeech,
                    style: const TextStyle(
                      color: Colors.white,
                      fontWeight: FontWeight.w500,
                      fontSize: 12,
                    ),
                  ),
                ),
              ],
            ),
            const SizedBox(height: 8),
            Text(
              entry.pinyin,
              style: TextStyle(
                fontSize: 16,
                color: Colors.white.withOpacity(0.9),
              ),
            ),
            const SizedBox(height: 12),
            Text(
              entry.definition,
              maxLines: 2,
              overflow: TextOverflow.ellipsis,
              style: TextStyle(
                fontSize: 14,
                color: Colors.white.withOpacity(0.8),
                height: 1.5,
              ),
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildSearchResults() {
    return ListView.builder(
      padding: const EdgeInsets.all(24),
      itemCount: _searchResults.length,
      itemBuilder: (context, index) {
        return Padding(
          padding: const EdgeInsets.only(bottom: 16),
          child: _buildResultCard(_searchResults[index]),
        );
      },
    );
  }

  Widget _buildResultCard(DictionaryEntry entry) {
    return GestureDetector(
      onTap: () => _showDetailScreen(entry),
      child: Container(
        decoration: BoxDecoration(
          color: Colors.white,
          borderRadius: BorderRadius.circular(20),
          boxShadow: [
            BoxShadow(
              color: Colors.grey.withOpacity(0.1),
              blurRadius: 12,
              offset: const Offset(0, 4),
            ),
          ],
        ),
        child: ClipRRect(
          borderRadius: BorderRadius.circular(20),
          child: Column(
            children: [
              // 上半部分:主要信息
              Container(
                decoration: BoxDecoration(
                  gradient: LinearGradient(
                    colors: [
                      entry.gradient[0].withOpacity(0.05),
                      entry.gradient[1].withOpacity(0.05),
                    ],
                    begin: Alignment.topLeft,
                    end: Alignment.bottomRight,
                  ),
                ),
                child: Padding(
                  padding: const EdgeInsets.all(20),
                  child: Row(
                    children: [
                      // 左侧渐变条
                      Container(
                        width: 6,
                        height: 80,
                        decoration: BoxDecoration(
                          gradient: LinearGradient(
                            colors: entry.gradient,
                            begin: Alignment.topCenter,
                            end: Alignment.bottomCenter,
                          ),
                          borderRadius: BorderRadius.circular(3),
                        ),
                      ),
                      const SizedBox(width: 16),
                      // 内容区域
                      Expanded(
                        child: Column(
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: [
                            Row(
                              mainAxisAlignment: MainAxisAlignment.spaceBetween,
                              children: [
                                Expanded(
                                  child: Text(
                                    entry.word,
                                    style: const TextStyle(
                                      fontSize: 24,
                                      fontWeight: FontWeight.bold,
                                    ),
                                  ),
                                ),
                                // 操作按钮组
                                Row(
                                  mainAxisSize: MainAxisSize.min,
                                  children: [
                                    // 发音按钮
                                    _buildActionButton(
                                      icon: Icons.volume_up_rounded,
                                      onTap: () => _speakWord(entry.word),
                                      color: entry.gradient[0],
                                    ),
                                    const SizedBox(width: 8),
                                    // 收藏按钮
                                    _buildActionButton(
                                      icon: Icons.bookmark_border_rounded,
                                      onTap: () => _toggleFavorite(entry),
                                      color: entry.gradient[0],
                                    ),
                                  ],
                                ),
                              ],
                            ),
                            const SizedBox(height: 6),
                            Row(
                              children: [
                                Text(
                                  entry.pinyin,
                                  style: TextStyle(
                                    fontSize: 14,
                                    color: Colors.grey[600],
                                  ),
                                ),
                                const SizedBox(width: 12),
                                // 热度标签
                                Container(
                                  padding: const EdgeInsets.symmetric(
                                    horizontal: 8,
                                    vertical: 2,
                                  ),
                                  decoration: BoxDecoration(
                                    color: Colors.orange.withOpacity(0.1),
                                    borderRadius: BorderRadius.circular(12),
                                  ),
                                  child: Row(
                                    mainAxisSize: MainAxisSize.min,
                                    children: [
                                      Icon(
                                        Icons.local_fire_department,
                                        size: 14,
                                        color: Colors.orange[700],
                                      ),
                                      const SizedBox(width: 4),
                                      Text(
                                        '${(entry.word.length * 100 % 500 + 100)}热度',
                                        style: TextStyle(
                                          fontSize: 12,
                                          color: Colors.orange[700],
                                          fontWeight: FontWeight.w500,
                                        ),
                                      ),
                                    ],
                                  ),
                                ),
                              ],
                            ),
                            const SizedBox(height: 10),
                            // 类型标签
                            Container(
                              padding: const EdgeInsets.symmetric(
                                horizontal: 12,
                                vertical: 4,
                              ),
                              decoration: BoxDecoration(
                                color: entry.gradient[0].withOpacity(0.15),
                                borderRadius: BorderRadius.circular(12),
                              ),
                              child: Text(
                                '${entry.partOfSpeech} · ${entry.type}',
                                style: TextStyle(
                                  color: entry.gradient[0],
                                  fontSize: 12,
                                  fontWeight: FontWeight.w600,
                                ),
                              ),
                            ),
                          ],
                        ),
                      ),
                    ],
                  ),
                ),
              ),
              // 下半部分:详情预览
              Padding(
                padding:
                    const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    // 释义
                    Container(
                      padding: const EdgeInsets.all(12),
                      decoration: BoxDecoration(
                        color: Colors.grey[50],
                        borderRadius: BorderRadius.circular(12),
                      ),
                      child: Row(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: [
                          Container(
                            margin: const EdgeInsets.only(top: 2),
                            child: Icon(
                              Icons.lightbulb_outline_rounded,
                              size: 16,
                              color: entry.gradient[0],
                            ),
                          ),
                          const SizedBox(width: 8),
                          Expanded(
                            child: Text(
                              entry.definition,
                              maxLines: 2,
                              overflow: TextOverflow.ellipsis,
                              style: TextStyle(
                                fontSize: 13,
                                color: Colors.grey[700],
                                height: 1.5,
                              ),
                            ),
                          ),
                        ],
                      ),
                    ),
                    const SizedBox(height: 10),
                    // 例句预览
                    if (entry.examples.isNotEmpty)
                      Container(
                        padding: const EdgeInsets.all(12),
                        decoration: BoxDecoration(
                          color: entry.gradient[0].withOpacity(0.05),
                          borderRadius: BorderRadius.circular(12),
                        ),
                        child: Row(
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: [
                            Container(
                              margin: const EdgeInsets.only(top: 2),
                              child: Icon(
                                Icons.format_quote_rounded,
                                size: 16,
                                color: entry.gradient[0],
                              ),
                            ),
                            const SizedBox(width: 8),
                            Expanded(
                              child: Text(
                                entry.examples.first,
                                maxLines: 1,
                                overflow: TextOverflow.ellipsis,
                                style: TextStyle(
                                  fontSize: 12,
                                  color: entry.gradient[0].withOpacity(0.8),
                                  fontStyle: FontStyle.italic,
                                ),
                              ),
                            ),
                          ],
                        ),
                      ),
                    // 相关词语预览
                    if (entry.relatedWords.isNotEmpty) ...[
                      const SizedBox(height: 10),
                      Wrap(
                        spacing: 6,
                        children: entry.relatedWords.take(3).map((word) {
                          return _buildWordChip(word, entry.gradient[0],
                              isSmall: true);
                        }).toList(),
                      ),
                    ],
                  ],
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }

  Widget _buildSearchHistory() {
    return Container(
      padding: const EdgeInsets.all(20),
      decoration: BoxDecoration(
        color: Colors.white,
        borderRadius: BorderRadius.circular(24),
        boxShadow: [
          BoxShadow(
            color: Colors.black.withOpacity(0.1),
            blurRadius: 20,
            offset: const Offset(0, 10),
          ),
        ],
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: [
              const Text(
                '搜索历史',
                style: TextStyle(
                  fontSize: 18,
                  fontWeight: FontWeight.bold,
                ),
              ),
              TextButton(
                onPressed: () {
                  setState(() {
                    _searchHistory.clear();
                  });
                },
                style: TextButton.styleFrom(
                  foregroundColor: const Color(0xFF6366F1),
                ),
                child: const Text('清除全部'),
              ),
            ],
          ),
          const SizedBox(height: 12),
          Wrap(
            spacing: 10,
            runSpacing: 10,
            children: _searchHistory.take(6).map((term) {
              return InkWell(
                onTap: () {
                  _searchController.text = term;
                  _performSearch(term);
                },
                borderRadius: BorderRadius.circular(20),
                child: Container(
                  padding: const EdgeInsets.symmetric(
                    horizontal: 16,
                    vertical: 10,
                  ),
                  decoration: BoxDecoration(
                    gradient: LinearGradient(
                      colors: [
                        const Color(0xFF6366F1).withOpacity(0.1),
                        const Color(0xFF667EEA).withOpacity(0.1),
                      ],
                    ),
                    borderRadius: BorderRadius.circular(20),
                  ),
                  child: Row(
                    mainAxisSize: MainAxisSize.min,
                    children: [
                      Icon(
                        Icons.history_rounded,
                        size: 16,
                        color: const Color(0xFF6366F1),
                      ),
                      const SizedBox(width: 6),
                      Text(
                        term,
                        style: const TextStyle(
                          color: Color(0xFF6366F1),
                          fontSize: 14,
                        ),
                      ),
                    ],
                  ),
                ),
              );
            }).toList(),
          ),
        ],
      ),
    );
  }

  // 词语标签组件
  Widget _buildWordChip(String word, Color color, {bool isSmall = false}) {
    return InkWell(
      onTap: () {
        _searchController.text = word;
        _performSearch(word);
      },
      borderRadius: BorderRadius.circular(20),
      child: Container(
        padding: EdgeInsets.symmetric(
          horizontal: isSmall ? 12 : 16,
          vertical: isSmall ? 6 : 10,
        ),
        decoration: BoxDecoration(
          color: color.withOpacity(0.1),
          borderRadius: BorderRadius.circular(20),
          border: Border.all(
            color: color.withOpacity(0.3),
            width: 1,
          ),
        ),
        child: Text(
          word,
          style: TextStyle(
            color: color,
            fontSize: isSmall ? 12 : 14,
            fontWeight: FontWeight.w600,
          ),
        ),
      ),
    );
  }

  // 发音按钮组件
  Widget _buildActionButton({
    required IconData icon,
    required VoidCallback onTap,
    required Color color,
  }) {
    return InkWell(
      onTap: onTap,
      borderRadius: BorderRadius.circular(12),
      child: Container(
        padding: const EdgeInsets.all(10),
        decoration: BoxDecoration(
          color: color.withOpacity(0.1),
          borderRadius: BorderRadius.circular(12),
        ),
        child: Icon(
          icon,
          color: color,
          size: 20,
        ),
      ),
    );
  }

  // 朗读词语
  void _speakWord(String word) {
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(
        content: Row(
          children: [
            const Icon(Icons.volume_up_rounded, color: Colors.white),
            const SizedBox(width: 8),
            Text('朗读: $word'),
          ],
        ),
        backgroundColor: Colors.green,
        duration: const Duration(seconds: 1),
      ),
    );
  }

  // 收藏/取消收藏
  void _toggleFavorite(DictionaryEntry entry) {
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(
        content: Row(
          children: [
            const Icon(Icons.favorite_rounded, color: Colors.white),
            const SizedBox(width: 8),
            Text('已收藏: ${entry.word}'),
          ],
        ),
        backgroundColor: entry.gradient[0],
        duration: const Duration(seconds: 1),
      ),
    );
  }
}

// 词语详情页面
class DictionaryDetailScreen extends StatelessWidget {
  final DictionaryEntry entry;

  const DictionaryDetailScreen({super.key, required this.entry});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        decoration: BoxDecoration(
          gradient: LinearGradient(
            begin: Alignment.topLeft,
            end: Alignment.bottomRight,
            colors: [
              entry.gradient[0],
              entry.gradient[1],
            ],
          ),
        ),
        child: SafeArea(
          child: Column(
            children: [
              // 顶部导航
              Padding(
                padding: const EdgeInsets.all(20),
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: [
                    Container(
                      decoration: BoxDecoration(
                        color: Colors.white.withOpacity(0.2),
                        borderRadius: BorderRadius.circular(16),
                      ),
                      child: IconButton(
                        onPressed: () => Navigator.pop(context),
                        icon: const Icon(
                          Icons.arrow_back_rounded,
                          color: Colors.white,
                        ),
                      ),
                    ),
                    const Text(
                      '词语详情',
                      style: TextStyle(
                        fontSize: 20,
                        fontWeight: FontWeight.bold,
                        color: Colors.white,
                      ),
                    ),
                    Container(
                      decoration: BoxDecoration(
                        color: Colors.white.withOpacity(0.2),
                        borderRadius: BorderRadius.circular(16),
                      ),
                      child: IconButton(
                        onPressed: () {
                          ScaffoldMessenger.of(context).showSnackBar(
                            const SnackBar(
                              content: Text('已添加到收藏'),
                              backgroundColor: Colors.green,
                            ),
                          );
                        },
                        icon: const Icon(
                          Icons.favorite_border_rounded,
                          color: Colors.white,
                        ),
                      ),
                    ),
                  ],
                ),
              ),

              // 词语卡片
              Expanded(
                child: SingleChildScrollView(
                  padding: const EdgeInsets.all(24),
                  child: Column(
                    children: [
                      // 主卡片
                      Container(
                        padding: const EdgeInsets.all(32),
                        decoration: BoxDecoration(
                          color: Colors.white,
                          borderRadius: BorderRadius.circular(32),
                          boxShadow: [
                            BoxShadow(
                              color: Colors.black.withOpacity(0.2),
                              blurRadius: 30,
                              offset: const Offset(0, 20),
                            ),
                          ],
                        ),
                        child: Column(
                          children: [
                            Text(
                              entry.word,
                              style: const TextStyle(
                                fontSize: 56,
                                fontWeight: FontWeight.bold,
                                color: Color(0xFF2D3436),
                              ),
                            ),
                            const SizedBox(height: 12),
                            Text(
                              entry.pinyin,
                              style: TextStyle(
                                fontSize: 24,
                                color: Colors.grey[600],
                                letterSpacing: 2,
                              ),
                            ),
                            const SizedBox(height: 20),
                            Container(
                              padding: const EdgeInsets.symmetric(
                                horizontal: 20,
                                vertical: 10,
                              ),
                              decoration: BoxDecoration(
                                gradient: LinearGradient(
                                  colors: entry.gradient,
                                ),
                                borderRadius: BorderRadius.circular(20),
                              ),
                              child: Text(
                                entry.partOfSpeech,
                                style: const TextStyle(
                                  color: Colors.white,
                                  fontSize: 16,
                                  fontWeight: FontWeight.w600,
                                ),
                              ),
                            ),
                          ],
                        ),
                      ),

                      const SizedBox(height: 32),

                      // 释义
                      _buildDetailSection(
                        '释义',
                        Icons.info_rounded,
                        entry.gradient[0],
                        Text(
                          entry.definition,
                          style: const TextStyle(
                            fontSize: 18,
                            height: 1.8,
                            color: Color(0xFF2D3436),
                          ),
                        ),
                      ),

                      const SizedBox(height: 24),

                      // 例句
                      _buildDetailSection(
                        '例句',
                        Icons.format_quote_rounded,
                        entry.gradient[0],
                        Container(
                          padding: const EdgeInsets.all(24),
                          decoration: BoxDecoration(
                            color: entry.gradient[0].withOpacity(0.1),
                            borderRadius: BorderRadius.circular(20),
                            border: Border.all(
                              color: entry.gradient[0].withOpacity(0.3),
                            ),
                          ),
                          child: Row(
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: [
                              const Text(
                                '"',
                                style: TextStyle(
                                  fontSize: 48,
                                  color: Color(0xFF6366F1),
                                  fontWeight: FontWeight.bold,
                                ),
                              ),
                              const SizedBox(width: 12),
                              Expanded(
                                child: Text(
                                  entry.example,
                                  style: const TextStyle(
                                    fontSize: 18,
                                    fontStyle: FontStyle.italic,
                                    height: 1.6,
                                    color: Color(0xFF2D3436),
                                  ),
                                ),
                              ),
                            ],
                          ),
                        ),
                      ),

                      const SizedBox(height: 24),

                      // 相关词语
                      _buildDetailSection(
                        '相关词语',
                        Icons.link_rounded,
                        entry.gradient[0],
                        Wrap(
                          spacing: 12,
                          runSpacing: 12,
                          children: entry.relatedWords.map((word) {
                            return GestureDetector(
                              onTap: () {
                                Navigator.pushReplacement(
                                  context,
                                  MaterialPageRoute(
                                    builder: (context) =>
                                        DictionaryDetailScreen(
                                      entry: DictionaryEntry(
                                        word: word,
                                        pinyin: '',
                                        partOfSpeech: '相关词',
                                        definition: '点击查看详情',
                                        example: '',
                                        relatedWords: [],
                                        gradient: entry.gradient,
                                      ),
                                    ),
                                  ),
                                );
                              },
                              child: Container(
                                padding: const EdgeInsets.symmetric(
                                  horizontal: 20,
                                  vertical: 12,
                                ),
                                decoration: BoxDecoration(
                                  color: entry.gradient[0].withOpacity(0.1),
                                  borderRadius: BorderRadius.circular(24),
                                  border: Border.all(
                                    color: entry.gradient[0].withOpacity(0.3),
                                  ),
                                ),
                                child: Row(
                                  mainAxisSize: MainAxisSize.min,
                                  children: [
                                    CircleAvatar(
                                      radius: 12,
                                      backgroundColor: entry.gradient[0],
                                      child: Text(
                                        word[0],
                                        style: const TextStyle(
                                          color: Colors.white,
                                          fontSize: 14,
                                          fontWeight: FontWeight.bold,
                                        ),
                                      ),
                                    ),
                                    const SizedBox(width: 10),
                                    Text(
                                      word,
                                      style: TextStyle(
                                        color: entry.gradient[0],
                                        fontSize: 16,
                                        fontWeight: FontWeight.w600,
                                      ),
                                    ),
                                  ],
                                ),
                              ),
                            );
                          }).toList(),
                        ),
                      ),

                      const SizedBox(height: 40),

                      // 操作按钮
                      Row(
                        children: [
                          Expanded(
                            child: _buildActionButton(
                              Icons.share_rounded,
                              '分享',
                              () {
                                ScaffoldMessenger.of(context).showSnackBar(
                                  const SnackBar(
                                    content: Text('分享成功'),
                                    backgroundColor: Colors.green,
                                  ),
                                );
                              },
                            ),
                          ),
                          const SizedBox(width: 16),
                          Expanded(
                            child: _buildActionButton(
                              Icons.copy_rounded,
                              '复制',
                              () {
                                ScaffoldMessenger.of(context).showSnackBar(
                                  const SnackBar(
                                    content: Text('已复制到剪贴板'),
                                    backgroundColor: Colors.green,
                                  ),
                                );
                              },
                            ),
                          ),
                        ],
                      ),
                    ],
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }

  Widget _buildDetailSection(
    String title,
    IconData icon,
    Color color,
    Widget content,
  ) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Row(
          children: [
            Container(
              padding: const EdgeInsets.all(10),
              decoration: BoxDecoration(
                color: color.withOpacity(0.1),
                borderRadius: BorderRadius.circular(12),
              ),
              child: Icon(
                icon,
                color: color,
                size: 24,
              ),
            ),
            const SizedBox(width: 12),
            Text(
              title,
              style: const TextStyle(
                fontSize: 22,
                fontWeight: FontWeight.bold,
                color: Color(0xFF2D3436),
              ),
            ),
          ],
        ),
        const SizedBox(height: 16),
        content,
      ],
    );
  }

  Widget _buildActionButton(IconData icon, String label, VoidCallback onTap) {
    return GestureDetector(
      onTap: onTap,
      child: Container(
        padding: const EdgeInsets.symmetric(vertical: 16),
        decoration: BoxDecoration(
          color: Colors.white,
          borderRadius: BorderRadius.circular(16),
          boxShadow: [
            BoxShadow(
              color: Colors.grey.withOpacity(0.2),
              blurRadius: 10,
              offset: const Offset(0, 4),
            ),
          ],
        ),
        child: Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Icon(
              icon,
              color: const Color(0xFF6366F1),
            ),
            const SizedBox(width: 8),
            const Text(
              'label',
              style: TextStyle(
                fontSize: 16,
                fontWeight: FontWeight.w600,
                color: Color(0xFF2D3436),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

// 字典条目数据模型
class DictionaryEntry {
  final String word;
  final String pinyin;
  final String partOfSpeech;
  final String definition;
  final String example;
  final List<String> examples;
  final List<String> relatedWords;
  final List<String> similarWords;
  final String type;
  final List<Color> gradient;

  DictionaryEntry({
    required this.word,
    required this.pinyin,
    required this.partOfSpeech,
    required this.definition,
    this.example = '',
    this.examples = const [],
    this.relatedWords = const [],
    this.similarWords = const [],
    this.type = '',
    required this.gradient,
  });
}
相关推荐
h7ml2 小时前
电商返利系统中佣金计算的幂等性保障与对账补偿机制实现
服务器·前端·php
程序员清洒2 小时前
Flutter for OpenHarmony:Stack 与 Positioned — 层叠布局
开发语言·flutter·华为·鸿蒙
EndingCoder2 小时前
高级项目:构建一个 CLI 工具
大数据·开发语言·前端·javascript·elasticsearch·搜索引擎·typescript
RFCEO2 小时前
HTML元素+网页布局区块概念汇总表
前端·html·html编程基础课·html元素汇总表·html元素位置展示
Dawndddddd2 小时前
XSS知识点总结
前端·xss
时光慢煮2 小时前
从进度可视化出发:基于 Flutter × OpenHarmony 的驾照学习助手实践
学习·flutter·华为·开源·openharmony
子春一2 小时前
Flutter for OpenHarmony:构建一个工业级 Flutter 计算器,深入解析表达式解析、状态管理与 Material 3 交互设计
flutter·交互
晚霞的不甘2 小时前
Flutter for OpenHarmony字典查询 App 全栈解析:从搜索交互到详情展示的完整实
flutter·架构·前端框架·全文检索·交互·个人开发
kirk_wang2 小时前
Flutter艺术探索-设计模式在Flutter中的应用:单例、工厂、观察者
flutter·移动开发·flutter教程·移动开发教程