Skip to content

Instantly share code, notes, and snippets.

@kitsuniru
Last active July 3, 2023 19:15
Show Gist options
  • Save kitsuniru/cebbcfef0b49c3baf0ba16f3038f3239 to your computer and use it in GitHub Desktop.
Save kitsuniru/cebbcfef0b49c3baf0ba16f3038f3239 to your computer and use it in GitHub Desktop.
Animate system chrome (StatusBar & NavBar) during animating between routes
import 'package:flutter/material.dart';
import 'system_chrome_animation.dart';
class AnimatedMaterialRoute<T> extends MaterialPageRoute<T> with SystemChromeAnimationMixin {
AnimatedMaterialRoute({required super.builder, required this.originColor, required this.targetColor});
@override
final Color originColor;
@override
final Color targetColor;
}
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:meta/meta.dart';
/// Use this mixin to animate navigation bar color (android only).
/// When you are using annotated region or SystemChrome.setUiOverlayStyle color
/// will be set with delay and without animation. With current implementation
/// navbar color will be interpolated between [originColor] and [targetColor] colors.
mixin SystemChromeAnimationMixin<T> on ModalRoute<T> {
@mustBeOverridden
Color get originColor;
@mustBeOverridden
Color get targetColor;
@override
Widget buildPage(
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
) {
///take overlays control from AnnotatedRegions widgets
WidgetsBinding.instance.renderView.automaticSystemUiAdjustment = false;
///Listen to route animation and applying colors linear interpolation.
animation.addListener(() {
unawaited(setNavBar(context, animation.value));
});
return super.buildPage(context, animation, secondaryAnimation);
}
/// Copy of _toMap implementation from SystemChrome class.
Map<String, dynamic> _toMap(SystemUiOverlayStyle style) {
return <String, dynamic>{
'systemNavigationBarColor': style.systemNavigationBarColor?.value,
'systemNavigationBarDividerColor': style.systemNavigationBarDividerColor?.value,
'systemStatusBarContrastEnforced': style.systemStatusBarContrastEnforced,
'statusBarColor': style.statusBarColor?.value,
'statusBarBrightness': style.statusBarBrightness?.toString(),
'statusBarIconBrightness': style.statusBarIconBrightness?.toString(),
'systemNavigationBarIconBrightness': style.systemNavigationBarIconBrightness?.toString(),
'systemNavigationBarContrastEnforced': style.systemNavigationBarContrastEnforced,
};
}
Future<void> setNavBar(BuildContext context, double value) async {
if (context.mounted) {
final color = Color.lerp(
originColor,
targetColor,
value,
);
/// Same implementation as in SystemChrome.setUiOverlayStyle, but without
/// microtask scheduling
await SystemChannels.platform.invokeMethod<void>(
'SystemChrome.setSystemUIOverlayStyle',
_toMap(
// ignore: invalid_use_of_visible_for_testing_member
SystemChrome.latestStyle!.copyWith(
systemNavigationBarIconBrightness: Theme.of(context).brightness,
// uncomment this if you want to change
// color of status bar too
//
// statusBarColor: color,
systemNavigationBarColor: color,
),
),
);
}
}
@override
bool didPop(T? result) {
/// switching ui adjustment after pop for returning overlays control to
/// AnnotatedRegion.
WidgetsBinding.instance.renderView.automaticSystemUiAdjustment = true;
animation?.removeListener(() {});
return super.didPop(result);
}
}
@kitsuniru
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment