Flutter Squricle Study
A study and comparison of different Squircle ShapeBorder options in Flutter, using a Flutter app to compare available Squircle shapes visually.
Overview
There currently is no known rounded rectangle in Flutter that would be verified to be an exact match for the rounded rectangle shape created e.g. in Swift-UI with RoundedRectangle(cornerRadius: myRadius, style: .continuous)
that would also be without issues in Flutter. This type of rounded rectangle with a continuous curvature is also known as a super ellipses shape or squircle.
In this study, a package called figma_squircle
is used as reference. This package is used and regarded by many as the best Flutter approximation of the iOS Squircle shape. To verify this, it should be compared with actual iOS SwiftUI produced shapes. As a starting point, it is used for comparisons and for findings presented in this study.
With the Flutter squircle_study app in this repo used for this study, you can cross compare any two selected shapes at different sizes and curvature.
In the Flutter GitHub repo, the issue #91523 is used to track the implementation of an iOS matching continuously rounded rectangle.
Summary of Findings
The ContinuousRectangleBorder
in Flutter SDK is a super ellipses shape, but it is not a match for the one used in iOS UI elements.
The package figma_squircle
is an implementation of the squircle used in Figma. The Figma Squircle claims to be a match for the iOS shape when used with smoothing factor 0.6. It may be a good match when used border radius is lower than half of the shape’s stadium radius, this should still be verified. At a higher radius than 0.5x of the shape’s stadium radius, the shape starts to approach a standard circular border curvature. At stadium radius, it is identical to a circular stadium shape. Which is not a continuously rounded stadium shape. The shape also breaks down at border radius higher than the shape’s stadium radius.
There is a less known package called smooth_corner
, that produces identical shapes to figma_squircle
. It does not break down at border radius higher than the shape’s stadium radius.
The performance impact of using any other shape than RoundedRectangleBorder has been mentioned, at least Tweet comments. They typically mention the FigmaSquircle, even for just the SDK ContinuousRectangleBorder, but even more so for the figma_squircle
. The performance impact of the shapes should be studied further. See Appendix A, at the end of the study report for more info.
All studied shapes do not have an outline border option. Some may not implement linear interpolation correctly, and probably none of them implement shape transform from one ShapeBorder
to another Flutter SDK ShapeBorder
, like most Flutter SDK ShapeBorder
s do. A proper Flutter iOS squircle shape should do all of these things correctly. The studied shapes that can draw an outline, all except SquircleBorder PR and SquircleStadiumBorder PR that never had any border option, seem to produce varying results concerning how thick the border visually appears to be at same thickness values. Might be an idea to look into why. The key part is of course that an official Squricle should use same principle as current Flutter OutlinedBorder
shapes.
TODOs
- Compare performance impact of the used and studied Squircle ShapeBorder‘s versus vanilla
RoundedRectangleBorder
andStadiumBorder
. - Compare the shapes that are claimed to be the best match to iOS Squircle below, to actual different Squircle shapes drawn by iOS Swift-UI.
Studied and Available Shapes
This demo allows you to visually compare the difference or similarity between different hyper ellipses, or so-called Squircle border rounding on rectangles.
The Shape options you can compare with this squircle_study app are:
- Circular aka RoundedRectangleBorder from: Flutter SDK
- ContinuousRectangleBorder from Flutter SDK
- ContinuousRectangleBorder x 2.3529 from Flutter SDK x factor
- SquircleBorder PR from Flutter rejected PR code
- FigmaSquircle from package figma_squircle
- SmoothCorner from package smooth_corner
- CupertinoSquircleBorder aka CupertinoCorners from package cupertino_rounded_corners
- SuperellipseShape from package superellipse_shape
- StadiumBorder from: Flutter SDK
- SquircleStadiumBorder PR from Flutter rejected PR
- SimonSquircleBorder from Slightfoot gist
- BeveledRectangleBorder from Flutter SDK
All are obviously not hyper ellipses or squircles, but included for comparison reasons.
Studied Squircle like Flutter ShapeBorder implementations
Below we take a closer look at them all, comparing them all to the FigmaSquircle from the package figma_squircle
.
Circular aka RoundedRectangleBorder
The standard circular rounded rectangle border shape with an outline, provided by Flutter SDK.
- Name: RoundedRectangleBorder
- From Flutter SDK
- Shape can break down: NO
Stays at circular stadium shape when radius exceeds its stadium radius.
Findings
The difference between Circular and FigmaSquircle is subtle, but still visible to a sharp and keen designer eye. At a border radius < 0.5 times (in the example 96 dp) of the stadium radius (stadium radius would be 200 in the example below), we can see a subtle but clear difference:
ShapeBorder RoundedRectangleBorder
It is more obvious when zoomed in:
ShapeBorder RoundedRectangleBorder, zoomed for a closer look
The difference between a standard circular border and the FigmaSquircle gets lower as the radius increases, and we get closer to the stadium radius.
ShapeBorder RoundedRectangleBorder at 0.75x of stadium radius
When zoomed, it is even more obvious that there is hardly any difference at 0.75 times what would be a stadium border.
ShapeBorder RoundedRectangleBorder at 0.75x of stadium radius, zoomed for a closer look
We will se this effect further when comparing with the circular StadiumBorder. It looks like the FigmaSquircle does not implement any continuous border effect the closer we get to the stadium radius, and none at all at stadium radius. It is unknown if this is correct behavior, compared to the desired actual iOS Squircle border, but it seems unlikely that it would be.
At a radius equal to or greater than the shape’s stadium radius, the RoundedRectangleBorder produces a StadiumBorder:
ShapeBorder RoundedRectangleBorder when radius equals stadium radius is the same as a StadiumBorder
Conclusion – Circular RoundedRectangleBorder
If FigmaSquircle at smoothing 0.6 is a correct representation of the iOS Swift-UI Squircle, then Circular RoundedRectangleBorder is NOT an acceptable compromise if high fidelity is desired at mid-border radius.
For low fidelity it may be acceptable, but keen eyes will feel that something is off.
We also have a first indication that maybe the FigmaSquircle is not a correct representation of the Swift-UI squircle at border radius approaching or equal to stadium radius, since it then becomes equal to a circular stadium border.
ContinuousRectangleBorder
The continuous rounded rectangle border shape is provided by Flutter SDK. It was supposed to bring the iOS squircle border to Flutter, but the implementation is very far from it.
- Name: ContinuousRectangleBorder
- From Flutter SDK
- Shape can break down: YES
The source code mentions limit checks to prevent the
ContinuousRectangleBorder
to get what it calls a “TIE-fighter” shape. In this demo, we can still observe the TIE-fighter shape at higher border radius. The attempt to prevent this shape is thus not completely successful. TODO(rydmike): Consider raising an issue about it.
- Other issues
It does not come with a Stadium border option.
Findings
The difference between ContinuousRectangleBorder and FigmaSquircle is very significant:
ShapeBorder ContinuousRectangleBorder
At high border radius, shown below, the ContinuousRectangleBorder creates a TIE-fighter shape. This is not desirable.
ShapeBorder ContinuousRectangleBorder getting TIE-fighter shape
Conclusion – ContinuousRectangleBorder
If FigmaSquircle at smoothing 0.6 is a correct representation of the iOS Swift-UI Squircle, then ContinuousRectangleBorder is NOT at all an acceptable option.
The performance impact of the ContinuousRectangleBorder over RoundedRectangleBorder has also been mentioned as an issue. Performance impacts when using anything else than RoundedRectangleBorder should be studied further.
ContinuousRectangleBorder x 2.3529
A Flutter continuous rounded rectangle border shape using radius multiplied with 2.3529. It is mentioned in a Flutter issue that a ContinuousRectangleBorder
that has its border radius multiplied with 2.3529 becomes close to an iOS squircle.
The mentioned claim of fit with iOS border is in issue 91523 where it is said “Currently,
ContinuousRectangleBorder
requires aborderRadius
of ~24 to resemble theRoundedRectangle
with acornerRadius
of ~10.2″. So basically 24/10.2 = 2.3529, as used here, should be a match.
- Name: ContinuousRectangleBorder x 2.3529
- From Flutter SDK x factor
- Shape can break down: YES
The TIE fighter shape issue applies here too. It occurs earlier since the radius is multiplied by 2.3529.
Findings
The difference between ContinuousRectangleBorder x 2.3529 and FigmaSquircle is clear, but not so significant at border radius < 0.5 stadium border.
ShapeBorder ContinuousRectangleBorder x 2.3529 vs. FigmaSquircle at smoothing 0.6
Especially not if we change the smoothness of the FigmaSquircle from 0.6 to maximum 1.0. As shown below, it then becomes an almost perfect match:
ShapeBorder ContinuousRectangleBorder x 2.3529 vs. FigmaSquircle at smoothing 1.0
At higher border radius, e.g. at 0.75x of stadium radius, the gap in visuals becomes more significant and the smoothing factor on FigmaSquircle does not really matter anymore:
ShapeBorder ContinuousRectangleBorder x 2.3529, at 0.75x of its stadium border radius
At this border radius, it might also be the FigmaSquircle that is the poorer squircle shape.
The TIE fighter effect when using ContinuousRectangleBorder x 2.3529 starts already at 0.6 times the stadium radius.
Conclusion – ContinuousRectangleBorder x 2.3529
If FigmaSquircle at smoothing 0.6 is a correct representation of the iOS Swift-UI Squircle, then ContinuousRectangleBorder x 2.3529 is NOT at an exact match for it, but it is not a bad Squircle shape.
At border radius of < 0.5 times the stadium radius, and using smoothness 1.0 for the FigmaSquircle, the ContinuousRectangleBorder x 2.3529 is for practical visual comparisons a good fit.
SquircleBorder PR
A PR for a Squircle that was rejected in Flutter SDK. It was discussed here flutter/flutter#27523. This is a RydMike code revival of the PR with some minor mods.
- Name: SquircleBorder PR
- From Flutter rejected PR code
- Shape can break down: YES
The
SquircleBorder
border has poor behavior with higher border radius, it cannot become a stadium, it stops changing shape at higher relative border radius.
- Other issues
The implementation is not an
OutlinedBorder
, so it has no outline capability. This needs to be added.
Findings
The difference between SquircleBorder PR and FigmaSquircle is none existing at border radius < 0.49 of the stadium radius, when using FigmaSquircle with smoothness 0.6.
ShapeBorder SquircleBorder PR at radius < 0.5x of its stadium radius
The SquircleBorder PR stops responding to border radius increases when the radius is >= 0.5x the stadium radius and can not be used for Squircle shapes where the radius is from 0.5x to 1x of the stadium radius. Up and until that radius, it works very well and matches the FigmaSquircle.
On the other hand, it has also been shown that for a radius range that exceeded 0.5x stadium radius, that the FigmaSquircle gets closer and closer to the plain circular border represented by the RoundedRectangleBorder.
ShapeBorder SquircleBorder PR at radius < 0.75x of its stadium radius
It could also be argued that the SquircleBorder PR refrains from drawing shapes for a radius for which it no longer produces a correct squircle result. Whereas, the FigmaSquircle then instead approaches a vanilla circular border, as the stadium radius is approached.
Conclusion – SquircleBorder PR
If FigmaSquircle at smoothing 0.6 is a correct representation of the iOS Swift-UI Squircle, then SquircleBorder PR is an acceptable option at lower radius than 0.5x Stadium radius. At higher border radius it visually stops changing it radius, since it cannot draw a squircle shape any higher radius than that.
FigmaSquircle
A Flutter package implementation of Figma corner smoothing.
This package is used and regarded by many as one of the best approximations of the iOS squircle shape. It is an implementation of the FigmaSquircle shape. It has a smoothness factor from 0.0 to 1.0, at value 0.6 the Figma shape claims to be identical to the iOS squircle shape.
At same smoothness, this figma_squircle
package should also then be identical to the iOS squircle. To verify this, it should be compared to actual iOS SwiftUI produced shapes.
In this study, we use it as a reference to show how others deviate from it.
- Name: FigmaSquircle
- From package figma_squircle
- Shape can break down: YES
The shape breaks down with border radius exceeding the shape stadium radius.
Findings
The FigmaSquircle breaks down when set border radius exceeds its Stadium radius.
ShapeBorder FigmaSquircle (SmoothRectangleBorder) at radius > than its stadium radius, shape breaks down
For border radius > 0.5x and <= 1.0x of the shape’s stadium radius, the FigmaSquircle gets closer to an ordinary circular rounded rectangle border. At a border radius of > 0.9x and <= 1.0x of the shape’s stadium radius, we can no longer observe any practical difference from a normal circular border made with RoundedRectangleBorder:
ShapeBorder FigmaSquircle (SmoothRectangleBorder) at radius 0.9x of its stadium radius, pretty identical to circular RoundedRectangleBorder
Conclusion – FigmaSquircle
If FigmaSquircle at smoothing 0.6 is a correct representation of the iOS Swift-UI Squircle, then this is a good choice for fidelity with iOS shapes.
However, FigmaSquircle shape breaks down when the radius exceeds the shape’s stadium radius. A good shape algorithm should stay at its equivalent stadium shaped when the stadium radius is exceeded.
It has also been observed that for border radius of > 0.5x and <= 1.0x of the shape’s stadium radius, that the FigmaSquircle shape starts to take the shape of just an ordinary circular rounded rectangle border. It is at this stage unknown if this is correct compared to how actual iOS stadium shapes look. Based on a quick look, it probably is not. This needs to be verified.
The performance impact of the FigmaSquircle has also been mentioned in issues. It should be studied further.
SmoothCorner
A rectangular border with variable smoothness imitated from Figma.
This is another implementation of the Figma squircle. It appears to be shape wise identical to above FigmaSquircle.
- Name: SmoothCorner
- From package smooth_corner
- Shape can break down: NO
Stays correctly shaped when border radius exceeds its stadium radius.
Findings
The difference between SmoothCorner and FigmaSquircle appears to be negligible. Visually, the results appear to be identical when using the same smoothness factor. SmoothCorner also supports the smoothness factor that FigmaSquircle has.
ShapeBorder SmoothCorner and FigmaSquircle are visually identical
The SmoothCorner does not break down when border radius exceeds the shape Stadium radius.
ShapeBorder SmoothCorner does not break down like FigmaSquircle at radius > stadium radius
Conclusion – SmoothCorner
If FigmaSquircle at smoothing 0.6 is a correct representation of the iOS Swift-UI Squircle, then SmoothCorner is correct as well. Since they are identical, SmoothCorner has the same questionable stadium shape as FigmaSquircle.
SmoothCorner has one advantage over FigmaSquircle and that is that shape does not break down when the radius exceeds the shape’s stadium radius. This is a nice and desired feature and matches how RoundedRectangleBorder behaves in relations to its StadiumBorder shape, it stays at stadium shape when the stadium radius is exceeded.
The performance of SmoothCorner has no known feedback, since it is not used as much as the FigmaSquircle. Its performance impact should be studied as well.
CupertinoSquircleBorder aka CupertinoCorners
A widget and border used to make cupertino rounded corners also referred to as squircle, using a bezier path and having the two points in the corners.
- Name: CupertinoSquircleBorder
- From package cupertino_rounded_corners
Findings
The CupertinoCorners appears to be visually pretty identical to ContinuousRectangleBorder.
ShapeBorder CupertinoCorners and ContinuousRectangleBorder are visually identical
It has the same TIE-fighter issue too:
ShapeBorder CupertinoCorners has the same TIE-fighter shape breakdown as ContinuousRectangleBorder
At a border radius larger than the shortest side, the TIE-fighter shapes do diverge. The ContinuousRectangleBorder stops taking on increased TIE-fighter shape, but with the CupertinoCorners it becomes even more pronounced and doubled:
ShapeBorder CupertinoCorners TIE-fighter shape gets more aggressive than ContinuousRectangleBorder
Conclusion – CupertinoCorners
There is no reason to use CupertinoCorners over the ContinuousRectangleBorder that exists in the Flutter SDK. It is also as a poor match for the FigmaSquircle as the ContinuousRectangleBorder.
SuperEllipse
The SuperEllipse is a package for creating superellipse shapes in flutter. A superellipse is a shape constituting a transition between a rectangle and a circle.
- Name: SuperellipseShape
- From package superellipse_shape
Findings
The SuperEllipse appears to be visually pretty identical to ContinuousRectangleBorder.
ShapeBorder SuperEllipse and ContinuousRectangleBorder are visually identical
It has the same TIE-fighter issue too, but unlike CupertinoCorners it is identical to ContinuousRectangleBorder at any given border radius, also very high ones.
ShapeBorder CupertinoSuperEllipse has the same TIE-fighter shape breakdown as ContinuousRectangleBorder
Conclusion – SuperEllipse
There is no reason to use SuperEllipse over the ContinuousRectangleBorder that exists in the Flutter SDK. It is also as a poor match for the FigmaSquircle as the ContinuousRectangleBorder.
StadiumBorder
The Flutter standard circular stadium border. It fits a stadium-shaped border, a box with semicircles on the ends, within the rectangle of the widget it is applied to.
- Name: StadiumBorder
- From Flutter SDK
- Shape can break down: NO
Findings
There is NO visible difference between a FigmaSquircle and the standard Flutter SDK circular StadiumBorder when using a border radius that equals the shape’s stadium radius.
ShapeBorder StadiumBorder and FigmaSquircle are visually identical
The smoothness factor also has no impact on the FigmaSquircle when the border radius equals the stadium radius.
ShapeBorder StadiumBorder and FigmaSquircle are visually identical, also when taking a closer zoomed in look
Conclusion – StadiumBorder
There is no point in using the FigmaSquircle for a stadium shape, it is identical to StadiumBorder at any radius that equals the shapes’ stadium radius. Already at a radius about 0.6x of the stadium radius, we are beginning to look at negligible visual differences between FigmaSquircle and circular RoundedRectangleBorder.
SquircleStadiumBorder PR
A PR for a Stadium Squircle that was rejected in Flutter SDK. It was discussed here flutter/flutter#27523. This is a RydMike code revival of the PR with some mods.
-
Name: SquircleStadiumBorder
-
From Flutter rejected PR
-
Shape can break down: YES
The shape shrinks its height when width approaches height, and wise versa. This is NOT a desired behavior.
- Other issues
The implementation is not an
OutlinedBorder
, so it has no outline capability. This needs to be added.
Findings
The SquircleStadiumBorder PR looks better than FigmaSquircle:
ShapeBorder SquircleStadiumBorder is a nice looking stadium Squircle than FigmaSquircle
There is a clear difference between SquircleStadiumBorder PR and FigmaSquircle when zoomed:
ShapeBorder SquircleStadiumBorder and FigmaSquircle zoomed in for a closer look
The FigmaSquircle at stadium border is just equal to StadiumBorder. Comparing SquircleStadiumBorder PR to a StadiumBorder is thus the same as comparing it to FigmaSquircle:
ShapeBorder SquircleStadiumBorder vs StadiumBorder is same as comparing to FigmaSquircle
The SquircleStadiumBorder behaves differently for the StadiumBorder when the longer side approaches the same width as the shorter side. The width shrinks, before the shortest and longest sides change, and thus on which edges the stadium curve is drawn on, is swapped. This behavior is not desired, it should behave as the StadiumBorder does.
ShapeBorder SquircleStadiumBorder vs StadiumBorder when edge length changes
Conclusion – SquircleStadiumBorder PR
The SquircleStadiumBorder PR appears to be the only stadium shape that has a nice looking squircle shape. It may be more correct for an iOS stadium squircle shape, than the FigmaSquircle. This is based on that the FigmaSquircle is just identical to a normal circular stadium border, which an iOS squircle stadium shape may not be.
SimonSquircle
A squircle implementation by Simon Lightfoot provided in a Gist.
- Name: SimonSquircleBorder
- From Slightfoot gist
- Shape can break down: YES
The shape cannot handle border radius from 0 to less than 1.0, it draws very odd shapes then.
Findings
Draws weird shapes for border radius from 0 to less than 1. The shape is not an iOS squircle, it is something entirely different. Examples of produced shapes at different border radius are shown below.
ShapeBorder SimonSquircle at border radius 0.57
ShapeBorder SimonSquircle at border radius 1.36
ShapeBorder SimonSquircle at border radius 2.62
ShapeBorder SimonSquircle at border radius 26
ShapeBorder SimonSquircle at border radius 80
ShapeBorder SimonSquircle at border radius 133
Conclusion – SimonSquircle
Do not use this shape for iOS squircle shapes, it is not a match.
Beveled
A rectangular border with flattened or “beveled” corners.
- Name: BeveledRectangleBorder
- From Flutter SDK
For obvious reasons, this shape is not compared. It is only included in the study app to show an alternative corner shape that exists, but is rarely used in the Flutter SDK.
Appendix A – Tweets About Performance Issues
Some links to Tweets about performance issues when using Figma Squircle and ContinuousRectangleBorder.
Figma Squircle
- https://twitter.com/lets4r/status/1630843536739295232?s=20
- https://twitter.com/lets4r/status/1668240937225539586?s=20
Continuous Rectangle Border
- https://twitter.com/andrewpmoore/status/1668223930878836738?s=20
- https://twitter.com/andrewpmoore/status/1668243655314882567?s=20
- https://twitter.com/RydMike/status/1668275006919278592?s=20 Contains a performance comparison recording and link to repo used for it.