Holds predefined Material Design shapes as RoundedPolygons that can be used at various components as they are, or with a MaterialShapeBorder to animate between them.
Note that each RoundedPolygon in this class is normalized.
https://developer.android.com/images/reference/androidx/compose/material3/shapes.png
This example shows how to morph through every shape in all by animating a MaterialShapeBorder.
To see it in action, copy and run this code snippet on DartPad.
import 'dart:async';
import 'package:flutter/physics.dart';
import 'package:material_ui/material_ui.dart';
/// Flutter code sample for [MaterialShapes].
void main() {
runApp(const MaterialShapesExampleApp());
}
class MaterialShapesExampleApp extends StatelessWidget {
const MaterialShapesExampleApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(home: const MaterialShapesExample());
}
}
class MaterialShapesExample extends StatefulWidget {
const MaterialShapesExample({super.key});
@override
State<MaterialShapesExample> createState() => _MaterialShapesExampleState();
}
class _MaterialShapesExampleState extends State<MaterialShapesExample>
with SingleTickerProviderStateMixin {
/// The shapes to morph through, in the order they are listed in
/// [MaterialShapes.all].
static final List<RoundedPolygon> _shapes = MaterialShapes.all;
/// A tween from each shape in [_shapes] to the next one, wrapping around
/// from the last shape back to the first.
///
/// Lerping between two [MaterialShapeBorder]s morphs one shape into the
/// other.
late final List<ShapeBorderTween> _tweens;
/// The tween that is currently animating.
late ShapeBorderTween _tween;
/// Drives the progress of [_tween].
///
/// The controller is unbounded so that the springs below can overshoot past a
/// progress of 1, which carries the morph slightly beyond its end shape.
late final AnimationController _controller;
int _morphIndex = 0;
Timer? _startTimer;
final _bouncySimulation = SpringSimulation(
SpringDescription.withDampingRatio(ratio: 0.5, stiffness: 400, mass: 1),
0,
1,
5,
snapToEnd: true,
);
// Overshooting past a progress of 1 extrapolates a morph beyond its end
// shape, which distorts the heart into sharp spikes. The heart therefore
// animates with a spring that starts at rest and barely overshoots.
final _lessBouncySimulation = SpringSimulation(
SpringDescription.withDampingRatio(ratio: 0.8, stiffness: 300, mass: 1),
0,
1,
0,
snapToEnd: true,
);
/// The shape that the currently animating morph ends on.
RoundedPolygon get _targetShape =>
_shapes[(_morphIndex + 1) % _shapes.length];
@override
void initState() {
super.initState();
_tweens = <ShapeBorderTween>[
for (var i = 0; i < _shapes.length; i++)
ShapeBorderTween(
begin: MaterialShapeBorder(shape: _shapes[i]),
end: MaterialShapeBorder(shape: _shapes[(i + 1) % _shapes.length]),
),
];
_tween = _tweens.first;
_controller = AnimationController.unbounded(vsync: this);
// Hold the first shape for a moment so that it can be seen before it starts
// morphing.
_startTimer = Timer(const Duration(seconds: 1), _morphThroughShapes);
}
@override
void dispose() {
_startTimer?.cancel();
_controller.dispose();
super.dispose();
}
/// Animates the tweens in [_tweens] one after another, looping back to the
/// first one after the last, until this widget is disposed.
///
/// Waiting for each spring to settle, rather than advancing on a fixed
/// interval, keeps a morph from being cut short and popping to the next
/// shape.
Future<void> _morphThroughShapes() async {
while (mounted) {
setState(() => _tween = _tweens[_morphIndex]);
_controller.value = 0;
await _controller.animateWith(
_targetShape == MaterialShapes.heart
? _lessBouncySimulation
: _bouncySimulation,
);
_morphIndex = (_morphIndex + 1) % _tweens.length;
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Material 3 Expressive Shapes Sample')),
body: Center(
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 300, maxHeight: 300),
child: AspectRatio(
aspectRatio: 1,
child: AnimatedBuilder(
animation: _controller,
builder: (BuildContext context, Widget? child) {
return DecoratedBox(
decoration: ShapeDecoration(
color: Theme.of(context).colorScheme.primary,
shape: _tween.evaluate(_controller)!,
),
);
},
),
),
),
),
);
}
}
Properties
- hashCode → int
-
The hash code for this object.
no setterinherited
- runtimeType → Type
-
A representation of the runtime type of the object.
no setterinherited
Methods
-
noSuchMethod(
Invocation invocation) → dynamic -
Invoked when a nonexistent method or property is accessed.
inherited
-
toString(
) → String -
A string representation of this object.
inherited
Operators
-
operator ==(
Object other) → bool -
The equality operator.
inherited
Static Properties
-
all
→ List<
RoundedPolygon> -
A list of all available shapes.
final
- arch → RoundedPolygon
-
An arch shape.
final
- arrow → RoundedPolygon
-
An arrow shape.
final
- boom → RoundedPolygon
-
A boom shape.
final
- bun → RoundedPolygon
-
A bun shape.
final
- burst → RoundedPolygon
-
A burst shape.
final
- circle → RoundedPolygon
-
A circle shape.
final
- clamShell → RoundedPolygon
-
A clam-shell shape.
final
- clover4Leaf → RoundedPolygon
-
A 4-leaf clover shape.
final
- clover8Leaf → RoundedPolygon
-
An 8-leaf clover shape.
final
-
A 12-sided cookie shape.
final
-
A 4-sided cookie shape.
final
-
A 6-sided cookie shape.
final
-
A 7-sided cookie shape.
final
-
A 9-sided cookie shape.
final
- diamond → RoundedPolygon
-
A diamond shape.
final
- fan → RoundedPolygon
-
A fan shape.
final
- flower → RoundedPolygon
-
A flower shape.
final
- gem → RoundedPolygon
-
A gem shape.
final
- ghostish → RoundedPolygon
-
A ghostish shape.
final
- heart → RoundedPolygon
-
A heart shape.
final
- oval → RoundedPolygon
-
An oval shape.
final
- pentagon → RoundedPolygon
-
A pentagon shape.
final
- pill → RoundedPolygon
-
A pill shape.
final
- pixelCircle → RoundedPolygon
-
A pixel-circle shape.
final
- pixelTriangle → RoundedPolygon
-
A pixel-triangle shape.
final
- puffy → RoundedPolygon
-
A puffy shape.
final
- puffyDiamond → RoundedPolygon
-
A puffy-diamond shape.
final
- semiCircle → RoundedPolygon
-
A semi-circle shape.
final
- slanted → RoundedPolygon
-
A slanted square shape.
final
- softBoom → RoundedPolygon
-
A soft-boom shape.
final
- softBurst → RoundedPolygon
-
A soft-burst shape.
final
- square → RoundedPolygon
-
A square shape.
final
- sunny → RoundedPolygon
-
A sunny shape.
final
- triangle → RoundedPolygon
-
A triangle shape.
final
- verySunny → RoundedPolygon
-
A very-sunny shape.
final