Flutter for OpenHarmony《智慧字典》 App 主页深度优化解析:从视觉动效到交互体验的全面升级 - 教程

Flutter for OpenHarmony《智慧字典》 App 主页深度优化解析:从视觉动效到交互体验的全面升级

在移动应用竞争日益激烈的今天,第一印象和交互流畅度直接决定了用户的留存率。本文将聚焦于您提供的《智慧字典》App 主页
(DictionaryHomeScreen)
的优化代码,深入剖析其如何通过
精致的视觉设计、流畅的动画效果和人性化的交互逻辑,将一个基础的工具类应用,蜕变为一款令人眼前一亮的精品。

我们将从 整体视觉风格、核心交互区域、空状态设计、搜索历史浮层 四个维度,逐一拆解其实现细节与设计哲学。


完整效果展示
在这里插入图片描述
在这里插入图片描述

一、整体视觉风格:沉浸式渐变美学

新版主页彻底摒弃了传统的纯色背景,转而采用 全屏渐变,营造出沉浸式的视觉体验。

1.1 全局渐变背景

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],
),
),
// ... SafeArea and Column
)

在这里插入图片描述

  • 三色渐变:从左上角的蓝紫色 (0xFF667EEA) 到右下角的亮蓝色 (0xFF66A6FF),中间过渡自然,科技感与优雅感并存。
  • 对角线方向 (topLeft to bottomRight):比垂直或水平渐变更具动感和现代感。

1.2 动画驱动的标题栏

利用 SingleTickerProviderStateMixin 和 AnimationController,为主标题添加了 淡入动画。

// initState 中初始化
_animationController = AnimationController(...);
_fadeInAnimation = Tween<double>(begin: 0.0, end: 1.0).animate(...);
  // build 方法中使用
  FadeTransition(
  opacity: _fadeInAnimation,
  child: Column(...), // 标题和副标题
  )

在这里插入图片描述

  • 用户体验价值:页面加载时,标题优雅地淡入,避免了生硬的“闪现”,提升了应用的精致感和专业度。

二、核心交互区域:搜索栏的极致打磨

搜索栏是字典 App 的心脏,新版对其进行了全方位的视觉和交互升级。

2.1 视觉重塑

  • 超大圆角 (borderRadius: 24):柔和的曲线符合现代 UI 趋势。
  • 深度阴影 (blurRadius: 20, offset: (0, 10)):强烈的 Z 轴层次感,使其从背景中“浮”出来,成为视觉焦点。
  • 图标定制:
    • 前缀图标:使用 search_rounded,尺寸更大 (size: 28),主色调 (0xFF6366F1) 高亮。
    • 后缀图标:动态切换。有输入时显示 圆形关闭图标 (close_rounded);无输入时显示 麦克风图标 (mic_rounded),暗示语音输入功能(虽未实现,但为未来扩展预留了入口)。

2.2 交互优化

  • 点击推荐词自动填充:在“每日推荐”卡片中,点击任意词语会自动将其填入搜索框并触发搜索,极大简化了用户操作路径。
    onTap: () {
    _searchController.text = entry.word;
    _performSearch(entry.word);
    }

在这里插入图片描述

三、空状态设计:从“无结果”到“主动引导”

旧版的空状态仅是一个静态提示,新版则将其升级为一个 主动的内容推荐平台 —— “每日推荐”。

3.1 结构化布局

Widget _buildEmptyState() {
return Stack(
children: [
// 背景装饰圆圈
Positioned(...),
Positioned(...),
// 推荐内容主体
Column(
children: [
// 标题栏:“每日推荐” + “发现更多”
Padding(...),
// 推荐列表
Expanded(child: ListView.builder(...)),
],
),
],
);
}
  • Stack 布局:巧妙地在内容背后叠加了两个半透明的圆形装饰 (BoxShape.circle),增加了画面的丰富度和呼吸感,避免了大面积留白的单调。

3.2 推荐卡片 (_buildRecommendedCard)

每个推荐卡片本身就是一个 微型详情页,信息密度高且极具吸引力。

  • 专属渐变:每个词语 (DictionaryEntry) 都绑定了自己的 gradient,卡片背景即为此渐变,视觉上独一无二。
  • 信息层级清晰:
    • 主词:超大白色字体 (fontSize: 32),加粗。
    • 词性:白色小标签,置于右上角。
    • 拼音 & 释义:次级白色文字,释义截断两行。
  • 微交互:整个卡片可点击,点击后自动填充搜索框。

商业/产品价值:这不仅是 UI 优化,更是 用户增长策略。它能有效引导新用户探索字典内容,降低冷启动时的流失率。


四、搜索结果:信息卡片的精致呈现

当有搜索结果时,列表项的设计同样体现了对细节的追求。

4.1 左侧渐变指示条

Container(
width: 6,
decoration: BoxDecoration(
gradient: LinearGradient(colors: entry.gradient, ...),
),
)
  • 视觉锚点:一条 6px 宽的左侧竖条,使用该词语的专属渐变色,瞬间建立起结果项与词语本身的强关联。
  • 品牌一致性:与详情页、推荐卡片的渐变风格完全统一。

4.2 内容区与箭头

  • 内容区:标准的 ListTile 信息结构(词语、词性、拼音、释义),排版清晰。
  • 右侧箭头:使用 chevron_right_rounded 图标,并且 颜色与该词语的渐变主色一致 (entry.gradient[0]),形成完美的视觉闭环。

五、搜索历史:创新的浮层交互

新版将搜索历史从页面底部的固定区域,改造为一个 悬浮在内容之上的浮层。

5.1 浮层定位

if (_searchHistory.isNotEmpty && _searchController.text.isEmpty)
Positioned(
bottom: 20,
left: 20,
right: 20,
child: _buildSearchHistory(),
)
  • Positioned:使其脱离正常的文档流,悬浮于结果列表之上。
  • 条件渲染:仅在无搜索输入时显示,避免干扰当前搜索。

5.2 浮层设计 (_buildSearchHistory)

  • 独立容器:拥有自己的圆角 (borderRadius: 24) 和深度阴影 (blurRadius: 20),看起来像一个独立的模态面板。
  • 历史项样式:
    • 不再是简单的 Chip,而是带有 浅色渐变背景 的容器。
    • 左侧历史图标 (history_rounded):明确标识其为历史记录。
    • 主色调文字:文字和图标均为应用主色 (0xFF6366F1),保持品牌一致性。
  • 交互:点击历史项,同样会自动填充搜索框并执行搜索。

优势:这种设计让搜索历史 随时可用,又不喧宾夺主,极大地提升了高频用户的操作效率。


六、总结:超越功能的体验设计

通过对《智慧字典》主页优化代码的逐层剖析,我们可以看到,一次成功的 UI/UX 升级绝不仅仅是“换个颜色”或“加个动画”那么简单。它是一套 系统性的思考:

  1. 建立统一的视觉语言:通过全局渐变、专属配色 (gradient) 和一致的圆角/阴影,构建了强烈的品牌识别度。
  2. 用动效讲述故事:从标题的淡入到页面的滑动进入 (PageRouteBuilder),每一个动画都在无声地提升应用的品质感。
  3. 化被动为主动:将空状态转化为内容推荐位,变“等待用户输入”为“主动引导用户”,这是产品思维的体现。
  4. 细节决定成败:左侧的 6px 渐变条、历史项的图标、按钮的圆角值… 正是这些看似微不足道的细节,共同铸就了卓越的用户体验。

这个优化后的主页,已经不再仅仅是一个“查询入口”,而是一个 集美观、高效、引导于一体的智能交互中心。它完美诠释了 Flutter 在构建高性能、高颜值移动应用方面的强大能力,也为所有开发者提供了一个值得借鉴的优秀范例。

加入社区

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


技术因分享而进步,生态因共建而繁荣。
—— 晚霞的不甘 · 与您共赴鸿蒙跨平台开发之旅

完整代码展示

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 DictionaryHomeScreen(),
);
}
}
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 = [];
        late AnimationController _animationController;
        late Animation<double> _fadeInAnimation;
          // 模拟字典数据
          final List<DictionaryEntry> _dictionaryData = [
            DictionaryEntry(
            word: '学习',
            pinyin: 'xué xí',
            partOfSpeech: '动词',
            definition: '通过阅读、听讲、研究、实践等途径获得知识或技能。',
            example: '我们要努力学习科学文化知识。',
            relatedWords: ['自学', '研习', '进修'],
            gradient: [const Color(0xFF667EEA), const Color(0xFF764BA2)],
            ),
            DictionaryEntry(
            word: '努力',
            pinyin: 'nǔ lì',
            partOfSpeech: '形容词',
            definition: '尽最大力量;尽一切可能。',
            example: '他工作非常努力。',
            relatedWords: ['勤奋', '刻苦', '尽力'],
            gradient: [const Color(0xFFF093FB), const Color(0xFFF5576C)],
            ),
            DictionaryEntry(
            word: '知识',
            pinyin: 'zhī shi',
            partOfSpeech: '名词',
            definition: '人们在认识世界、改造世界的过程中积累起来的经验。',
            example: '知识就是力量。',
            relatedWords: ['常识', '学识', '见识'],
            gradient: [const Color(0xFF4FACFE), const Color(0xFF00F2FE)],
            ),
            DictionaryEntry(
            word: '文化',
            pinyin: 'wén huà',
            partOfSpeech: '名词',
            definition: '人类在社会实践中所创造的物质财富和精神财富的总和。',
            example: '中华文明历史悠久,文化灿烂。',
            relatedWords: ['文明', '艺术', '传统'],
            gradient: [const Color(0xFFFA709A), const Color(0xFFFEE140)],
            ),
            DictionaryEntry(
            word: '创新',
            pinyin: 'chuàng xīn',
            partOfSpeech: '动词',
            definition: '抛开旧的,创造新的。',
            example: '科技创新推动了社会进步。',
            relatedWords: ['改革', '创造', '发明'],
            gradient: [const Color(0xFF30CFD0), const Color(0xFF330867)],
            ),
            DictionaryEntry(
            word: '发展',
            pinyin: 'fā zhǎn',
            partOfSpeech: '动词',
            definition: '事物由小到大、由简到繁、由低级到高级的变化。',
            example: '经济持续健康发展。',
            relatedWords: ['进步', '增长', '扩展'],
            gradient: [const Color(0xFFA8FF78), const Color(0xFF78FFA8)],
            ),
            DictionaryEntry(
            word: '理想',
            pinyin: 'lǐ xiǎng',
            partOfSpeech: '名词',
            definition: '对未来事物的想象或希望。',
            example: '每个人都有自己的理想。',
            relatedWords: ['梦想', '抱负', '目标'],
            gradient: [const Color(0xFFFF9A9E), const Color(0xFFFECFEF)],
            ),
            DictionaryEntry(
            word: '坚持',
            pinyin: 'jiān chí',
            partOfSpeech: '动词',
            definition: '坚决保持、维持或进行。',
            example: '坚持就是胜利。',
            relatedWords: ['坚守', '执着', '持续'],
            gradient: [const Color(0xFFFFF9C), const Color(0xFFFFB199)],
            ),
            DictionaryEntry(
            word: '成功',
            pinyin: 'chéng gōng',
            partOfSpeech: '名词',
            definition: '达到预期的目的或结果。',
            example: '经过不懈努力,他终于成功了。',
            relatedWords: ['胜利', '成就', '收获'],
            gradient: [const Color(0xFF89F7FE), const Color(0xFF66A6FF)],
            ),
            DictionaryEntry(
            word: '友谊',
            pinyin: 'yǒu yì',
            partOfSpeech: '名词',
            definition: '朋友之间的交情。',
            example: '友谊是人生最宝贵的财富之一。',
            relatedWords: ['友情', '交情', '伙伴'],
            gradient: [const Color(0xFFE0C3FC), const Color(0xFF8EC5FC)],
            ),
            ];
            @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: 400), () {
              final results = _dictionaryData.where((entry) {
              return entry.word.contains(query) ||
              entry.pinyin.toLowerCase().contains(query.toLowerCase()) ||
              entry.definition.contains(query);
              }).toList();
              if (query.isNotEmpty && !_searchHistory.contains(query)) {
              setState(() {
              _searchHistory.insert(0, query);
              if (_searchHistory.length > 10) {
              _searchHistory.removeLast();
              }
              });
              }
              setState(() {
              _searchResults = results;
              _isSearching = false;
              });
              });
              }
              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) {
              _performSearch(value);
              },
              onSubmitted: (value) {
              _performSearch(value);
              },
              ),
              ),
              ),
              const SizedBox(height: 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: Row(
              children: [
              // 左侧渐变条
              Container(
              width: 6,
              decoration: BoxDecoration(
              gradient: LinearGradient(
              colors: entry.gradient,
              begin: Alignment.topCenter,
              end: Alignment.bottomCenter,
              ),
              ),
              ),
              // 内容区域
              Expanded(
              child: Padding(
              padding: const EdgeInsets.all(20),
              child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
              Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
              Text(
              entry.word,
              style: const TextStyle(
              fontSize: 24,
              fontWeight: FontWeight.bold,
              ),
              ),
              Container(
              padding: const EdgeInsets.symmetric(
              horizontal: 10,
              vertical: 4,
              ),
              decoration: BoxDecoration(
              color: entry.gradient[0].withOpacity(0.1),
              borderRadius: BorderRadius.circular(8),
              ),
              child: Text(
              entry.partOfSpeech,
              style: TextStyle(
              color: entry.gradient[0],
              fontSize: 12,
              fontWeight: FontWeight.w500,
              ),
              ),
              ),
              ],
              ),
              const SizedBox(height: 4),
              Text(
              entry.pinyin,
              style: TextStyle(
              fontSize: 14,
              color: Colors.grey[600],
              ),
              ),
              const SizedBox(height: 8),
              Text(
              entry.definition,
              maxLines: 2,
              overflow: TextOverflow.ellipsis,
              style: TextStyle(
              fontSize: 14,
              color: Colors.grey[700],
              height: 1.5,
              ),
              ),
              ],
              ),
              ),
              ),
              // 箭头图标
              Container(
              padding: const EdgeInsets.all(16),
              child: Icon(
              Icons.chevron_right_rounded,
              color: entry.gradient[0],
              size: 24,
              ),
              ),
              ],
              ),
              ),
              ),
              );
              }
              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(),
              ),
              ],
              ),
              );
              }
              }
              // 词语详情页面
              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> relatedWords;
                final List<Color> gradient;
                  DictionaryEntry({
                  required this.word,
                  required this.pinyin,
                  required this.partOfSpeech,
                  required this.definition,
                  required this.example,
                  required this.relatedWords,
                  required this.gradient,
                  });
                  }
posted @ 2026-03-08 17:58  yangykaifa  阅读(52)  评论(0)    收藏  举报