Theme Toggle Animation

Smooth, animated theme switching for Flutter.

Circle reveals, scanning lines, and custom GIF mask animations โ€” zero dependencies, fully customizable.

Pub CI License Flutter

Get Started ยท Examples ยท API


Demo

Circle Line Custom Mask
Circle animation demo Line animation demo Custom mask animation demo
Expanding circle reveal from any corner or tap position. Scanning line sweep across the screen. Animated GIF mask reveal effect.

Note

Demo GIFs looks a bit pixalated due to the conversion from mp4 recording. It looks better originally in the UI when using this theme toggle animation.


โœจ Features

Feature Description
๐ŸŽฏ 3 animation types circle, line, customMask
๐Ÿ“ 5 circle directions 4 corners + from tap position
๐Ÿ“ 10 line directions Cardinal, diagonal, and from tap position
๐Ÿ–ผ๏ธ GIF mask animation Animated GIFs as reveal masks
๐Ÿ”€ Custom clip paths Bring your own Path function
๐ŸŒซ๏ธ Blur effects Configurable blur on animation edges
๐ŸŽ›๏ธ Configurable Duration, curve, enabled flag
๐Ÿ”” Lifecycle callbacks onAnimationStart / onAnimationEnd
โšก Optimized RepaintBoundary, content caching, GPU clips
๐Ÿงฉ State management agnostic Provider, Riverpod, Bloc, GetX โ€” all work
๐Ÿ“ฆ Zero dependencies Only Flutter SDK

๐Ÿ“ฆ Installation

Add to your pubspec.yaml:

dependencies:
  theme_toggle_animation: ^1.0.3

Then run:

flutter pub get

๐Ÿš€ Quick Start

class MyApp extends StatefulWidget {
  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  bool _isDark = false;

  @override
  Widget build(BuildContext context) {
    return ThemeToggleAnimation(
      currentTheme: _isDark ? ThemeData.dark() : ThemeData.light(),
      onToggle: () => setState(() => _isDark = !_isDark),
      builder: (context, toggle) => MaterialApp(
        home: Scaffold(
          appBar: AppBar(
            actions: [
              IconButton(
                icon: Icon(_isDark ? Icons.light_mode : Icons.dark_mode),
                onPressed: toggle,
              ),
            ],
          ),
          body: const Center(child: Text('Hello World')),
        ),
      ),
      child: const SizedBox.expand(),
    );
  }
}

๐ŸŽฌ Examples

Circle

Expanding circle reveal from any corner or the tap position:

ThemeToggleAnimation(
  currentTheme: myTheme,
  animationType: ThemeAnimationType.circle,
  circleDirection: CircleAnimationDirection.fromWidget,
  blurAmount: 4.0,
  onToggle: () => setState(() => _isDark = !_isDark),
  builder: (context, toggle) => MyToggleWidget(onTap: toggle),
  child: MyApp(),
)
Direction Description
ftl From top-left
ftr From top-right
fbl From bottom-left
fbr From bottom-right
fromWidget From tap position

Line

Scanning line sweep in 10 directions:

ThemeToggleAnimation(
  currentTheme: myTheme,
  animationType: ThemeAnimationType.line,
  lineDirection: LineAnimationDirection.ltr,
  blurAmount: 4.0,
  onToggle: () => setState(() => _isDark = !_isDark),
  builder: (context, toggle) => MyToggleWidget(onTap: toggle),
  child: MyApp(),
)
Direction Description
ltr Left โ†’ right
rtl Right โ†’ left
ttb Top โ†’ bottom
btt Bottom โ†’ top
fromWidgetHorizontal From tap, horizontal
fromWidgetVertical From tap, vertical
ftl Diagonal top-left
ftr Diagonal top-right
fbl Diagonal bottom-left
fbr Diagonal bottom-right

Custom Mask

Reveal the new theme through an animated GIF:

ThemeToggleAnimation(
  currentTheme: myTheme,
  animationType: ThemeAnimationType.customMask,
  customMaskImage: AssetImage('assets/mask.gif'),
  customMaskOffset: Offset(50, 100),
  customMaskSize: Size(150, 150),
  duration: Duration(milliseconds: 2000),
  onToggle: () => setState(() => _isDark = !_isDark),
  builder: (context, toggle) => MyToggleWidget(onTap: toggle),
  child: MyApp(),
)

๐Ÿ’ก GIFs with transparent backgrounds work best โ€” opaque pixels reveal the new theme.


๐Ÿ”Œ State Management

Works with any state management solution โ€” just call onToggle to flip your state.

Provider / Riverpod
ThemeToggleAnimation(
  currentTheme: ref.watch(themeProvider),
  onToggle: () => ref.read(themeProvider.notifier).toggle(),
  builder: (context, toggle) => MyToggleWidget(onTap: toggle),
  child: MyApp(),
)
Bloc
ThemeToggleAnimation(
  currentTheme: context.read<ThemeBloc>().state.themeData,
  onToggle: () => context.read<ThemeBloc>().add(ToggleTheme()),
  builder: (context, toggle) => MyToggleWidget(onTap: toggle),
  child: MyApp(),
)
GetX
ThemeToggleAnimation(
  currentTheme: Get.isDarkMode ? darkTheme : lightTheme,
  onToggle: () => Get.isDarkMode
      ? Get.changeTheme(lightTheme)
      : Get.changeTheme(darkTheme),
  builder: (context, toggle) => MyToggleWidget(onTap: toggle),
  child: MyApp(),
)
setState
ThemeToggleAnimation(
  currentTheme: _isDark ? darkTheme : lightTheme,
  onToggle: () => setState(() => _isDark = !_isDark),
  builder: (context, toggle) => MyToggleWidget(onTap: toggle),
  child: MyApp(),
)

๐Ÿ“– API Reference

ThemeToggleAnimation

Parameter Type Default Description
currentTheme ThemeData required The current theme to apply
builder Widget Function(BuildContext, VoidCallback) required Builder with toggle callback
child Widget required Child widget tree
onToggle VoidCallback? null Called when toggle is tapped
animationType ThemeAnimationType circle Animation effect
duration Duration 750ms Animation duration
curve Curve easeInOut Animation curve
enabled bool true Enable / disable animation
onAnimationStart VoidCallback? null Fired when animation starts
onAnimationEnd VoidCallback? null Fired when animation completes
circleDirection CircleAnimationDirection ftl Circle origin
lineDirection LineAnimationDirection ltr Line sweep direction
blurAmount double 0.0 Blur intensity (circle / line only)
clipper Path Function(Size, Offset, double)? null Custom clip path
customMaskImage ImageProvider? null GIF / image for mask
customMaskOffset Offset? center Mask position
customMaskSize Size? 200 ร— 200 Mask size during play phase

Enums

ThemeAnimationType โ€” circle ยท line ยท customMask

CircleAnimationDirection โ€” ftl ยท ftr ยท fbl ยท fbr ยท fromWidget

LineAnimationDirection โ€” ltr ยท rtl ยท ttb ยท btt ยท fromWidgetHorizontal ยท fromWidgetVertical ยท ftl ยท ftr ยท fbl ยท fbr


๐Ÿ“‹ Requirements

  • Flutter >=3.0.0
  • Dart SDK ^3.0.0

๐Ÿ“„ License

MIT ยฉ Hirdaya Shrestha โ€” see LICENSE for details.


Made with โค๏ธ by Hirdaya Shrestha

Report Bug ยท Request Feature