before_after_slider 3.1.0
before_after_slider: ^3.1.0 copied to clipboard
Compare before/after images or widgets with a smooth draggable divider, pinch zoom, pan, and customizable overlay UI.
before_after_slider #
A production-ready Flutter widget for before/after comparison with smooth divider drag, zoom/pan gestures, and customizable labels and overlay.
Features #
- Single universal widget:
BeforeAfter(beforeChild, afterChild) - Works with images and arbitrary widgets
- Controlled and uncontrolled progress modes
- Pinch zoom + pan on mobile
- Cmd/Ctrl + wheel zoom on desktop and web
- Optional double-tap zoom
- Grouped options API (
interaction,zoom,labels,overlay) - External
ZoomControllersupport - Platform-adaptive demo app (web/desktop/mobile)
Get Started #
Installation #
dependencies:
before_after_slider: ^3.0.0
flutter pub get
Quick Start #
import 'package:before_after_slider/before_after_slider.dart';
BeforeAfter(
beforeChild: const Image(
image: AssetImage('assets/before.jpg'),
fit: BoxFit.cover,
),
afterChild: const Image(
image: AssetImage('assets/after.jpg'),
fit: BoxFit.cover,
),
)
API Design #
BeforeAfter keeps top-level usage clean and groups behavior into dedicated options:
interactionOptionsfor dragging and hit zoneszoomOptionsfor zoom/pan/pointer settingslabelsOptionsfor label visibility and renderingoverlayOptionsfor style or custom overlay builder
Usage Recipes #
Controlled slider #
class _MyPageState extends State<MyPage> {
double progress = 0.5;
@override
Widget build(BuildContext context) {
return BeforeAfter(
beforeChild: const Image(image: AssetImage('assets/before.jpg'), fit: BoxFit.cover),
afterChild: const Image(image: AssetImage('assets/after.jpg'), fit: BoxFit.cover),
progress: progress,
onProgressChanged: (value) => setState(() => progress = value),
);
}
}
Full interactive setup #
BeforeAfter(
beforeChild: const Image(image: AssetImage('assets/before.jpg'), fit: BoxFit.cover),
afterChild: const Image(image: AssetImage('assets/after.jpg'), fit: BoxFit.cover),
interactionOptions: const BeforeAfterInteractionOptions(
sliderOrientation: SliderOrientation.horizontal,
sliderDragMode: SliderDragMode.fullOverlay,
sliderHitZone: SliderHitZone(
minLineHalfWidth: 18,
minThumbRadius: 30,
),
),
zoomOptions: const BeforeAfterZoomOptions(
enabled: true,
pointer: PointerZoomOptions(
requiresModifier: true,
smoothing: 0.4,
),
enableDoubleTapZoom: true,
doubleTapZoomScale: 3.0,
),
labelsOptions: BeforeAfterLabelsOptions(
behavior: LabelBehavior.attachedToContent,
beforeBuilder: (_) => const Text('Before'),
afterBuilder: (_) => const Text('After'),
),
overlayOptions: const BeforeAfterOverlayOptions(
style: OverlayStyle(
dividerWidth: 2,
thumbSize: 40,
),
),
)
Vertical slider orientation #
BeforeAfter(
beforeChild: ...,
afterChild: ...,
interactionOptions: const BeforeAfterInteractionOptions(
sliderOrientation: SliderOrientation.vertical,
),
)
Custom overlay #
BeforeAfter(
beforeChild: ...,
afterChild: ...,
overlayOptions: BeforeAfterOverlayOptions(
builder: (size, position) {
return Stack(
children: [
Positioned(
left: position.dx,
top: 0,
bottom: 0,
child: const VerticalDivider(width: 2, color: Colors.white),
),
],
);
},
),
)
Auto viewport ratio from image #
BeforeAfter(
autoViewportAspectRatioFromImage: true,
beforeChild: const Image(image: AssetImage('assets/before.jpg')),
afterChild: const Image(image: AssetImage('assets/after.jpg')),
)
Notes:
viewportAspectRatiohas higher priority than auto mode.- Auto mode currently reads ratio from direct
Imagechildren.
Programmatic zoom control #
final zoomController = ZoomController();
BeforeAfter(
beforeChild: ...,
afterChild: ...,
zoomController: zoomController,
)
zoomController.reset();
Desktop and Web Controls #
If PointerZoomOptions.requiresModifier = true:
- macOS: hold
Cmdand use wheel/scroll - Windows/Linux/Web: hold
Ctrland use wheel/scroll
Migration #
2.x -> 3.x #
3.x finalized grouped options in BeforeAfter.
Before:
BeforeAfter(
beforeChild: ...,
afterChild: ...,
overlayStyle: const OverlayStyle(...),
enableProgressWithTouch: true,
enableZoom: true,
)
After:
BeforeAfter(
beforeChild: ...,
afterChild: ...,
interactionOptions: const BeforeAfterInteractionOptions(
enableProgressWithTouch: true,
),
zoomOptions: const BeforeAfterZoomOptions(
enabled: true,
),
overlayOptions: const BeforeAfterOverlayOptions(
style: OverlayStyle(...),
),
)
1.x -> 2.x #
- Removed
BeforeAfterImage - Removed
BeforeAfterLayout - Unified API in
BeforeAfter