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

基于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),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

关键代码说明

  1. 滚动控制:通过WidgetsBinding.instance.addPostFrameCallback确保在文本更新、布局重建完成后再执行滚动操作,避免滚动位置不准确的问题。
  2. 动画启停:使用Timer.periodic创建定时任务,逐字拼接文本;点击按钮时取消定时器并更新状态,终止动画。
  3. 状态管理:通过_isTyping变量控制按钮状态和动画逻辑,确保重复点击不会创建多个定时器。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 17:53:09