aster.cloud aster.cloud
  • /
  • Platforms
    • Public Cloud
    • On-Premise
    • Hybrid Cloud
    • Data
  • Architecture
    • Design
    • Solutions
    • Enterprise
  • Engineering
    • Automation
    • Software Engineering
    • Project Management
    • DevOps
  • Programming
    • Learning
  • Tools
  • About
  • /
  • Platforms
    • Public Cloud
    • On-Premise
    • Hybrid Cloud
    • Data
  • Architecture
    • Design
    • Solutions
    • Enterprise
  • Engineering
    • Automation
    • Software Engineering
    • Project Management
    • DevOps
  • Programming
    • Learning
  • Tools
  • About
aster.cloud aster.cloud
  • /
  • Platforms
    • Public Cloud
    • On-Premise
    • Hybrid Cloud
    • Data
  • Architecture
    • Design
    • Solutions
    • Enterprise
  • Engineering
    • Automation
    • Software Engineering
    • Project Management
    • DevOps
  • Programming
    • Learning
  • Tools
  • About
  • Programming

The Shape Of Things To Come

  • aster.cloud
  • April 29, 2023
  • 12 minute read

Creating and animating rounded shapes with AndroidX, Part I

The new graphics-shapes library allows easy creation and editing of complex, rounded polygonal shapes

A new library with the flashy name :graphics:graphics-shapes: launched recently in AndroidX. I’m happy (especially after many months of working on it with my colleague Sergio Sancho from the Android Wear team) that this project and API is finally out there. But I thought it might be helpful to describe what it is and how to actually use it.

There are two major parts to the library, which internally we call Shapes and Morph. For the benefit of short-attentions-span Medium readership, I will therefore break the description of the library down into two articles along similar lines. This first one will cover the Shapes portion of the library, which allows easy creation and rendering of rounded polygonal shapes. The second article shows how to animate (a.k.a, “Morph”) those shapes.


Partner with aster.cloud
for your next big idea.
Let us know here.



From our partners:

CITI.IO :: Business. Institutions. Society. Global Political Economy.
CYBERPOGO.COM :: For the Arts, Sciences, and Technology.
DADAHACKS.COM :: Parenting For The Rest Of Us.
ZEDISTA.COM :: Entertainment. Sports. Culture. Escape.
TAKUMAKU.COM :: For The Hearth And Home.
ASTER.CLOUD :: From The Cloud And Beyond.
LIWAIWAI.COM :: Intelligence, Inside and Outside.
GLOBALCLOUDPLATFORMS.COM :: For The World's Computing Needs.
FIREGULAMAN.COM :: For The Fire In The Belly Of The Coder.
ASTERCASTER.COM :: Supra Astra. Beyond The Stars.
BARTDAY.COM :: Prosperity For Everyone.

Android offers a very flexible drawing API. In a custom View, you can override onDraw() and use the Canvas parameter to draw anything from lines to circles to rectangles, to complex Path objects. And if you want something rounded, you can create and draw any shape you want… as long you want a RoundRect.

Of course, you can always (if you’re up for the effort) create a very complex shape (complete with arbitrary rounding) with the Path API. But out of the box, we give you only Canvas.drawRoundRect(). Moreover, Android offers very little flexibility in terms of how those rects are rounded. That is, each of the corners of the rectangles are rounded with a circular curve… period. So if you want something more custom (either in the shape of the rounded corners or the number of vertices), you are on your own.

Until now.

We thought it would be useful to provide simple creation of all kinds of rounded shapes. I mean, rectangles are cool and all. And so are those circular corners, right? They’re so… circular! But sometimes you want just a little more. Or even a lot more.

I don’t know why you would create a shape like this. But isn’t it nice that you can?

We also wanted these shapes to be available not just for apps running on future platform versions, but also across much older releases, for the enjoyment of all developers and users. So we created an API to do just that, by using Path objects internally. Path has been available since 1.0 and thus offers compatibility back as far as AndroidX itself goes.

The API for creating and drawing these shapes is simple (we saved all the complicated bits for the internal code which creates them). There are just a couple of different pieces to understand: creating a polygonal shape and specifying optional rounding parameters for the shape’s corners. I’ll cover these below.

Aside: Polygons

Q: What is a Polygon?

A: There are so many sides to that question…

It’s worth talking a little bit first about what we mean by “polygon.” In particular, it’s worth explaining what we mean when we use of the term, to show how we get to the much more complex (and interesting) shapes enabled by this library.

Wikipedia defines Polygon thusly:

In geometry, a polygon (/ˈpɒlɪɡɒn/) is a plane figure made up of line segments connected to form a closed polygonal chain.

which I find… not terribly helpful. I think mathematicians enjoy math so much that even when they’re writing words, it still sounds like equations. Let’s simplify this definition for the non mathematicians in the audience.

In its most basic form, a polygon is a 2D shape with edges and vertices (or “corners”). I usually think of polygons as having vertices that are ordered around some center, with all edges having the same length. Polygons can be much more complex than that, however, including shapes that can be self-intersecting.

Our library’s polygons are, however, a bit more staid and boring, with vertices that are positioned equidistant from some center, marching around in order. All sides are of equal length and there are no funky self-intersections. (This constraint ends up being important in being able to handle automatic morphing between our shapes with reasonable results). You can think of the base RoundedPolygon object (which we will see in more detail below) as being a shape that has a center around which all of its vertices are positioned at some given radius away from that center.

The library’s polygons can be thought of as a set of equidistant, ordered vertices which lie ‘radius’ distance from some center.

Our polygons can be a bit more complex as well. For one thing, the library has the concept of a “star polygon.” Star polygons are similar to polygons, except they have both an inner and outer radius, with vertices lying on one or the other, taking turns as the outline proceeds around the center.

Finally, our polygons have the concept of “rounding.” Rounding is not strictly a polygonal concept, since mathematical polygons are defined to have straight edges and sharp corners. So we call our shapes “Rounded Polygons,” as a blend of the general concepts of polygons with the additional nuance of optionally rounded corners. Rounded polygons have a similar geometry as the shapes above, except that each vertex has optional parameters which describe how to round its corner. For example, here is a 5-sided star polygon, like the one above, but with rounding specified for corners formed by the vertices on its outer radius.

Another star polygon, except this time with rounded corners on the outer radius

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

Read More  Google Cloud Next 2019 | Multi-Cloud Kubernetes: Formulas for Success

Now let’s look at how to use the library’s API to create those shapes.

Polygon, Stars, and More

Note: This article is current as of the alpha02 release. There will probably be minor API changes during the alpha phase; I will update the article when the API changes, and will update this release note accordingly.

The main class used to create a shape is RoundedPolygon. There are many different shapes you can create with this API, but all of them boil down to polygonal variations.

The way that you create a simple, unrounded*RoundedPolygon is by telling the API how many vertices you want and optionally providing a radius and center. Of course, any shape will have a radius and center, but by default the library creates canonical shapes with a radius of 1 around a center at (0, 0). Note that you can transform (scale, translate, rotate) the canonical shape to get it to the size and location you want by calling RoundedPolygon.transform(Matrix).

* At this point, you might be wondering why we have an API named “Rounded” which allows you to create an unrounded thing. The original version of the API handled that semantic difference, with a Polygon superclass and a RoundedPolygon subclass. But in the end, it was all a bit academic to split this functionality based on the meaning of the word “polygon,” so we went with a single class instead which handles all possibilities.
API naming is hard, imperfect, and a perpetual source of regret.

The simplest use of the API involves passing in the number of vertices and letting the library do its thing. You can then call the transform() function to resize and position the object and finally draw it into your custom view with an extension method provided by the library.

Here’s an example which creates a five-sided figure with a radius of 200 and draws it with a given Canvas and Paint object (created elsewhere):

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

Star polygons (discussed earlier) are nearly as simple; the only extra thing needed is a second radius, which is provided via the innerRadius parameter in the Star() function. This inner radius is a value ranging from 0 to the value of radius (which is the “outer” radius for the shape).

For example, to create a five-sided star polygon with a radius of 100 and an inner radius halfway between the outer radius and the center, you would do this:

val pentagonalStar = Star(5, 100f, 50f)
A Star shape created with 5 vertices and an inner radius half the value of the main radius

Rounding Error

So all of this is nice. We’ve provided a simple API to create and draw regular and star polygons. But these are not the hard parts in this problem space; it’s not too difficult to create straight-edged, sharp-corner shapes like these with the existing APIs. The interesting (and tricky) part is how to round those corners.

Figuring this out meant (in my case) re-learning a bunch of high-school level geometry and trigonometry (hey, it had been… a long time since I had those classes). Thing like trig identities, the Law of Cosines, and handy geometry facts like the angles of a triangle adding up to 180 degrees all came into play. Maybe I’ll write up that stuff sometime (or you can just look at the code and see where it ended up).

Read More  Android Dev Summit 2019 | Performance Myth Busters

But the key part (for users of the library) is: how do you use the API to get nice, rounded shapes? Fortunately, the API (like so many APIs) is much simpler than the implementation. Creating a polygon, or star polygon, with rounded corners is nothing more than creating those shapes with the APIs described above, with additional information about how the corners should be rounded.

To accomplish this task, use the class CornerRounding which is responsible for determining how the corners should be rounded. It takes two parameters: radius and smoothing.

Rounding Radius

radius is the radius of the circle used to round a vertex. This is similar to the radius parameters supplied to the existing drawRoundRect method of Canvas, except it works in concert with the optional smoothing parameter (see below). For example, we can create this rounded triangle:

where the rounding radius r for each of the corners can be pictured geometrically as follows:

The rounding radius r determines the circular rounding size of rounded corners

Note that a rounding radius produces a purely circular curve on the corner, between the two straight edges that meet at the vertex.

Smooth Moves

“Smoothing,” unlike the corner rounding radius, is a new concept in our APIs. You can think of smoothing as a factor which determines how long it takes to get from the circular rounding portion of the corner to the edge. A smoothing factor of 0 (unsmoothed, the default value for CornerRounding) results in purely circular corner rounding (if a nonzero radius is specified, as above). A nonzero smoothing factor (up to the max of 1.0) results in the corner being rounded by three separate curves. The center curve is the same circular arc produced by the rounding radius, explained above. But instead of that curve coming all the way to the polygon edges, there are now two “flanking” curves, which transition from the inner circular curve to the outer edges in smooth (non-circular) arcs of their own.

The magnitude of the smoothing curve determines both the length of the inner circular curve (more smoothing == smaller circular curve) and the length of the flanking curves (more smoothing == larger flanking curves). The flanking curves affect not only how much of the rounding happens on a circular path, but also the distance of the overall rounding curve. A larger smoothing factor pushes the intersection point of the rounding curve further along the edge toward the next vertex. A value of 1 (the max) results in no inner curve at all (the circular portion has length zero) and the maximum length of the flanking curves (which can extend as far as the next vertex, depending on the rounding parameters of that vertex).

To illustrate the impact of smoothing, it is helpful to look at a diagram showing the underlying curves. Note that all polygons are represented internally by a list of Bézier cubic curves, which are each defined by pairs of anchor and control points. These cubic curves are then used internally to create the Path objects responsible for drawing the shapes into the custom view.

Note: Describing cubic curves is beyond the scope of this already long article, but fortunately there is plenty of information out there about Bézier curves,** cubic curves, Paths, and more. I invite you to do background reading there and elsewhere if you aren’t familiar with any these concepts. But here’s a very simple description in case it helps: a cubic Bézier curve can be defined by two anchor points (one at each end of the curve) and two control points which determine the slope of the curve at those anchor points.

** I have to give a shout out to the that Bezier curve primer site linked here; it’s a vast treasure trove of information about all things Bézier, with proofs, equations, sample code, diagrams, live embedded demos, and thorough explanations. I return to it often to understand more in this complex and interesting space.

Let’s look at some pictures to see what’s going on with the underlying curves. In the diagram below, the corner of the shape (the white object on the left) is represented on the right by the green line (the outline of the shape) and the white dashed line (a circle with the given rounding radius). The cubic curve is represented by pink circles that are anchor points, yellow circles that are control points for the curve, and yellow lines between the anchor and control points. If you’ve used drawing programs such as Adobe Illustrator, or even Keynote, you may have seen similar handle visuals when drawing curves.

A smoothing factor of 0 (unsmoothed) produces a single cubic curve which follows a circle around the corner with the specified rounding radius, as in the earlier example.

When we supply a non-zero smoothing factor, the rounded corner is created with three cubic curves: the circular curve (which we saw above in the unsmoothed case) plus two flanking curves which transition between the inner circular curve and the edges. Note that the flanking curves start further back along the edge than in the unsmoothed case. The resulting shape is shown by the white object on the right. The effects of smoothing can be quite subtle, but they allow much more flexibility for designers in producing smoothed shapes that go beyond the traditional circular-round shapes.

A nonzero smoothing factor produces three cubic curves to round the vertex: the inner circular curve (as before) plus two flanking curves that transition between the inner curve and the polygon edges.

I should note that although there are many separate segments which make up each rounded corner (two edges, two flanking curves, and one inner circular curve), the result is very, er, smooth because each curve is calculated to match the slope at the point where it joins the next segment. Thus, for example, the rounded corner smoothly transitions from the inner circular curve to the non-circular smoothing curve, and then again to the straight edge.

Read More  Why Choose Rust As Your Next Programming Language

One More Thing

Besides the constructors covered above, which all take the number of vertices, there is also a more general constructor which takes a list of vertices:

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

This constructor makes it possible for you to create shapes that… do not work well with the rest of our rounded-polygon assumptions. So don’t be surprised if you throw randomly complex lists of vertices at it and the results are not as pleasing as the more constrained polygons created by the other constructors.

This constructor exists to allow creation of more interesting polygonal shapes whose vertices are not all equidistant from some center point. For example, we can use the vertex-list constructor to create a triangle shape where the bottom edge bows in.

This shape is mostly… but not completely a regular triangle. We need to use the constructor which takes a list of vertices to capture that bottom edge shape.

This triangle-ish shape 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 worry about the radialToCartesian function above — or check it out in the sample project listed below if you are curious. It’s just a function that simplifies placing vertices around a center point at specific angles).

And So On

I talked specifically about a single CornerRounding parameter above, but the API allows you to specify multiple rounding parameters, including one for the inner and outer radii to get an effect like this on star polygons.

Inner vertices can use different rounding than outer vertices. Here the outer vertices are unrounded.

You can also, if you want to take it that far, define per-vertex rounding parameters, to get a very custom shape indeed. For any of these situations, the API allows you to easily create and draw all kinds of rounded (or unrounded) polygonal shapes. You could always do this on Android, of course. After all, we are just using the existing Path API underneath to handle the drawing. But there are a lot of details (and so much math!) to sort out along the way. This new library makes the job, we hope, far easier.

A sample of shapes that can be created with this library . This screenshot was taken from the GITHUB SAMPLE described at the end of this article.

Next Steps

One of the things that drove the internal structure using cubic curves was the need to not just create and draw these shapes, but to also animate smoothly and automatically between them. Check out the next article, Shape Morphing in Android, to see how to do that with this library.

See Also

APIs!

The library is available in alpha form on AndroidX:

graphics | Jetpack | Android Developers

Sample code!

The shape editing animation in the header was created with a sample app which demonstrates shape creation, editing, and morphing. It is hosted on GitHub:

GitHub – chethaase/ShapesDemo: Demo apps showing how to use the AndroidX graphics-shapes: library

The sample has both Compose and View apps, showing how to use the library to create and morph shapes in both kinds of UI toolkits. The Compose version has an additional editor view that helps visualize the various shape parameters.

By Chet Haase
Originally published at Medium

Source: Cyberpogo


For enquiries, product placements, sponsorships, and collaborations, connect with us at [email protected]. We'd love to hear from you!

Our humans need coffee too! Your support is highly appreciated, thank you!

aster.cloud

Related Topics
  • Android
  • AndroidX
  • API
  • Jetpack
  • Shapes
You May Also Like
View Post
  • Architecture
  • Data
  • Engineering
  • People
  • Programming
  • Software Engineering
  • Technology
  • Work & Jobs

Predictions: Top 25 Careers Likely In High Demand In The Future

  • June 6, 2023
View Post
  • Programming
  • Software Engineering
  • Technology

Build a Python App to Alert You When Asteroids Are Close to Earth

  • May 22, 2023
View Post
  • Programming

Illuminating Interactions: Visual State In Jetpack Compose

  • May 20, 2023
View Post
  • Computing
  • Data
  • Programming
  • Software
  • Software Engineering

The Top 10 Data Interchange Or Data Exchange Format Used Today

  • May 11, 2023
View Post
  • Architecture
  • Programming
  • Public Cloud

From Receipts To Riches: Save Money W/ Google Cloud & Supermarket Bills – Part 1

  • May 8, 2023
View Post
  • Programming
  • Public Cloud

3 New Ways To Authorize Users To Your Private Workloads On Cloud Run

  • May 4, 2023
View Post
  • Programming
  • Public Cloud

Buffer HTTP Requests With Cloud Tasks

  • May 4, 2023
View Post
  • Programming
  • Public Cloud
  • Software
  • Software Engineering

Learn About Google Cloud’s Updated Renderer For The Maps SDK For Android

  • May 4, 2023

Stay Connected!
LATEST
  • college-of-cardinals-2025 1
    The Definitive Who’s Who of the 2025 Papal Conclave
    • May 7, 2025
  • conclave-poster-black-smoke 2
    The World Is Revalidating Itself
    • May 6, 2025
  • 3
    Conclave: How A New Pope Is Chosen
    • April 25, 2025
  • Getting things done makes her feel amazing 4
    Nurturing Minds in the Digital Revolution
    • April 25, 2025
  • 5
    AI is automating our jobs – but values need to change if we are to be liberated by it
    • April 17, 2025
  • 6
    Canonical Releases Ubuntu 25.04 Plucky Puffin
    • April 17, 2025
  • 7
    United States Army Enterprise Cloud Management Agency Expands its Oracle Defense Cloud Services
    • April 15, 2025
  • 8
    Tokyo Electron and IBM Renew Collaboration for Advanced Semiconductor Technology
    • April 2, 2025
  • 9
    IBM Accelerates Momentum in the as a Service Space with Growing Portfolio of Tools Simplifying Infrastructure Management
    • March 27, 2025
  • 10
    Tariffs, Trump, and Other Things That Start With T – They’re Not The Problem, It’s How We Use Them
    • March 25, 2025
about
Hello World!

We are aster.cloud. We’re created by programmers for programmers.

Our site aims to provide guides, programming tips, reviews, and interesting materials for tech people and those who want to learn in general.

We would like to hear from you.

If you have any feedback, enquiries, or sponsorship request, kindly reach out to us at:

[email protected]
Most Popular
  • 1
    IBM contributes key open-source projects to Linux Foundation to advance AI community participation
    • March 22, 2025
  • 2
    Co-op mode: New partners driving the future of gaming with AI
    • March 22, 2025
  • 3
    Mitsubishi Motors Canada Launches AI-Powered “Intelligent Companion” to Transform the 2025 Outlander Buying Experience
    • March 10, 2025
  • PiPiPi 4
    The Unexpected Pi-Fect Deals This March 14
    • March 13, 2025
  • Nintendo Switch Deals on Amazon 5
    10 Physical Nintendo Switch Game Deals on MAR10 Day!
    • March 9, 2025
  • /
  • Technology
  • Tools
  • About
  • Contact Us

Input your search keywords and press Enter.