v2.5.0marqueer
一个可自定义的 Flutter 滚动字幕小部件,支持多方向滚动、用户交互和程序化控制。
适用于 Flutter 的 Marquee 包
{"sdk":"flutter"}^10.0.0以下为英文项目原文快照,最新内容请访问 GitHub。
The Marqueer package is a versatile Flutter widget designed to create smooth and customizable marquee effects. Whether you're building a news ticker, scrolling advertisements, or any animated content display, Marqueer offers flexibility, performance, and user interaction controls.
With support for infinite scrolling, dynamic item generation, and highly customizable animation behavior, Marqueer ensures an engaging and fluid user experience.
previewpps (pixels per second) parameter.builder constructor for generating items dynamically.setState. Only restarts when pps, direction, or infinity parameters change.true, the widget creates an endless loop by either:
By adjusting the infinity parameter, you can control how the marquee behaves at its boundaries, ensuring a smooth experience regardless of content length.
direction: Defines the scroll direction. Options include:
rtl (Right-to-Left)ltr (Left-to-Right)ttb (Top-to-Bottom)btt (Bottom-to-Top)pps: Pixels per second, controlling the speed of the scroll animation. For instance, pps: 15.0 means 15 pixels are scrolled every second.
infinity: A bool determining how the scroll behaves after reaching the end of the list. When enabled, it either duplicates the content or reverses the animation.
autoStart: A bool controlling whether the marquee starts automatically when the widget is built.
interaction: If true, pauses the animation on user touch.restartAfterInteraction: Automatically restarts scrolling after user interaction if enabled.restartAfterInteractionDuration: Specifies the delay before restarting, e.g., Duration(seconds: 3).separatorBuilder: Adds a separator widget between items in the marquee.padding: Adds padding around the scrolling content.onStarted: Triggered when the animation starts.onStopped: Triggered when the animation stops.onInteraction: Called when a user interacts with the marquee.onChangeItemInViewPort: Invoked when a new item enters the viewport.controller: An optional MarqueerController to programmatically control the marquee (e.g., start, stop, change direction, or animate to position).edgeDuration: Adds a delay when the marquee reaches the edges, useful in finite scrolling scenarios.clipBehavior: Controls how the content is clipped. Default is Clip.hardEdge.intrinsicCrossAxisSize: Auto-sizes the cross axis based on child widget. No need for SizedBox wrapper. Default is false.start(): Starts the marquee animationstop(): Stops the marquee animationforward(): Starts forward animation (left to right or bottom to top)backward(): Starts backward animation (right to left or top to bottom)animateTo(position, duration, curve): Animates to a specific scroll positioninteractionEnabled(enabled): Enables or disables user interactionrecalculateIntrinsicSize(): Recalculates intrinsic size when child content changesisAnimating: Returns the animation status (requires single attached widget)The scrollablePointerIgnoring parameter is a boolean that resolves gesture-related issues caused by Flutter's default IgnorePointer behavior within Scrollable widgets. When set to true, it ensures that the IgnorePointer behavior in nested scrollable elements is bypassed, allowing gestures to propagate correctly.
Flutter's Scrollable widget applies an IgnorePointer by default to prevent unintended interactions during animations. However, this can interfere with custom gestures or user interactions in certain scenarios. Enabling scrollablePointerIgnoring ensures smooth and predictable gesture handling.
false: The default IgnorePointer behavior remains active.true: Disables the default IgnorePointer behavior, allowing gestures to work as expected.final controller = MarqueerController();
/// controller.start()
/// controller.stop()
/// controller.forward()
/// controller.backward()
/// controller.animateTo(position, duration: duration, curve: curve)
/// controller.interactionEnabled(false)
SizedBox(
height: 30,
child: Marqueer(
pps: 100,
/// optional
controller: controller,
/// optional
direction: .rtl,
/// optional
restartAfterInteractionDuration: const Duration(seconds: 6),
/// optional
restartAfterInteraction: false,
/// optional
onChangeItemInViewPort: (index) {
print('item index: $index');
},
onInteraction: () {
print('on interaction callback');
},
onStarted: () {
print('on started callback');
},
onStopped: () {
print('on stopped callback');
},
child: const Text(
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer pretium massa mollis lorem blandit imperdiet. Nulla mattis vitae mauris vel condimentum. Nam posuere, augue vitae lobortis consequat, odio ante condimentum est, at maximus augue purus id metus. Curabitur condimentum aliquet ante at aliquet. Quisque vel massa congue, bibendum leo sodales, malesuada ante. Maecenas sed tortor quis ipsum dictum sollicitudin.',
),
),
);
Usage with builder
SizedBox(
height: 50,
child: Marqueer.builder(
itemCount: 200,
interaction: false,
scrollablePointerIgnoring: true,
itemBuilder: (context, index) {
return GestureDetector(
onTap: () => print('tapped $index'),
child: Padding(
padding: .all(4),
child: Text('index: $index'),
),
);
},
),
);
Basic usage
SizedBox(
height: 50,
child: Marqueer(
child: AnyWidget(),
),
);
Auto-size (no SizedBox needed)
Marqueer(
intrinsicCrossAxisSize: true,
child: Text('Auto-sized marquee text'),
)