本文介绍2种跑马灯效果的实现:连贯式,非连贯式。效果如下图
连贯式
实现思路:写一个无限长度的列表(ListView),通过一个定时任务(Timer)每隔一定时间滑动一定距离(ScrollController)。这里面比较tricky的是滑动距离的设置,你不能直接设置一个和时间成正比的值。因为页面可能存在息屏或者跳转到其它页面的不可见状态,此时是不希望有滑动的,就算你给他设置了滑动,系统并不会去滑动它。所以每次轮询都去获取当前列表滑动的距离(scrollController.offset),在它基础上加上一个距离作为要滚动到的位置。
class _MarqueeContinuousState extends State{ 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 Statewith SingleTickerProviderStateMixin { AnimationController _controller; Animation _animation; @override void initState() { super.initState(); _controller = AnimationController(vsync: this, duration: Duration(seconds: 10)); _animation = Tween (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需求进行选择。在此基础上,你还可以做其它的自定义,如设置滚动的速度,滚动的方向等。 最后附上,以供参考。
本文版权属于再惠研发团队,欢迎转载,转载请保留出处。