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

Flutter单个Widget内多文本循环淡入淡出效果如何实现

多段文本循环淡入淡出实现方案

首先调整核心逻辑,支持多文本轮播,对齐目标效果的时间节奏:文本展示停留2秒→2秒淡出→切换文本→2秒淡入→停留2秒循环,修改内容如下:

  • 定义多段文本列表存储需要轮播的所有文案
  • 新增当前展示文本索引变量跟踪轮播进度
  • 调整opacity控制逻辑,对齐淡入淡出与文本切换的时序
  • 使用Timer控制动画循环,dispose时销毁Timer避免内存泄漏

完整可运行代码

import 'dart:async';
import 'package:audioplayers/audioplayers.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HomeScreen(),
    );
  }
}

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

  @override
  _HomeScreenState createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  AudioPlayer audioPlayer = AudioPlayer();
  Duration duration = Duration();
  Duration position = Duration();
  bool playing = false;
  Timer? textAnimationTimer;

  // 自定义轮播文本列表,可按需新增修改
  final List<String> quoteList = [
    'Television contracts the imagination and radio expands it.',
    'Radio is the theater of the mind.',
    'Listening to radio is like having a friend in the room.',
    'Radio connects people across boundaries and generations.'
  ];
  int currentTextIndex = 0;
  double opacity = 1.0;

  @override
  void initState() {
    super.initState();
    startTextAnimation();
  }

  startTextAnimation() {
    // 每4秒触发一次切换:2秒停留 + 2秒淡出
    textAnimationTimer = Timer.periodic(const Duration(seconds: 4), (timer) {
      // 第一步:当前文本淡出
      setState(() {
        opacity = 0.0;
      });
      // 等待2秒淡出完成后切换文本再淡入
      Future.delayed(const Duration(seconds: 2), () {
        if(mounted) {
          setState(() {
            currentTextIndex = (currentTextIndex + 1) % quoteList.length;
            opacity = 1.0;
          });
        }
      });
    });
  }

  @override
  void dispose() {
    audioPlayer.dispose();
    textAnimationTimer?.cancel();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        backgroundColor: const Color(0xff252525),
        appBar: AppBar(
          backgroundColor: const Color(0xffffcb05),
          title: Image.asset(
            'assets/logoradio.png',
            fit: BoxFit.contain,
            height: 40,
            width: 40,
          ),
          actions: [IconButton(icon: const Icon(Icons.search), onPressed: () {})],
        ),
        drawer: Drawer(
          elevation: 10.0,
          child: ListView(
            children: [
              UserAccountsDrawerHeader(
                accountName: const Text('sundar'),
                accountEmail: const Text('sundar@gmail.com'),
                currentAccountPicture: CircleAvatar(
                  backgroundColor: Colors.red,
                  child: const Text('xyz'),
                ),
                otherAccountsPictures: [
                  CircleAvatar(
                    backgroundColor: Colors.red,
                    child: const Text('ABC'),
                  )
                ],
              ),
              const ListTile(
                title: Text('HOME'),
                leading: Icon(Icons.mail),
              ),
              const Divider(
                height: 0.5,
                color: Colors.red,
              ),
              const ListTile(
                title: Text('PODCAST'),
                leading: Icon(Icons.mail),
              ),
              const Divider(
                height: 0.5,
                color: Colors.red,
              ),
              const ListTile(
                title: Text('ABOUT'),
                leading: Icon(Icons.mail),
              ),
              const Divider(
                height: 0.5,
                color: Colors.red,
              ),
              const ListTile(
                title: Text('CONTACT'),
                leading: Icon(Icons.people),
              )
            ],
          ),
        ),
        body: SafeArea(
            child: Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  // 单个AnimatedOpacity组件实现多文本轮播
                  AnimatedOpacity(
                    opacity: opacity,
                    duration: const Duration(seconds: 2),
                    child: Text(
                      quoteList[currentTextIndex],
                      textAlign: TextAlign.center,
                      style: const TextStyle(
                        color: Colors.red,
                        fontSize: 30,
                      ),
                    ),
                  ),
                  const SizedBox(height: 80,),
                  InkWell(
                    onTap: () {
                      getAudio();
                    },
                    child: Icon(
                      playing == false
                          ? Icons.play_circle_outline
                          : Icons.pause_circle_outline,
                      size: 50,
                      color: Colors.red,
                    ),
                  ),
                ],
              ),
            )));
  }

  Widget slider() {
    return Slider.adaptive(
        min: 0.0,
        value: position.inSeconds.toDouble(),
        max: duration.inSeconds.toDouble(),
        onChanged: (double value) {
          setState(() {
            audioPlayer.seek(Duration(seconds: value.toInt()));
          });
        });
  }

  void getAudio() async {
    var url = "https://live.radio5ive.com/proxy/radio5ivetamil/stream";
    if (playing) {
      var res = await audioPlayer.pause();
      if (res == 1) {
        setState(() {
          playing = false;
        });
      }
    } else {
      var res = await audioPlayer.play(url, isLocal: false);
      if (res == 1) {
        setState(() {
          playing = true;
        });
      }
    }
    audioPlayer.onDurationChanged.listen((Duration dd) {
      setState(() {
        duration = dd;
      });
    });
    audioPlayer.onAudioPositionChanged.listen((Duration dd) {
      setState(() {
        position = dd;
      });
    });
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 20:15:04