基于Flutter实现类ChatGPT对话打字动画及滚动控制的技术求助
Flutter 实现打字动画+自动滚动+终止功能
核心实现思路
- 通过
Timer.periodic定时逐字拼接文本,模拟打字机效果 - 使用
ScrollController监听滚动位置,每次文本更新后自动滚动至底部 - 通过状态变量控制动画启停,点击按钮终止打字过程
完整示例代码
import 'dart:async'; import 'package:flutter/material.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( title: '打字动画示例', theme: ThemeData(primarySwatch: Colors.blue), home: const TypingScrollPage(), ); } } class TypingScrollPage extends StatefulWidget { const TypingScrollPage({super.key}); @override State<TypingScrollPage> createState() => _TypingScrollPageState(); } class _TypingScrollPageState extends State<TypingScrollPage> { late ScrollController _scrollController; // 原始文本内容 final String _fullText = "这是一段用于测试的长文本,演示打字动画效果。当文本逐字显示时,页面会自动滚动到底部,让最新的内容始终可见。点击下方的终止按钮可以随时停止打字动画,再次点击则重新开始。你可以替换这段文本为任意内容,调整打字速度来适配不同的场景需求。"; // 当前显示的文本 String _displayText = ""; Timer? _typingTimer; // 是否正在执行打字动画 bool _isTyping = false; // 打字间隔(毫秒) final int _typingInterval = 200; @override void initState() { super.initState(); _scrollController = ScrollController(); // 初始化时自动开始打字 _startTyping(); } @override void dispose() { _scrollController.dispose(); _typingTimer?.cancel(); super.dispose(); } // 开始打字动画 void _startTyping() { if (_isTyping) return; setState(() { _isTyping = true; _displayText = ""; }); int currentIndex = 0; _typingTimer = Timer.periodic(Duration(milliseconds: _typingInterval), (timer) { if (currentIndex < _fullText.length) { setState(() { _displayText += _fullText[currentIndex]; currentIndex++; }); // 文本更新后自动滚动到底部 WidgetsBinding.instance.addPostFrameCallback((_) { if (_scrollController.hasClients) { _scrollController.jumpTo(_scrollController.position.maxScrollExtent); } }); } else { // 文本全部显示完成后停止定时器 _stopTyping(); } }); } // 终止打字动画 void _stopTyping() { _typingTimer?.cancel(); setState(() { _isTyping = false; }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('打字动画自动滚动示例')), body: Column( children: [ // 控制按钮 Padding( padding: const EdgeInsets.all(16.0), child: ElevatedButton( onPressed: _isTyping ? _stopTyping : _startTyping, child: Text(_isTyping ? '终止打字' : '开始打字'), ), ), // 滚动文本区域 Expanded( child: SingleChildScrollView( controller: _scrollController, padding: const EdgeInsets.all(16.0), child: Text( _displayText, style: const TextStyle(fontSize: 16), ), ), ), ], ), ); } }
关键代码说明
- 滚动控制:通过
WidgetsBinding.instance.addPostFrameCallback确保在文本更新、布局重建完成后再执行滚动操作,避免滚动位置不准确的问题。 - 动画启停:使用
Timer.periodic创建定时任务,逐字拼接文本;点击按钮时取消定时器并更新状态,终止动画。 - 状态管理:通过
_isTyping变量控制按钮状态和动画逻辑,确保重复点击不会创建多个定时器。
内容的提问来源于stack exchange,提问作者zhao
相关产品推荐
相关产品推荐

