Flutter Mixins
As mentioned at the start of this book, a Mixin is a class that contains methods for use by other classes without it having to be the parent class of those other classes.
So, a Mixin is a class you can use code from without having to inherit from.
It enables developers to piecemeal classes together without having to get involved with inheritance, abstract classes etc.
Mixins & Code Generators
Mixins are often used to merge generated code into your code. The generator creates abstract classes containing code. Your code then usesthe ‘with’ + the abstract class name to include that code in your class as a mixin.
Example
If you use the ‘json_serializable’ package and you invoke the build_runner to build the serialization / deserialization code, some of that generated code resides in an abstract class. Later on, you combine that code into your classes using a mixin.See Generating Code for Serializing & Deserializing for more information.
Example – ‘mixins’
This app draws circles and squares using a CircleWidget and a SquareWidget. They have corresponding CirclePainter and SquarePainter classes that paint onto the canvas with random colors.The CirclePainter and SquarePainter use the Colorizer class as a mixin to provide random colors.
Source Code
import 'dart:math';
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new CircleWidget(),
routes: <String, WidgetBuilder>{
'/circle': (context) => CircleWidget(),
'/square': (context) => SquareWidget(),
},
);
}
}
class Colorizer {
final _random = new Random();
int next(int min, int max) => min + _random.nextInt(max - min);
List<Color> _colors = [];
_initColors() {
for (int i = 0; i < 100; i++) {
_colors.add(Colors.green
.withRed(next(0, 255))
.withGreen(next(0, 255))
.withBlue(next(0, 255)));
}
}
}
class CirclePainter extends CustomPainter with Colorizer {
CirclePainter() {
_initColors();
}
@override
void paint(Canvas canvas, Size size) {
for (int i = 0; i < 100; i++) {
var radius = (i * 10).toDouble();
canvas.drawCircle(
new Offset(1000.0, 1000.0),
radius,
new Paint()
..color = _colors[i]
..strokeCap = StrokeCap.round
..style = PaintingStyle.stroke
..strokeWidth = 15.0);
}
}
@override
bool shouldRepaint(CirclePainter oldDelegate) {
return false;
}
}
class SquarePainter extends CustomPainter with Colorizer {
SquarePainter() {
_initColors();
}
@override
void paint(Canvas canvas, Size size) {
for (int i = 0; i < 100; i++) {
var inset = (i * 10).toDouble();
canvas.drawRect(
new Rect.fromLTRB(inset, inset, 2000.0 - inset, 2000.0 - inset),
new Paint()
..color = _colors[i]
..strokeCap = StrokeCap.round
..style = PaintingStyle.stroke
..strokeWidth = 15.0);
}
}
@override
bool shouldRepaint(CirclePainter oldDelegate) {
return false;
}
}
class CircleWidget extends StatelessWidget {
CirclePainter _painter = new CirclePainter();
CircleWidget({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(title: new Text("Circle"), actions: [
IconButton(
icon: Icon(Icons.crop_square),
onPressed: () => Navigator.pushNamed(context, "/square"))
]),
body: new SingleChildScrollView(
scrollDirection: Axis.horizontal,
physics: AlwaysScrollableScrollPhysics(),
child: CustomPaint(
size: Size(2000.0, 2000.0),
foregroundPainter: _painter,
)));
}
}
class SquareWidget extends StatelessWidget {
SquarePainter _painter = new SquarePainter();
SquareWidget({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("Square"),
),
body: new SingleChildScrollView(
scrollDirection: Axis.horizontal,
physics: AlwaysScrollableScrollPhysics(),
child: CustomPaint(
size: Size(2000.0, 2000.0),
foregroundPainter: _painter,
)));
}
}