醉临武-临武县第一中学官网

Flutter 跑马灯组件

本文介绍2种跑马灯效果的实现:连贯式,非连贯式。效果如下图

marquee image


连贯式

实现思路:写一个无限长度的列表(ListView),通过一个定时任务(Timer)每隔一定时间滑动一定距离(ScrollController)。这里面比较tricky的是滑动距离的设置,你不能直接设置一个和时间成正比的值。因为页面可能存在息屏或者跳转到其它页面的不可见状态,此时是不希望有滑动的,就算你给他设置了滑动,系统并不会去滑动它。所以每次轮询都去获取当前列表滑动的距离(scrollController.offset),在它基础上加上一个距离作为要滚动到的位置。

class _MarqueeContinuousState extends State<MarqueeContinuous> {  
 ScrollController _controller;   
 Timer _timer;   
 double _offset = 0.0;   
 @override   void initState() {     
 super.initState();    
  _controller = ScrollController(initialScrollOffset: _offset);     
  _timer = Timer.periodic(widget.duration, (timer) {      
   double newOffset = _controller.offset + widget.stepOffset;       
   if (newOffset != _offset) {         
   _offset = newOffset;        
    _controller.animateTo(_offset,             
    duration: widget.duration, curve: Curves.linear);       
    }   
      });  
       }   
       @override   void dispose() {     
       _timer.cancel();     
       _controller.dispose();     
       super.dispose();  
        }   
        @override   Widget build(BuildContext context) {     
        return ListView.builder(         
        scrollDirection: Axis.horizontal,         
        controller: _controller,         
        itemBuilder: (context, index) {           
        return widget.child;         
        });   
        } }

非连贯式

实现思路:通过不断播放平移动画来实现(FractionalTranslation)。这里需要注意的是,动画是全屏幕展示的,如果你要让它只在控件范围内显示,需要把它包裹在ClipRect中(ClipRect会把超出控件部分裁剪掉)。另外要使超出屏幕宽度的文字不被折叠,需要把控件包裹在SingleChildScrollView中。

class _MarqueeSingleState extends State<MarqueeSingle> with SingleTickerProviderStateMixin {   
AnimationController _controller;   
Animation<Offset> _animation;   
@override   void initState() {     
super.initState();     
_controller =         AnimationController(vsync: this, duration: Duration(seconds: 10));     
_animation = Tween<Offset>(begin: Offset(1.0, 0.0), end: Offset(-1.0, 0.0))         .animate(_controller);     
_animation.addListener(() {       
setState(() {});    
 });    
 _controller.repeat();   
}  
 @override   Widget build(BuildContext context) {     
 return ClipRect(child: FractionalTranslation(         
 translation: _animation.value,         
 child: SingleChildScrollView(             
 scrollDirection: Axis.horizontal, child: widget.child)));  
  }   
  @override   void dispose() {     
  _controller.dispose();     
  super.dispose();   
  } }

总结

以上是实现跑马灯效果的2种思路,大家可以根据UI需求进行选择。在此基础上,你还可以做其它的自定义,如设置滚动的速度,滚动的方向等。