5 Mixins That Made My Flutter Code 10x Cleaner
Teqani Blogs
Writer at Teqani
Mixins are reusable code snippets that can be added to classes in Flutter, offering a way to share functionality without deep inheritance hierarchies. This article explores five essential mixins to enhance code cleanliness and efficiency.
SingleAnimationMixin
The SingleAnimationMixin simplifies the setup of a single AnimationController, reducing boilerplate when creating animations in Flutter. This mixin manages the initialization and disposal of the controller, providing a clean way to implement repeating animations.
mixin SingleRepeatAnimationMixin<T extends StatefulWidget> on State<T>, SingleTickerProviderStateMixin {
late AnimationController animationController;
Duration get animationDuration => const Duration(seconds: 1);
bool get repeatInReverse => true;
@override
void initState() {
super.initState();
animationController = AnimationController(
vsync: this,
duration: animationDuration,
)..repeat(reverse: repeatInReverse);
}
@override
void dispose() {
animationController.dispose();
super.dispose();
}
}
FormFieldValidationMixin
This FormFieldValidationMixin provides pre-built validators for common form fields. It includes functions for checking if a field is required or if an email is valid, reducing the need to rewrite these validations repeatedly.
mixin FormFieldValidationMixin {
String? isRequired(String? value, [String field = "This field"]) {
if (value == null || value.trim().isEmpty) return "$field is required.";
return null;
}
String? isEmail(String? value) {
if (value == null || value.isEmpty) return "Email is required.";
final regex = RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$');
if (!regex.hasMatch(value)) return "Enter a valid email.";
return null;
}
}
DelayedInitMixin
The DelayedInitMixin allows you to execute code after the first frame is rendered. This is useful for tasks like scrolling to a specific position or showing a dialog after the widget has fully built, avoiding common layout issues.
mixin DelayedInitMixin<T extends StatefulWidget> on State<T> {
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) => afterFirstLayout());
}
void afterFirstLayout();
}
RebuildCounterMixin
This RebuildCounterMixin tracks the number of times a widget rebuilds, aiding in performance debugging and optimization. It prints the rebuild count to the debug console and can be used to display the count in the UI.
mixin RebuildMixin<T extends StatefulWidget> on State<T> {
int _rebuilds = 0;
@override
Widget build(BuildContext context) {
_rebuilds++;
debugPrint('${widget.runtimeType} rebuilt $_rebuilds times');
return buildWithCount(context, _rebuilds);
}
Widget buildWithCount(BuildContext context, int count);
}
RenderAwareMixin
The RenderAwareMixin provides easy access to the size and position of a widget after it has been rendered. This mixin uses a GlobalKey to access the RenderBox, providing the widget's size and screen offset.
mixin RenderAwareMixin<T extends StatefulWidget> on State<T> {
final renderKey = GlobalKey();
Size? get widgetSize {
final ctx = renderKey.currentContext;
if (ctx == null) return null;
final box = ctx.findRenderObject() as RenderBox?;
return box?.size;
}
Offset? get widgetPosition {
final ctx = renderKey.currentContext;
if (ctx == null) return null;
final box = ctx.findRenderObject() as RenderBox?;
return box?.localToGlobal(Offset.zero);
}
}
By incorporating these mixins into your Flutter projects, you can significantly improve code reusability, reduce boilerplate, and enhance overall code quality. Experiment with these tools and discover the efficiency they bring to your development workflow.
All blogs are certified by our company and reviewed by our specialists
Issue Number: #e7aa9a27-a141-49b2-8f61-37a4d86b0c1c