Android Program to Draw Multiple Circles and Update Radius

Did you always desire to create highly-customized user interfaces in Android? Then this is the tutorial for you!

To draw custom shapes, you demand to proceed iterating until you accomplish the beautiful fine art yous desire. In this tutorial, y'all'll learn how to draw your design on paper starting time to avoid wasting time via trial and mistake.

Y'all'll ameliorate an app called Stars of Scientific discipline. You'll learn how to create custom shapes by painting a profile card with a curved custom shape and slope colors.

Throughout the tutorial, yous'll learn how to:

  • Gear up a custom shape on newspaper earlier coding.
  • Extend the Android View to draw and paint it on the Canvas.
  • Describe a curved shape in slope colors.

The custom shape you'll create will look like this:

Android custom shape

Note: This tutorial assumes yous empathise the nuts of Android development with Kotlin. If you're new to Android development, please become through Showtime Android Development with Kotlin to understand the basics. If you're new to Kotlin, check out this Introduction to Kotlin tutorial.

Getting Started

Download the project materials by clicking the Download Materials button at the superlative or bottom of this tutorial. Launch Android Studio iii.half dozen.ane or subsequently and select Open an existing Android Studio projection. Then navigate to and select the starter project folder where you'll find the files you need to start, along with some widgets.

Your app already has its basic UI prepare and then yous can focus on drawing custom shapes in Android.

Build and run the app. You'll encounter the following screen on your mobile phone or Android emulator:

The starter app showing a plain bio card

It'due south not bad, just the top of the card doesn't accept much pizazz. You'll change that throughout the tutorial.

Exploring the Projection

Take a quick expect at the project structure. Expand starsofscience package and check out the folders inside:

Here'southward a breakdown of the folders:

  • utils contains four files with extension functions you'll utilize in your painting journey.
  • view contains CircularImageView which you'll use to display the avatar in a circular shape. The code inside this course is out of the scope of this tutorial.
  • starsofscience contains 3 files:
    • MainActivity.kt is the app'due south principal and luncher activity.
    • Painter.kt contains paint() which y'all'll implement to paint your custom shape. You'll add together all drawing and painting logic to this part.
    • CustomPainter.kt is a custom Android View with a constructor accepting the width and height of your custom shape in add-on to a painter object that has all the cartoon and painting logic. This CustomPainter overrides onDraw() and delegates all the cartoon to the painter by executing canvas?.let(painter::paint).

Now that y'all know more well-nigh the classes you'll work with take a moment to larn some of the theory behind making cute shapes.

Coding Your Shapes

Before diving into drawing with Android Canvas, you need to know which tools y'all'll demand, how to utilize them and how to prepare to code your target shape.

Think almost drawing in the concrete earth. To draw a shape, you need to get a pencil and paper and then use your hand to motion the pencil across the paper'due south surface. Finally, if you want to make it beautiful, yous need to get a brush with some paint.

In this department, you'll start by cartoon a shape freehand. Grab a pencil and paper and go prepare!

Know Your Sail

Your canvas acts every bit the digital version of the piece of paper yous draw on. It holds all your drawing elements, including lines, curves, arches, shapes, text and images.

The canvas needs a size, including width and height. Drawing on a canvas without knowing its size tin can pb to unexpected results.

On your paper, before drawing whatever shape, define the canvas by cartoon a rectangle of any size you lot desire. Any shapes you draw after volition be relative to that sheet.

Rectangle on paper

Note: You don't desire your shapes to have an absolute position or size. Instead, make them relative to the size of the canvas. This lets you lot brandish your shapes on different devices with different screen sizes.

For instance, you might identify your shape at the eye of the canvas or make its size equal to half of the canvas size.

Now that yous have a canvas, it's fourth dimension to create a shape.

Defining How to Move Your Pencil

In visual arts, you have to motion your pencil properly across the paper'south surface to create your artwork. You'll use the same mechanism to describe on the sail.

Before you lot can draw a shape, you lot demand to consider which functionalities the canvass object needs to accept.

For instance, if you want to draw a square, yous need to depict four lines. And so, you need the drawing line function in your framework. On the other manus, if you want to depict a crescent, you demand to draw ii curves with the drawing curve function.

Pick up your pencil and depict a circle in the heart of the circle that's a quarter of the width, like this:

Draw a circle on paper

At present, to convert that shape on your newspaper into a shape in Android, you need to consider its coordinates.

Calculating Coordinates

Coordinates are pairs of numbers that define the verbal location of a betoken on a aeroplane.

Before yous draw anything, you lot demand to know the principal points that make up that shape. For good exercise, calculate all the coordinates and dimensions on your paper earlier writing any code. This saves you coding time and makes you focus on translating that shape from the paper onto your device.

Since you already drew a circumvolve relative to the canvas on your newspaper, you already calculated two things:

  1. The middle of the circle: Since your circle is at the eye of the canvas, the middle of the circle is the middle of the canvas. So the 10 coordinate of the circumvolve'due south heart is equal to one-half of the width of the sail and the y coordinate of the circle's center is equal to half of the top of the sheet. This ways that:
    cx = canvass width / 2
    cy = canvas meridian / 2
  2. The radius: Since your circle is a quarter of the canvas width, the diameter of the circumvolve is equal to a quarter of the width of the sheet. The radius is equal to half of the diameter. That means:
    diameter = canvas width / 4
    radius = diameter / 2 = canvass width / 8

Circle properties

See, drawing your shapes on newspaper helps you summate the points you demand to draw your shape relative to the canvass.

It's efficient to visualize what yous need to do earlier it's time to translate your ideas into code. Making paper sketches is a prerequisite for your custom cartoon! :]

Using CustomPainter

At present that y'all've learned some theory, it's time to start using the Android Sheet and add some lawmaking that will reproduce your drawing in the app.

Implementing the Painter Interface

Kickoff past creating a new form ProfileCardPainter in the starsofscience parcel. Then replace the whole file content with:

package com.raywenderlich.android.starsofscience  import android.graphics.* import androidx.note.ColorInt  //1 grade ProfileCardPainter(     //2     @ColorInt private val colour: Int ) : Painter {   //3   override fun paint(sheet: Canvas) {    } }        

Here you:

  1. Ascertain a new grade named ProfileCardPainter that implements the interface Painter.
  2. So in its primary constructor y'all define the contour color as a class property.
  3. Finally, yous implement paint(sail: Canvas). CustomPainter will phone call this method whenever the object needs to paint.

    You'll write all your drawing code within this office, which gives you one parameter: The canvas to draw on.

Rendering With CustomPainter

Become to MainActivity.kt. Y'all'll find the following line of lawmaking in onCreate():

profileCardContainer.setBackgroundColor(R.color.colorPrimary.toColorInt(this))        

It sets a background color to the profileCardContainer which is a FrameLayout already defined in XML. You don't need that line anymore because you desire to add your custom shape instead of that solid color.

Replace that line with the post-obit code:

//1 val azureColor = R.color.colorPrimary.toColorInt(this) val avatarRadius = R.dimen.avatar_radius.resToPx(this) val avatarMargin = R.dimen.avatar_margin.resToPx(this) val cardWidth = ViewGroup.LayoutParams.MATCH_PARENT val cardHeight = R.dimen.profile_card_height.resToPx(this).toInt() //two val painter = ProfileCardPainter(   color = azureColor ) //3 profileCardContainer.addView(   CustomPainter(     context = this,     width = cardWidth,     height = cardHeight,     painter = painter   ) )        

Add any missing import past pressing Option+Enter on Mac or Alt+Enter on PC.

In the lawmaking above:

  1. You define the properties of your custom shape: Colour, avatar radius, avatar margin, width and height.
  2. Then, y'all create a ProfileCardPainter with the color you lot previously divers.
  3. Finally, yous add a new CustomPainter as a subview of profileCardContainer past passing all its needed properties:
    • context to create this custom Android View.
    • width and tiptop of the custom shape.
    • painter responsible for all the drawing logic.

Build and run the app to see… a pretty ugly card because y'all haven't drawn anything yet. Don't worry, you'll start drawing something in a moment. :]

Initial changes to the app

Drawing Your Kickoff Shape

In this section, you'll do with the tools y'all need to draw in the calculator graphics globe. They're a lot like the physical tools yous used to draw a circle on a newspaper. Then, with this noesis, you'll draw your first shape!

Note: Graphics libraries take similar APIs for drawing, which makes drawing in Android comparable to drawing in iOS, Flutter and the web. When yous master drawing custom shapes on one platform, information technology's easy to reuse this knowledge on other platforms.

Cartoon and Painting a Rectangle

To draw a rectangle, you demand to create a RectF object with the size yous want. You then need a Pigment object with the colour you prefer to start drawing that RectF on the sheet.

RectF is a uncomplicated course with four immutable bladder properties: Left, top, right and bottom. These four numbers represent a rectangle, where:

  • Left is the left-most indicate on the x-centrality.
  • Top is the top-most signal on the y-axis.
  • Right is the correct-about signal on the x-centrality.
  • Bottom is the bottom-almost point on the y-axis.

Note: You can calculate any actress properties in RectF, like the width and height, based on these 4 principal properties.

In this tutorial, y'all'll rely on RectF for your shape bounds. You'll draw each shape inside of and based on a certain RectF.

In ProfileCardPainter.kt, go to paint() and add the post-obit:

//i val width = canvas.width.toFloat() val tiptop = sail.height.toFloat() //two val shapeBounds = RectFFactory.fromLTWH(0f, 0f, width, superlative) //3 val paint = Paint() paint.color = colour //iv sail.drawRect(shapeBounds, paint)        

Add together whatsoever missing import by pressing Choice+Enter on Mac or Alt+Enter on PC.

Here'south what this lawmaking defines:

  1. The width and height of the canvas.
  2. shapeBounds is a RectF with a size that fits the whole area of the canvas past using the factory function fromLTWH().
  3. paint is your paint and its colour.
  4. Finally, you draw your shapeBounds on the canvas by passing information technology to drawRect() along with your paint from the previous line.

Now, build and run the app. See that the card at present has a blue rectangle as its background. Hooray, you've drawn your first shape! :]

The starter app showing a plain bio card

That's better, but there's yet much room for improvement!

Using a Path to Draw the Profile Card

A path is not a bitmap or raster, and it doesn't have pixels. Information technology's an outline that represents a serial of smooth lines, arcs or Bézier curves. Using a path makes your shapes scalable and independent of the screen's resolution.

Path is a powerful class that you tin can utilise in many situations. For example, yous tin can prune a bitmap by a path, or you tin can utilise a path to draw a custom shape similar you lot're most to do right now.

Drawing the Profile Card

In this section, yous'll start using the Path class to draw a more complex shape like the blue shape here:

Profile card shape

Merely before you start, you need to do some preparation.

In that location are a few things you should note in the previous epitome:

  • Blackness dashed rectangle: Represents the whole canvass.
  • Red dashed rectangle: Marks the bounds of the blue shape. It has the same width and height equally the canvas, except that yous subtract the avatar radius from its tiptop.
  • Blue shape: A rectangle with a half circumvolve, an arc of a circle, every bit a negative infinite at the bottom heart. This arc should have a radius equal to the radius of the avatar.

Note: An arc is a segment of a bend. In this example, the arc you'll utilise is a section of a circle's circumference, besides called a circular arc.

The prototype below shows a bluish arc that starts at the cipher degree bending and sweeps to 90 degrees.

90 degrees arc

First, get the radius of the avatar. Start by adding a new form property called avatarRadius to your ProfileCardPainter primary constructor:

class ProfileCardPainter(     @ColorInt individual val colour: Int,     private val avatarRadius: Float ) : Painter {        

Then, go to MainActivity.kt and, in onCreate(), pass the avatarRadius to ProfileCardPainter:

val painter = ProfileCardPainter(   color = azureColor,   avatarRadius = avatarRadius )        

Finally, return to ProfileCardPainter.kt and update the shapeBounds by subtracting the avatarRadius from its tiptop in fromLTWH():

val shapeBounds = RectFFactory.fromLTWH(0f, 0f, width, summit - avatarRadius)        

The avatar radius

To see the results build and run the app:

Initial results for your custom painter

Great! At present the blue background stops halfway downwardly the length of the avatar.

Adding Negative Space Around the Avatar

Next, you'll add some negative space to the blue shape to set it apart from the avatar. Add together a new function chosen drawBackground() to ProfileCardPainter:

            private fun drawBackground(sheet: Sail, bounds: RectF, avatarBounds: RectF) {   //ane   val paint = Paint()   paint.color = color    //2   val backgroundPath = Path().apply {     // 3     moveTo(bounds.left, bounds.top)     // 4     lineTo(premises.bottomLeft.x, bounds.bottomLeft.y)     // five     lineTo(avatarBounds.centerLeft.ten, avatarBounds.centerLeft.y)     // 6     arcTo(avatarBounds, -180f, 180f, false)     // 7     lineTo(bounds.bottomRight.10, bounds.bottomRight.y)     // viii     lineTo(bounds.topRight.x, premises.topRight.y)     // 9     shut()    }    //10   canvas.drawPath(backgroundPath, paint); }        

Add any missing import by pressing Option+Enter on Mac or Alt+Enter on PC. To import all the extension functions you need for RectF in a row, add the following import:

import com.raywenderlich.android.starsofscience.utils.*        

This diagram illustrates the proper coordinates for each bespeak you lot need to build the path.

Custom path

In the previous code:

  1. You create a Paint object and prepare its color.
  2. So, you lot create a Path object.
  3. Y'all motility to the elevation-left corner, P1, without drawing a line. This is like moving a pencil to a starting betoken without touching the paper.
  4. Next, you lot add a directly line that starts at P1 and ends at P2.
  5. Then, yous add a straight line that starts at P2 and ends at P3: The point at the edge of where you lot will start drawing the arc.
  6. Then, starting from P3, add an arc in the upper half region of the avatar bounds: The arc starts from the bending -180 degrees and sweeps past 180 degrees catastrophe at P4.
    Yous laissez passer false as the final parameter to prevent starting a new sub-path for the arc. This tells Android that you desire the arc on the aforementioned path.
  7. Side by side, you add a straight line that starts from the electric current signal and ends at P5 at the bottom-right corner.
  8. You finish past adding a direct line that starts from the current signal P5 and ends at the given point P6 at the top-right corner.
  9. Then yous close the path by adding a straight line that starts at the electric current point P6 and ends at the beginning betoken on the path, P1.
  10. Finally, you describe the backgroundPath on the canvass past passing it to drawPath() with pigment.

In the previous code, yous can collapse lines five and half-dozen in a single line. Do you know how? You tin can find the solution in the spoiler beneath.

[spoiler title="Solution"]
Y'all can collapse lines five and six past leaving only line six.

arcTo(avatarBounds, -180f, 180f, imitation)

The official documentation of

arcTo(RectF oval, float startAngle, float sweepAngle, boolean forceMoveTo)

states: "If the start of the path is different from the path'south current last point, then an automated lineTo() is added to connect the current contour to the starting time of the arc."
[/spoiler]

Phew! That was a lot of lawmaking, merely information technology was worth the effort!

Creating the Rectangle Around the Avatar

In ProfileCardPainter, get to paint() and replace the last iii lines:

          val paint = Paint()     paint.color = color     canvas.drawRect(shapeBounds, pigment)        

with the following code to create a new RectF effectually the avatar:

//ane val centerAvatar = PointF(shapeBounds.centerX(), shapeBounds.bottom) //ii val avatarBounds = RectFFactory.fromCircle(center = centerAvatar, radius = avatarRadius) //3 drawBackground(sheet, shapeBounds, avatarBounds)        

Here'south what this lawmaking does:

  1. Yous create a PointF object for the center betoken of the avatar, where 10 is the shapeBounds.centerX() and y is the bottom of the shapeBounds.
  2. Then, y'all create a RectF object from the avatar circle using fromCircle(). The center is centerAvatar, which you simply created, and the radius is the avatarRadius.
  3. Finally, you telephone call drawBackground() and pass the canvas with residual of the parameters to draw your first path.

Build and run the app. You'll see this:

Initial results for your custom painter

You probably don't notice the difference yet. Don't worry, you'll fix that adjacent.

Adding a Margin Around the Avatar

There is a deviation, only you can't see information technology considering the negative space is exactly equal to the round avatar's size. Next, you'll brand that negative space a bit bigger to leave a margin betwixt it and the avatar.

First, become the margin of the avatar. Start by calculation 1 more class belongings chosen avatarMargin to your ProfileCardPainter primary constructor, don't forget the comma at the end of the line to a higher place the new lawmaking.

class ProfileCardPainter(     ...     individual val avatarMargin: Bladder )        

Then, become to MainActivity.kt and, in onCreate(), laissez passer the avatarMargin to the ProfileCardPainter constructor:

val painter = ProfileCardPainter(   ...   avatarMargin = avatarMargin )        

Finally, return to ProfileCardPainter.kt and\where y'all create the avatarBounds in pigment, add .inflate(avatarMargin) to the cease:

val avatarBounds = RectFFactory.fromCircle(center = centerAvatar, radius = avatarRadius).inflate(avatarMargin)        

Calling inflate() on a RectF creates a new RectF object whose left, top, correct and bottom edges are moved outwards past the given value. The result is a nice space around the avatar.

To see the margin in activeness, build and run the app.

Margin around the avatar

Pretty... merely ordinary. Next, you'll spice up the groundwork past calculation an attractive curved shape.

Adding More Keen Shapes

To heighten your custom shape, you can add some elementary decorations like stars or circles in a partially-faded color. For this app, y'all'll add a more interesting decoration: A curvy shape in gradient colors.

Adding a Curved Shape

Earlier y'all start drawing, take a moment to acquire about the dissimilar types of curves. The Quadratic Bézier Curve and the Cubic Bézier Curve are two normally used curves.

  • A quadratic Bézier curve requires three points to draw: A start signal, an endpoint and a handle point that pulls the curve towards it.

    Quadratic Bézier Curve

  • A cubic Bézier curve needs four points to describe: A start betoken, an end point and 2 handle points that pull the curve towards them.

    Cubic Bézier Curve

Next, you lot'll use a quadratic Bézier bend to create an interesting background shape.

Drawing a Quadratic Bézier Curve

Commencement by creating a new function called drawCurvedShape() inside ProfileCardPainter with the following:

individual fun drawCurvedShape(canvas: Canvas, bounds: RectF, avatarBounds: RectF) {   //one   val pigment = Paint()   paint.color = color.darkerShade()    //2   val handlePoint = PointF(bounds.left + (bounds.width() * 0.25f), bounds.top)    //three   val curvePath = Path().utilize {     //4     moveTo(bounds.bottomLeft.10, bounds.bottomLeft.y)     //5     lineTo(avatarBounds.centerLeft.ten, avatarBounds.centerLeft.y)     //6     arcTo(avatarBounds, -180f, 180f, false)     //vii     lineTo(premises.bottomRight.10, premises.bottomRight.y)     //viii     lineTo(bounds.topRight.ten, premises.topRight.y)     //9     quadTo(handlePoint.x, handlePoint.y, bounds.bottomLeft.x, bounds.bottomLeft.y)     //10     close()   }    //xi   canvass.drawPath(curvePath, paint) }        

This diagram volition help yous understand the lawmaking you added. Utilize it as a guide to the proper coordinates for each indicate you'll build to create the path:

Path for new arc

In the previous code:

  1. You create a Paint object and set its color to a darker shade of the profile color.
  2. Then, you create a handle bespeak at the top left corner of the RectF, shifted to the right by 25% of the width of the RectF. This is P6 in the guide image.
  3. You create a Path object.
  4. Then, you motion to the bottom-left corner, P1 in the guide image.
  5. Y'all add a directly line that starts from P1 and ends at P2: The heart point at the edge of the blackness dashed avatar bounds RectF.
  6. So, starting from the electric current betoken, P2, add together an arc in the upper- one-half region of the avatar bounds: The arc starts from the angle -180 degrees and sweeps past 180 degrees ending in P3.
    You laissez passer faux as the terminal parameter so you don't showtime a new sub-path for the arc. This tells Android that you lot want the arc on the same path.
  7. Yous add a straight line that starts from the electric current point and ends at the given point, the bottom-right corner. This adds a line from P3 to P4.
  8. Then, yous add a straight line that starts from the current indicate and ends at the given betoken, the top-right corner, adding a line from P4 to P5.
  9. Y'all add a quadratic Bézier bend that starts from the current point, P5, and ends at the bottom-left corner, P1, using the handle point you created in footstep two.
  10. Finally, you close the path, fifty-fifty though it's not required this time since you are back at the outset point on the path.
  11. You describe curvePath on the sail by passing it to drawPath() along with the paint object.

Finalizing the Curve

You're almost finished creating the bend. In ProfileCardPainter, go to the last line in paint() and add the following lawmaking:

//ane val curvedShapeBounds = RectFFactory.fromLTRB(     shapeBounds.left,     shapeBounds.top + shapeBounds.height() * 0.35f,     shapeBounds.right,     shapeBounds.lesser ) //two drawCurvedShape(canvass, curvedShapeBounds, avatarBounds)        

Here, you:

  1. Create a RectF that is similar to the shapeBounds rect, except you've shifted its peak slightly to the bottom by 35% of the shapeBounds' height: This is the reddish dashed RectF in the image above.
  2. Call drawCurvedShape() and pass the sail object, the curved shape premises and the avatar premises to it.

Build and run the app to see the neat background curve behind the avatar:

Add a curve behind the avatar

So you lot're done, right? Almost. There's nevertheless one more finishing bear upon you demand to add.

Calculation Gradient Pigment

You lot've created your first beautiful, custom curved shape, only your graphic designer wants you to do one more thing: Add together gradient colors to your curved shape.

There are different types of shaders or gradients, including linear gradients, which transition through at least ii colors in a directly line, and radial gradients, which transition through colors starting from a central point and radiating outward.

Right at present, yous'll create a shader, a linear slope described past three colors. Each color needs a stop to specify its position on a line from 0.0 to i.0.

Start by creating a new function called createGradient() inside ProfileCardPainter with the following code:

            individual fun createGradient(bounds: RectF): LinearGradient {   //i   val colors = intArrayOf(color.darkerShade(), color, color.darkerShade())   //ii   val stops = floatArrayOf(0.0f, 0.3f, one.0f)   //3   return LinearGradient(       bounds.centerLeft.x, bounds.centerLeft.y,       bounds.centerRight.ten, bounds.centerRight.y,       colors,       stops,       Shader.TileMode.REPEAT   ) }        

Here's what's going on in this lawmaking:

  1. You create a list of three colors, where the middle colour is the profile color and the first and concluding colors are darker shades of that profile color.
  2. And so yous create a list of three stops. The first is 0.0, which puts the corresponding color in the colors list at the zippo position of the gradient color. In the same way, the middle and the stops specify the positions of their corresponding colors in the color list.
  3. Finally, you create a linear gradient by passing the first coordinates and the end coordinates of the gradient with the given colors and stops, and the shader TileMode to echo the slope in instance the expanse which you fill up is larger than the shader you created.

Now go to drawCurvedShape() and update the paint object to use the new linear slope instead of a solid color.

Replace this line:

paint.color = color.darkerShade()        

With this one:

paint.shader = createGradient(bounds)        

Here, you lot create a new gradient and set it to the paint object.

Finally, build and run the app to see a gradient within the background curve:

Background curve with gradient

Congratulations! You've created a cute profile carte with an eye-catching custom groundwork shape and shading.

Where to Go From Here?

You can download the completed final project using the Download Materials button at the top or bottom of the tutorial.

Wow, that was a lot of work! But you learned a lot, also. In addition to taking a deep look at Canvas and many Android Graphics APIs, you learned how to:

  • Fix your custom shape on newspaper before coding.
  • Use Path and how to add different lines to it sequentially.
  • Draw a curved shape in gradient colors.

To larn more about Canvass and Android custom views bank check out the following links:

  • Android Custom View Tutorial.
  • Making your cartoon Interactive.
  • Custom Android Compound View.

Also, yous can cheque RichPath library. It's an open up-source library that gives you lot full control over your custom shapes in vector drawable format so you tin can manipulate and breathing them easily at runtime.

Feel complimentary to share your feedback, comments or enquire questions in the forum below. Don't stop drawing. ;]

kennedyollourety.blogspot.com

Source: https://www.raywenderlich.com/9556022-drawing-custom-shapes-in-android

0 Response to "Android Program to Draw Multiple Circles and Update Radius"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel