Flutter UI Challenge: Animating shapes and their position in Flutter: Part 2

Toseef Ali Khan
4 min readJun 10, 2024

--

Let’s continue where we left off.

Similar to the circular figure, other figures can be created. A complete list of figure configurations can be found in the initializeShapes method.

Shape configurations
Shape Configurations

Feel free to experiment with the configurations to make new figures!

Part 2: Painting and animating the shapes 🎨

You can refer to this page for the detailed code.

Primarily, we need to select one figure from our 6 configs which we’ll update periodically:

List<FigureConfiguration> figures = [];
FigureConfiguration? config;
late Timer _timer;

@override
void initState() {
startTimer();

WidgetsBinding.instance.addPostFrameCallback((_) {
initShapes();
config = figures[0];
setState(() {});
});

super.initState();
}

void startTimer() {
_timer = Timer.periodic(const Duration(seconds: 2), (timer) {
int randomIndex = Random().nextInt(figures.length);
config = figures[randomIndex];
setState(() {});
});
}

To ensure that we access MediaQuery only after the widget tree is built, we use addPostFrameCallback. This ensures that the callback is executed after the first frame is rendered, allowing us to safely access MediaQuery.

Let’s build our Stack of shapes now!

Stack(
children: [
_buildShape(config!.shape1, Projects.parallax,
initialColor: Colors.white),
_buildShape(config!.shape2, Projects.ecoShift,
initialColor: Colors.white),
_buildShape(config!.shape3, Projects.zeeve),
_buildShape(config!.shape4, Projects.about),
_buildShape(config!.shape5, Projects.dcomm),
_buildShape(config!.shape6, Projects.legacy),
_buildShape(config!.shape7, Projects.phaeton),
],
),

Projects is an enum of my personal projects. I’m using it to associate one project with each shape. Thus, there is a one-to-one relationship between shape->its color->associated project.

Coming to the most interesting part now: the animations! I have used implicit animations so that Flutter does the calculations related to the animation for us!

Implicit Animations
Widget _buildShape(ShapeConfiguration shape, Projects section,
{Color initialColor = Colors.black}) {
final Color color = getColorFromSection(section);
return AnimatedPositioned(
duration: const Duration(milliseconds: 600),
top: shape.top,
left: shape.left,
curve: Curves.ease,
child: Hero(
tag: color.toString(),
child: Material(
type: MaterialType.transparency,
child: AnimatedContainer(
duration: const Duration(milliseconds: 600),
width: shape.width,
height: shape.height,
curve: Curves.ease,
decoration: ShapeDecoration(color: color, shape: shape.shape),
child: GestureDetector(
onTap: () => animateToProjectDetailPage(
section, color, initialColor, shape.shape),
child: ClipPath(
clipper: ShapeBorderClipper(shape: shape.shape),
child: HoverText(
visibleText: section.name.toUpperCase(),
textColor: initialColor)),
),
),
),
),
);
}

Let me break it down for you:

Jokes aside, here’s the explanation:

getColorFromSection: Each project has a unique color.

AnimatedPositioned: To animate the position of our shapes. This is where the top and left properties from the ShapeConfiguration help.

Hero: To fling the shape when new screen is pushed. Will be covered in the next part.

AnimatedContainer: is the one doing the heavy lifting. It defines the shape, width and height of our shape.

Whenever the figure config changes because of the timer, AnimatedContainer and AnimatedPositioned seamlessly animate the position, shape and size of our figure. This is where you appreciate the beauty of Flutter and its widgets 💙

But how did we achieve the text preview when hovering over a shape?

Text preview on hover

Answer: AnimatedSwitcher

AnimatedSwitcher(
duration: const Duration(milliseconds: 300),
child: _isHovered
? Text(
widget.visibleText,
style: TextStyle(
fontWeight: FontWeight.bold,
color: widget.textColor,
fontSize: MediaQuery.of(context).size.shortestSide,
height: 0.8),
textAlign: TextAlign.left,
)
: const SizedBox.shrink(),
),

We use a MouseRegion to detect if the shape is hovered. AnimatedSwitcher takes care of the fade in/out animations for us. This code is part of the HoverText widget.

There’s one thing left: how does the animateToProjectDetailPage method work? How do we animate the navigation to the project detail page?

Navigating to the project detail page

This part is a bit complex and involves multiple steps to achieve the desired effect. Therefore, I’ll cover that in the next part!

Thanks for making it this far! Your support means everything 😄💙

Make sure to star the repo 🌟

--

--

Toseef Ali Khan

Flutter Developer | Winner at Global Gamers Challenge by Flutter | Creating Innovative Solutions at Zeeve 🚀