HomeAndroidThe Form of Issues to Come. Creating and animating rounded shapes… |...

The Form of Issues to Come. Creating and animating rounded shapes… | by Chet Haase | Android Builders | Apr, 2023


Creating and animating rounded shapes with AndroidX, Half I

A brand new library with the flashy identify :graphics:graphics-shapes: launched lately in AndroidX. I’m glad (particularly after many months of engaged on it with my colleague Sergio Sancho from the Android Put on staff) that this challenge and API is lastly on the market. However I believed it is perhaps useful to explain what it’s and easy methods to really use it.

There are two main elements to the library, which internally we name Shapes and Morph. For the good thing about short-attentions-span Medium readership, I’ll due to this fact break the outline of the library down into two articles alongside related traces. This primary one will cowl the Shapes portion of the library, which permits simple creation and rendering of rounded polygonal shapes. Tune in subsequent time to learn to animate (a.okay.a, “Morph”) these shapes.

Android gives a really versatile drawing API. In a customized View, you may override onDraw() and use the Canvas parameter to attract something from traces to circles to rectangles, to complicated Path objects. And if you would like one thing rounded, you may create and draw any form you need… as lengthy you need a RoundRect.

In fact, you may all the time (should you’re up for the hassle) create a really complicated form (full with arbitrary rounding) with the Path API. However out of the field, we provide you with solely Canvas.drawRoundRect(). Furthermore, Android gives little or no flexibility when it comes to how these rects are rounded. That’s, every of the corners of the rectangles are rounded with a round curve… interval. So if you would like one thing extra customized (both within the form of the rounded corners or the variety of vertices), you might be by yourself.

Till now.

We thought it could be helpful to supply easy creation of every kind of rounded shapes. I imply, rectangles are cool and all. And so are these round corners, proper? They’re so… round! However generally you need just a bit extra. And even much more.

We additionally needed these shapes to be obtainable not only for apps working on future platform variations, but in addition throughout a lot older releases, for the enjoyment of all builders and customers. So we created an API to do exactly that, by utilizing Path objects internally. Path has been obtainable since 1.0 and thus gives compatibility again so far as AndroidX itself goes.

The API for creating and drawing these shapes is easy (we saved all of the sophisticated bits for the interior code which creates them). There are only a couple of various items to know: making a polygonal form and specifying non-obligatory rounding parameters for the form’s corners. I’ll cowl these under.

Q: What’s a Polygon?

A: There are such a lot of sides to that query…

It’s price speaking slightly bit first about what we imply by “polygon.” Particularly, it’s price explaining what we imply once we use of the time period, to point out how we get to the way more complicated (and attention-grabbing) shapes enabled by this library.

Wikipedia defines Polygon thusly:

In geometry, a polygon (/ˈpɒlɪɡɒn/) is a aircraft determine made up of line segments linked to type a closed polygonal chain.

which I discover… not terribly useful. I feel mathematicians get pleasure from math a lot that even once they’re writing phrases, it nonetheless seems like equations. Let’s simplify this definition for the non mathematicians within the viewers.

In its most elementary type, a polygon is a 2D form with edges and vertices (or “corners”). I normally consider polygons as having vertices which can be ordered round some middle, with all edges having the identical size. Polygons may be way more complicated than that, nevertheless, together with shapes that may be self-intersecting.

Our library’s polygons are, nevertheless, a bit extra staid and boring, with vertices which can be positioned equidistant from some middle, marching round so as. All sides are of equal size and there are not any funky self-intersections. (This constraint finally ends up being essential in with the ability to deal with automated morphing between our shapes with cheap outcomes). You’ll be able to consider the bottom RoundedPolygon object (which we’ll see in additional element under) as being a form that has a focus on which all of its vertices are positioned at some given radius away from that middle.

Our polygons could be a bit extra complicated as nicely. For one factor, the library has the idea of a “star polygon.” Star polygons are much like polygons, besides they’ve each an inside and outer radius, with vertices mendacity on one or the opposite, taking turns because the define proceeds across the middle.

Lastly, our polygons have the idea of “rounding.” Rounding shouldn’t be strictly a polygonal idea, since mathematical polygons are outlined to have straight edges and sharp corners. So we name our shapes “Rounded Polygons,” as a mix of the final ideas of polygons with the extra nuance of optionally rounded corners. Rounded polygons have an identical geometry because the shapes above, besides that every vertex has non-obligatory parameters which describe easy methods to spherical its nook. For instance, here’s a 5-sided star polygon, just like the one above, however with rounding specified for corners fashioned by the vertices on its outer radius.

These, then, are the kinds of shapes that this library will produce: polygonal (ish) non-self-intersecting shapes the place the vertices are ordered and equidistant from a radius (or two), with optionally rounded corners.

Now let’s have a look at easy methods to use the library’s API to create these shapes.

Be aware: This text is present as of the alpha02 launch. There’ll in all probability be minor API modifications throughout the alpha section; I’ll replace the article when the API modifications, and can replace this launch observe accordingly.

The primary class used to create a form is RoundedPolygon. There are various completely different shapes you may create with this API, however all of them boil right down to polygonal variations.

The way in which that you just create a easy, unrounded*RoundedPolygon is by telling the API what number of vertices you need and optionally offering a radius and middle. In fact, any form will have a radius and middle, however by default the library creates canonical shapes with a radius of 1 round a middle at (0, 0). Be aware you could remodel (scale, translate, rotate) the canonical form to get it to the dimensions and placement you need by calling RoundedPolygon.remodel(Matrix).

* At this level, you is perhaps questioning why we’ve an API named “Rounded” which lets you create an unrounded factor. The unique model of the API dealt with that semantic distinction, with a Polygon superclass and a RoundedPolygon subclass. However in the long run, it was all a bit tutorial to separate this performance primarily based on the which means of the phrase “polygon,” so we went with a single class as a substitute which handles all potentialities.
API naming is difficult, imperfect, and a perpetual supply of remorse.

The best use of the API entails passing within the variety of vertices and letting the library do its factor. You’ll be able to then name the remodel() operate to resize and place the article and eventually draw it into your customized view with an extension technique offered by the library.

Right here’s an instance which creates a five-sided determine with a radius of 200 and attracts it with a given Canvas and Paint object (created elsewhere):

val pentagon = RoundedPolygon(5, 200f)
canvas.drawPolygon(pentagon, paint)

Star polygons (mentioned earlier) are almost as easy; the one further factor wanted is a second radius, which is offered through the innerRadius parameter within the Star() operate. This inside radius is a worth starting from 0 to the worth of radius (which is the “outer” radius for the form).

For instance, to create a five-sided star polygon with a radius of 100 and an inside radius midway between the outer radius and the middle, you’ll do that:

val pentagonalStar = Star(5, 100f, 50f)

So all of that is good. We’ve offered a easy API to create and draw common and star polygons. However these will not be the laborious elements on this drawback house; it’s not too tough to create straight-edged, sharp-corner shapes like these with the present APIs. The attention-grabbing (and tough) half is easy methods to spherical these corners.

Figuring this out meant (in my case) re-learning a bunch of high-school stage geometry and trigonometry (hey, it had been… a lengthy time since I had these lessons). Factor like trig identities, the Legislation of Cosines, and helpful geometry information just like the angles of a triangle including as much as 180 levels all got here into play. Perhaps I’ll write up that stuff someday (or you may simply have a look at the code and see the place it ended up).

However the important thing half (for customers of the library) is: how do you utilize the API to get good, rounded shapes? Happily, the API (like so many APIs) is way easier than the implementation. Making a polygon, or star polygon, with rounded corners is nothing greater than creating these shapes with the APIs described above, with further details about how the corners needs to be rounded.

To perform this process, use the categoryCornerRounding which is accountable for figuring out how the corners needs to be rounded. It takes two parameters: radius and smoothing.

Rounding Radius

radius is the radius of the circle used to spherical a vertex. That is much like the radius parameters equipped to the present drawRoundRect technique of Canvas, besides it really works in live performance with the non-obligatory smoothing parameter (see under). For instance, we will create this rounded triangle:

the place the rounding radius r for every of the corners may be pictured geometrically as follows:

Be aware {that a} rounding radius produces a purely round curve on the nook, between the 2 straight edges that meet on the vertex.

Easy Strikes

“Smoothing,” in contrast to the nook rounding radius, is a brand new idea in our APIs. You’ll be able to consider smoothing as an element which determines how lengthy it takes to get from the round rounding portion of the nook to the sting. A smoothing issue of 0 (unsmoothed, the default worth for CornerRounding) leads to purely round nook rounding (if a nonzero radius is specified, as above). A nonzero smoothing issue (as much as the max of 1.0) leads to the nook being rounded by three separate curves. The middle curve is identical round arc produced by the rounding radius, defined above. However as a substitute of that curve coming all the way in which to the polygon edges, there at the moment are two “flanking” curves, which transition from the inside round curve to the outer edges in easy (non-circular) arcs of their very own.

The magnitude of the smoothing curve determines each the size of the inside round curve (extra smoothing == smaller round curve) and the size of the flanking curves (extra smoothing == bigger flanking curves). The flanking curves have an effect on not solely how a lot of the rounding occurs on a round path, but in addition the gap of the general rounding curve. A bigger smoothing issue pushes the intersection level of the rounding curve additional alongside the sting towards the following vertex. A price of 1 (the max) leads to no inside curve in any respect (the round portion has size zero) and the utmost size of the flanking curves (which might lengthen so far as the following vertex, relying on the rounding parameters of that vertex).

For example the influence of smoothing, it’s useful to take a look at a diagram displaying the underlying curves. Be aware that each one polygons are represented internally by an inventory of Bézier cubic curves, that are every outlined by pairs of anchor and management factors. These cubic curves are then used internally to create the Path objects accountable for drawing the shapes into the customized view.

Be aware: Describing cubic curves is past the scope of this already lengthy article, however fortuitously there’s loads of info on the market about Bézier curves,** cubic curves, Paths, and extra. I invite you to do background studying there and elsewhere should you aren’t acquainted with any these ideas. However right here’s a quite simple description in case it helps: a cubic Bézier curve may be outlined by two anchor factors (one at every finish of the curve) and two management factors which decide the slope of the curve at these anchor factors.

** I’ve to offer a shout out to the that Bezier curve primer website linked right here; it’s an unlimited treasure trove of details about all issues Bézier, with proofs, equations, pattern code, diagrams, dwell embedded demos, and thorough explanations. I return to it usually to know extra on this complicated and attention-grabbing house.

Let’s have a look at some photos to see what’s occurring with the underlying curves. Within the diagram under, the nook of the form (the white object on the left) is represented on the correct by the inexperienced line (the define of the form) and the white dashed line (a circle with the given rounding radius). The cubic curve is represented by pink circles which can be anchor factors, yellow circles which can be management factors for the curve, and yellow traces between the anchor and management factors. If you happen to’ve used drawing packages similar to Adobe Illustrator, and even Keynote, you could have seen related deal with visuals when drawing curves.

After we provide a non-zero smoothing issue, the rounded nook is created with three cubic curves: the round curve (which we noticed above within the unsmoothed case) plus two flanking curves which transition between the inside round curve and the perimeters. Be aware that the flanking curves begin additional again alongside the sting than within the unsmoothed case. The ensuing form is proven by the white object on the correct. The consequences of smoothing may be fairly delicate, however they permit way more flexibility for designers in producing smoothed shapes that transcend the normal circular-round shapes.

I ought to observe that though there are various separate segments which make up every rounded nook (two edges, two flanking curves, and one inside round curve), the end result could be very, er, easy as a result of every curve is calculated to match the slope on the level the place it joins the following phase. Thus, for instance, the rounded nook easily transitions from the inside round curve to the non-circular smoothing curve, after which once more to the straight edge.

In addition to the constructors coated above, which all take the variety of vertices, there’s additionally a extra basic constructor which takes an inventory of vertices:

    constructor(
vertices: Listing<PointF>,
rounding: CornerRounding = CornerRounding.Unrounded,
perVertexRounding: Listing<CornerRounding>? = null,
middle: PointF? = null
)

This constructor makes it attainable so that you can create shapes that… don’t work nicely with the remainder of our rounded-polygon assumptions. So don’t be shocked should you throw randomly complicated lists of vertices at it and the outcomes will not be as pleasing because the extra constrained polygons created by the opposite constructors.

This constructor exists to permit creation of extra attention-grabbing polygonal shapes whose vertices will not be all equidistant from some middle level. For instance, we will use the vertex-list constructor to create a triangle form the place the underside edge bows in.

This triangle-ish form is created with this code.

        val triangleInnerRadiusRatio = .1f
val trianglePoints = listOf(
radialToCartesian(1f, 270f.toRadians()),
radialToCartesian(1f, 30f.toRadians()),
radialToCartesian(triangleInnerRadiusRatio, 90f.toRadians()),
radialToCartesian(1f, 150f.toRadians()),
)
RoundedPolygon(trianglePoints, CornerRounding(.22f))

(Don’t fear concerning the radialToCartesian operate above — or test it out within the pattern challenge listed under in case you are curious. It’s only a operate that simplifies putting vertices round a middle level at particular angles).

I talked particularly a couple of single CornerRounding parameter above, however the API lets you specify a number of rounding parameters, together with one for the inside and outer radii to get an impact like this on star polygons.

You may as well, if you wish to take it that far, outline per-vertex rounding parameters, to get a really customized form certainly. For any of those conditions, the API lets you simply create and draw every kind of rounded (or unrounded) polygonal shapes. You can all the time do that on Android, in fact. In any case, we’re simply utilizing the presentPath API beneath to deal with the drawing. However there are a number of particulars (and a lot math!) to kind out alongside the way in which. This new library makes the job, we hope, far simpler.

One of many issues that drove the interior construction of cubic curves was the necessity to not simply create and draw these shapes, however to additionally animate easily and routinely between them. Keep tuned for the following article on form morphing to see how to try this with this library.

APIs!

The library is offered in alpha type on AndroidX:

Pattern code!

The form modifying animation within the header was created with a pattern app which demonstrates form creation, modifying, and morphing. It’s hosted on GitHub:

The pattern has each Compose and View apps, displaying easy methods to use the library to create and morph shapes in each sorts of UI toolkits. The Compose model has a further editor view that helps visualize the varied form parameters.

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments