Greetings everyone. Since the last time I wrote “Create morphable shapes in Flutter”, a lot of effort has been devoted to updating the Shape design for that package. Today I am excited to tell you that every shape in the morphable_shape package is now responsive, just like what CSS shapes do but even more.
To create a responsive shape, we need to introduce a length class similar to what CSS has (check out the length_unit package). Now you can create a responsive rounded rectangle by writing:
bottomRight: DynamicRadius.elliptical(60.0.toPXLength, 10.0.toPercentLength))
which will give you a rectangle with a 60 px circular radius at the top left corner and a (60 px, 10%) elliptical corner at the bottom right. Just remember to add Dynamic in front of the BorderRadius and Radius class. To use the shape, plug it into the MorphableShapeBorder class (which allows you to set the border color and width) which can be used by the Material widget or the ShapeBorderClipper widget.
What shapes are supported at the moment?
The most powerful and commonly used one should be the RectangleShape class. It allows to you configure each corner of the rectangle individually or at once. If two radii overlap at one of the sides of the rectangle (like 60% and 50%), it automatically scales both sides so that they don’t overlap (just like what CSS does). But the RenctangleShape also supports other corner styles:
You can make a triangle, a diamond, a trapezoid, or even an arrow shape by just using the RectangleShape class and providing the right corner style and radius.
There’s also the CircleShape which allows you to choose the start angle and sweep angle:
The PolygonShape which supports changing the number of sides as well as corner radius and corner style:
The StarShape allows you to change the number of corners, the inset, the border radius, the border style, the inset radius, and the inset style.
There is also the ArrowShape, the TrapezoidShape, and the TriangleShape class to help you quickly generate those shapes.
For those of you who want more customization, there is also the PathShape class which accepts a DynamicPath instance to create freeform shapes. A DynamicPath is a path consisting of straight or cubic Bezier lines. All the previous Shape classes can be converted into a PathShape. I am also considering supporting SVG in the future.
What are all these small squares in your pictures?
Glad you asked. In order to let you get familiar with the package quickly and design your custom shapes, I have created this online shape editing tool at fluttershape.com. These rectangles in previous pictures are control points that let you edit the shape you are currently working with. The tool supports all the features in the morphable_shape package, is fully responsive, and lets you export your designed shape into the JSON format. By the way, all the Shape classes can be serialized and deserialized. So you can just use the JSON from the editing tool and recreate your shape anywhere (I am considering exporting to code as well). The tool is actually built from the example app in the package so you can compile it yourself and run it on other platforms as well (all flutter supported platforms should be fine).
Why is the package call morphable_shape then?
To answer this question, I would like first to talk about the built-in shapes that flutter provides: RoundedRectangle, Circle, and BeveledRectangle (actually they are called RoundedRectangleBorder, etc which is basically the shape plus the border style like the color and width). One of the crucial benefits of those built-in shapes is the ability to animate themselves. A RoundedRectangle can smoothly morph into another RoundedRectangle with different border radii or even a CircleBorder. The disadvantage of those built-in shapes is that: 1. They are not responsive. So you have to calculate the border radii you want manually. 2. A RoundedRectangle/Circle can not morph into a BeveledRectangle or vice versa. If you were to implement a new shape, you need to find out how to morph the new shape into other existing shapes or just have to disallow it.
This is not the case for morphable_shape. Every shape in the morphable_shape package can smoothly morph into each other. In my last article “Create morphable shapes in Flutter”, I discussed how I achieved this by traversing the shape border using the PathMetric class and morph the shapes using many many control points. This algorithm works but is time-consuming (lags heavily on the web) and inaccurate for complex shapes (you can increase the accuracy but that makes the lagging even worse). I have completely rewrite the morphing algorithm and fixed those two issues. That rewrite is not 100% finished and deserves a new article to talk about so stay tuned. But if you want to preview it, you can click the eye icon on the top left corner of the editing tool which will show a shape morphing animation between the shape you created and another predefined shape.
In conclusion, I have created a shape package that:
- is fully responsive like the CSS shape.
- supports lots of shapes (similar to a typical vector design tool).
- can morph between each other like the Flutter built-in shapes.
- can be serialized/deserialized.
- has a built-in online editing tool for you to work with.
I think this package is of great potential and encourage you to give it a try. If you find any bug or would like to ask for some new feature, please submit an issue on the GitHub repository (this has been a one-person project and I am also busy with my Ph.D. program in Physics, so I can not guarantee a swift response...).
That’s it for today. Go to fluttershape.com and try the package out!