Draw a Circle Android Drawable
Did y'all ever desire to create highly-customized user interfaces in Android? Then this is the tutorial for you!
To draw custom shapes, you need to proceed iterating until you accomplish the cute art yous want. In this tutorial, you'll learn how to draw your design on newspaper first to avert wasting time via trial and error.
You'll ameliorate an app called Stars of Science. You'll larn how to create custom shapes past painting a profile card with a curved custom shape and gradient colors.
Throughout the tutorial, you'll learn how to:
- Prepare a custom shape on newspaper before coding.
- Extend the Android
Viewto draw and paint it on theCanvas. - Draw a curved shape in slope colors.
The custom shape you'll create volition look like this:
Annotation: This tutorial assumes you sympathise the nuts of Android development with Kotlin. If you're new to Android development, please go through Outset Android Development with Kotlin to sympathize the basics. If yous'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 3.half dozen.1 or later and select Open an existing Android Studio project. Then navigate to and select the starter project folder where y'all'll find the files you lot need to showtime, along with some widgets.
Your app already has its bones UI prepare and then you tin focus on cartoon custom shapes in Android.
Build and run the app. You lot'll see the following screen on your mobile telephone or Android emulator:
It's groovy, only the top of the card doesn't have much pizazz. You lot'll change that throughout the tutorial.
Exploring the Projection
Take a quick look at the project construction. Expand starsofscience parcel and cheque out the folders within:
Hither'due south a breakdown of the folders:
- utils contains 4 files with extension functions you lot'll use in your painting journey.
- view contains
CircularImageViewwhich y'all'll use to display the avatar in a circular shape. The code inside this class is out of the telescopic of this tutorial. - starsofscience contains 3 files:
- MainActivity.kt is the app's primary and luncher activity.
- Painter.kt contains pigment() which y'all'll implement to paint your custom shape. You lot'll add all drawing and painting logic to this part.
- CustomPainter.kt is a custom Android View with a constructor accepting the width and pinnacle of your custom shape in addition to a painter object that has all the drawing and painting logic. This
CustomPainteroverridesonDraw()and delegates all the drawing to the painter by executingcanvas?.let(painter::pigment).
Now that y'all know more than nigh the classes yous'll piece of work with take a moment to learn some of the theory behind making beautiful shapes.
Coding Your Shapes
Earlier diving into drawing with Android Canvass, yous demand to know which tools you'll need, how to use them and how to ready to code your target shape.
Remember about drawing in the physical globe. To draw a shape, you need to get a pencil and newspaper and then use your hand to move the pencil across the newspaper'southward surface. Finally, if you want to go far beautiful, you need to get a castor with some paint.
In this department, you'll starting time by drawing a shape freehand. Catch a pencil and paper and get ready!
Know Your Sail
Your canvas acts every bit the digital version of the slice of paper you lot depict on. It holds all your drawing elements, including lines, curves, arches, shapes, text and images.
The canvas needs a size, including width and summit. Drawing on a canvas without knowing its size can lead to unexpected results.
On your paper, earlier drawing any shape, define the canvass by cartoon a rectangle of any size you desire. Any shapes yous draw later volition be relative to that canvas.
Note: Yous 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 display your shapes on different devices with different screen sizes.
For instance, you might place your shape at the center of the canvas or make its size equal to one-half of the canvas size.
At present that you accept a sheet, it's time to create a shape.
Defining How to Move Your Pencil
In visual arts, y'all have to movement your pencil properly across the paper's surface to create your artwork. You'll use the same mechanism to draw on the canvas.
Before you lot can draw a shape, yous demand to consider which functionalities the sheet object needs to take.
For case, if you desire to draw a square, you need to draw four lines. Then, yous need the drawing line function in your framework. On the other hand, if you desire to draw a crescent, you lot need to depict two curves with the drawing curve office.
Option up your pencil and depict a circumvolve in the center of the circle that'due south a quarter of the width, like this:
Now, to catechumen that shape on your paper into a shape in Android, you need to consider its coordinates.
Computing Coordinates
Coordinates are pairs of numbers that ascertain the verbal location of a indicate on a plane.
Earlier you lot draw anything, you need to know the main points that make up that shape. For proficient practice, calculate all the coordinates and dimensions on your paper earlier writing whatsoever lawmaking. This saves you lot coding time and makes you focus on translating that shape from the paper onto your device.
Since y'all already drew a circle relative to the canvas on your paper, you already calculated 2 things:
- The centre of the circumvolve: Since your circle is at the center of the canvass, the center of the circle is the center of the canvas. So the ten coordinate of the circle's center is equal to half of the width of the sheet and the y coordinate of the circle's centre is equal to half of the height of the sail. This means that:
cx = canvass width / ii
cy = canvas height / 2 - The radius: Since your circumvolve is a quarter of the sheet width, the diameter of the circumvolve is equal to a quarter of the width of the canvas. The radius is equal to one-half of the diameter. That means:
diameter = canvas width / 4
radius = bore / ii = canvas width / 8
See, drawing your shapes on paper helps you calculate the points y'all need to draw your shape relative to the sail.
It's efficient to visualize what you need to do before information technology's fourth dimension to translate your ideas into code. Making paper sketches is a prerequisite for your custom cartoon! :]
Using CustomPainter
Now that you lot've learned some theory, it's time to start using the Android Canvas and add some lawmaking that will reproduce your drawing in the app.
Implementing the Painter Interface
Start by creating a new class ProfileCardPainter in the starsofscience packet. So supervene upon the whole file content with:
package com.raywenderlich.android.starsofscience import android.graphics.* import androidx.annotation.ColorInt //1 course ProfileCardPainter( //two @ColorInt private val color: Int ) : Painter { //three override fun paint(canvas: Canvass) { } } Hither you:
- Define a new class named
ProfileCardPainterthat implements the interfacePainter. - Then in its primary constructor you lot define the profile color as a class holding.
- Finally, y'all implement
paint(canvass: Canvas).CustomPaintervolition phone call this method whenever the object needs to paint.Yous'll write all your cartoon code inside this function, which gives you one parameter: The
canvasto depict on.
Rendering With CustomPainter
Become to MainActivity.kt. You'll find the following line of code in onCreate():
profileCardContainer.setBackgroundColor(R.colour.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 want to add your custom shape instead of that solid color.
Replace that line with the following code:
//one 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() //2 val painter = ProfileCardPainter( colour = azureColor ) //three profileCardContainer.addView( CustomPainter( context = this, width = cardWidth, height = cardHeight, painter = painter ) ) Add whatever missing import by pressing Option+Enter on Mac or Alt+Enter on PC.
In the code above:
- You ascertain the properties of your custom shape: Color, avatar radius, avatar margin, width and height.
- Then, you create a
ProfileCardPainterwith the color yous previously divers. - Finally, you add together a new
CustomPainterevery bit a subview ofprofileCardContainerby passing all its needed properties:-
contextto create this custom AndroidView. -
widthandheightof the custom shape. -
painterresponsible for all the drawing logic.
-
Build and run the app to come across… a pretty ugly carte because y'all haven't fatigued annihilation nevertheless. Don't worry, you'll start drawing something in a moment. :]
Drawing Your First Shape
In this section, yous'll practise with the tools you need to depict in the computer graphics world. They're a lot like the physical tools you used to draw a circumvolve on a newspaper. Then, with this knowledge, you'll depict your first shape!
Note: Graphics libraries have like APIs for cartoon, which makes drawing in Android comparable to drawing in iOS, Flutter and the web. When you chief drawing custom shapes on ane platform, it'south piece of cake to reuse this knowledge on other platforms.
Drawing and Painting a Rectangle
To depict a rectangle, you need to create a RectF object with the size you desire. You lot then need a Paint object with the color you adopt to start cartoon that RectF on the canvas.
RectF is a simple course with four immutable float properties: Left, top, right and bottom. These four numbers correspond a rectangle, where:
- Left is the left-most betoken on the ten-axis.
- Height is the top-most point on the y-axis.
- Right is the right-most point on the x-axis.
- Bottom is the bottom-most signal on the y-axis.
Notation: You tin calculate whatever extra properties in RectF, similar the width and height, based on these four primary properties.
In this tutorial, you lot'll rely on RectF for your shape bounds. You'll depict each shape inside of and based on a certain RectF.
In ProfileCardPainter.kt, become to paint() and add the following:
//1 val width = canvas.width.toFloat() val height = canvas.summit.toFloat() //2 val shapeBounds = RectFFactory.fromLTWH(0f, 0f, width, height) //3 val paint = Paint() paint.color = color //4 canvas.drawRect(shapeBounds, paint) Add together whatever missing import by pressing Option+Enter on Mac or Alt+Enter on PC.
Here's what this lawmaking defines:
- The
widthandacmeof the sheet. -
shapeBoundsis aRectFwith a size that fits the whole area of the canvas by using the factory functionfromLTWH(). -
paintis your pigment and its colour. - Finally, you depict your
shapeBoundson thecanvasby passing it todrawRect()along with yourpigmentfrom the previous line.
At present, build and run the app. See that the card now has a blue rectangle as its groundwork. Hooray, you've drawn your get-go shape! :]
That'south amend, but at that place's still much room for comeback!
Using a Path to Draw the Contour Card
A path is non a bitmap or raster, and information technology doesn't have pixels. It's an outline that represents a series of polish lines, arcs or Bézier curves. Using a path makes your shapes scalable and contained of the screen'southward resolution.
Path is a powerful class that y'all can use in many situations. For example, you tin can clip a bitmap by a path, or you can utilize a path to draw a custom shape like you're about to do right now.
Drawing the Profile Card
In this section, y'all'll start using the Path form to draw a more complex shape like the blue shape here:
But before you lot beginning, y'all need to do some preparation.
In that location are a few things you should note in the previous paradigm:
- Blackness dashed rectangle: Represents the whole sail.
- Red dashed rectangle: Marks the bounds of the blue shape. It has the same width and height as the canvas, except that you decrease the avatar radius from its height.
- Blue shape: A rectangle with a half circle, an arc of a circle, equally a negative space at the lesser heart. This arc should have a radius equal to the radius of the avatar.
Annotation: An arc is a segment of a curve. In this instance, the arc you'll use is a section of a circumvolve's circumference, also called a circular arc.
The image below shows a blue arc that starts at the zero degree angle and sweeps to ninety degrees.
Outset, get the radius of the avatar. Start by calculation a new grade property called avatarRadius to your ProfileCardPainter primary constructor:
grade ProfileCardPainter( @ColorInt private val color: Int, individual val avatarRadius: Bladder ) : Painter { Then, get 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 superlative in fromLTWH():
val shapeBounds = RectFFactory.fromLTWH(0f, 0f, width, height - avatarRadius)
To see the results build and run the app:
Dandy! Now the blueish background stops halfway downward the length of the avatar.
Calculation Negative Space Around the Avatar
Adjacent, yous'll add some negative space to the blue shape to set it apart from the avatar. Add together a new office called drawBackground() to ProfileCardPainter:
private fun drawBackground(canvas: Canvas, bounds: RectF, avatarBounds: RectF) { //ane val paint = Paint() paint.color = color //2 val backgroundPath = Path().apply { // iii moveTo(premises.left, bounds.top) // 4 lineTo(bounds.bottomLeft.x, premises.bottomLeft.y) // five lineTo(avatarBounds.centerLeft.x, avatarBounds.centerLeft.y) // 6 arcTo(avatarBounds, -180f, 180f, fake) // vii lineTo(bounds.bottomRight.10, bounds.bottomRight.y) // 8 lineTo(bounds.topRight.x, bounds.topRight.y) // 9 close() } //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 y'all need for RectF in a row, add the post-obit import:
import com.raywenderlich.android.starsofscience.utils.* This diagram illustrates the proper coordinates for each signal yous need to build the path.
In the previous code:
- You create a
Pigmentobject and prepare its colour. - Then, you lot create a
Pathobject. - You move to the top-left corner, P1, without cartoon a line. This is like moving a pencil to a starting betoken without touching the newspaper.
- Adjacent, you add a straight line that starts at P1 and ends at P2.
- And so, you lot add together a straight line that starts at P2 and ends at P3: The point at the edge of where you lot volition start drawing the arc.
- Then, starting from P3, add together an arc in the upper half region of the avatar bounds: The arc starts from the angle
-180degrees and sweeps by180degrees ending at P4.
You passsimulatedevery bit the last parameter to forbid starting a new sub-path for the arc. This tells Android that you want the arc on the same path. - Adjacent, you add a directly line that starts from the current betoken and ends at P5 at the bottom-right corner.
- You cease by adding a straight line that starts from the current point P5 and ends at the given point P6 at the elevation-right corner.
- Then y'all close the path by adding a straight line that starts at the current signal P6 and ends at the get-go point on the path, P1.
- Finally, you draw the
backgroundPathon the canvas by passing it todrawPath()withpaint.
In the previous code, you tin can collapse lines five and 6 in a unmarried line. Do you know how? You lot can find the solution in the spoiler beneath.
[spoiler title="Solution"]
You tin can collapse lines 5 and six by leaving only line 6.
arcTo(avatarBounds, -180f, 180f, imitation) The official documentation of
arcTo(RectF oval, bladder startAngle, bladder sweepAngle, boolean forceMoveTo)
states: "If the start of the path is unlike from the path'south current last point, then an automatic lineTo() is added to connect the electric current contour to the start of the arc."
[/spoiler]
Phew! That was a lot of code, only it was worth the effort!
Creating the Rectangle Around the Avatar
In ProfileCardPainter, go to pigment() and replace the last 3 lines:
val paint = Paint() paint.colour = color canvas.drawRect(shapeBounds, paint) with the post-obit code to create a new RectF around the avatar:
//1 val centerAvatar = PointF(shapeBounds.centerX(), shapeBounds.bottom) //2 val avatarBounds = RectFFactory.fromCircle(middle = centerAvatar, radius = avatarRadius) //3 drawBackground(canvas, shapeBounds, avatarBounds) Here's what this code does:
- Yous create a
PointFobject for the center point of the avatar, where10is theshapeBounds.centerX()andyis thebottomof theshapeBounds. - Then, y'all create a
RectFobject from the avatar circumvolve usingfromCircle(). The center iscenterAvatar, which you just created, and the radius is theavatarRadius. - Finally, you lot phone call
drawBackground()and pass the canvas with rest of the parameters to describe your get-go path.
Build and run the app. Y'all'll see this:
You probably don't discover the difference even so. Don't worry, you'll set that side by side.
Adding a Margin Effectually the Avatar
There is a difference, but you tin can't run into it because the negative infinite is exactly equal to the round avatar's size. Side by side, you'll brand that negative space a bit bigger to leave a margin between it and the avatar.
Outset, get the margin of the avatar. Beginning past calculation one more class belongings called avatarMargin to your ProfileCardPainter chief constructor, don't forget the comma at the end of the line above the new code.
class ProfileCardPainter( ... private val avatarMargin: Float ) Then, go to MainActivity.kt and, in onCreate(), pass the avatarMargin to the ProfileCardPainter constructor:
val painter = ProfileCardPainter( ... avatarMargin = avatarMargin ) Finally, return to ProfileCardPainter.kt and\where you create the avatarBounds in paint , add together .inflate(avatarMargin) to the end:
val avatarBounds = RectFFactory.fromCircle(middle = centerAvatar, radius = avatarRadius).inflate(avatarMargin) Calling inflate() on a RectF creates a new RectF object whose left, height, right and bottom edges are moved outwards by the given value. The result is a dainty space around the avatar.
To run into the margin in action, build and run the app.
Pretty... simply ordinary. Next, you'll spice up the groundwork by adding an attractive curved shape.
Calculation More Bully Shapes
To enhance your custom shape, you can add some uncomplicated decorations like stars or circles in a partially-faded color. For this app, you'll add a more than interesting decoration: A curvy shape in gradient colors.
Adding a Curved Shape
Before you start drawing, take a moment to larn about the different types of curves. The Quadratic Bézier Curve and the Cubic Bézier Bend are two commonly used curves.
- A quadratic Bézier curve requires three points to depict: A start point, an endpoint and a handle point that pulls the curve towards it.
- A cubic Bézier bend needs iv points to draw: A start signal, an end point and two handle points that pull the curve towards them.
Next, you'll use a quadratic Bézier curve to create an interesting groundwork shape.
Drawing a Quadratic Bézier Bend
Start past creating a new role called drawCurvedShape() inside ProfileCardPainter with the following:
private fun drawCurvedShape(canvass: Canvas, bounds: RectF, avatarBounds: RectF) { //one val paint = Paint() pigment.color = color.darkerShade() //ii val handlePoint = PointF(bounds.left + (bounds.width() * 0.25f), bounds.top) //3 val curvePath = Path().utilise { //4 moveTo(bounds.bottomLeft.10, bounds.bottomLeft.y) //5 lineTo(avatarBounds.centerLeft.x, avatarBounds.centerLeft.y) //half dozen arcTo(avatarBounds, -180f, 180f, false) //vii lineTo(premises.bottomRight.ten, premises.bottomRight.y) //viii lineTo(bounds.topRight.10, bounds.topRight.y) //nine quadTo(handlePoint.ten, handlePoint.y, bounds.bottomLeft.x, bounds.bottomLeft.y) //10 shut() } //11 canvass.drawPath(curvePath, paint) } This diagram will help yous sympathise the code you added. Use information technology every bit a guide to the proper coordinates for each signal you'll build to create the path:
In the previous code:
- Yous create a
Paintobject and set its colour to a darker shade of the profile color. - Then, you create a handle point at the superlative left corner of the
RectF, shifted to the right by 25% of the width of theRectF. This is P6 in the guide image. - Y'all create a
Pathobject. - And then, you motility to the bottom-left corner, P1 in the guide prototype.
- You add a directly line that starts from P1 and ends at P2: The center point at the border of the blackness dashed avatar bounds
RectF. - Then, starting from the current point, P2, add an arc in the upper- half region of the avatar bounds: The arc starts from the angle
-180degrees and sweeps past180degrees catastrophe in P3.
Yous passfakeas the last parameter so y'all don't start a new sub-path for the arc. This tells Android that yous want the arc on the aforementioned path. - You lot add a straight line that starts from the current point and ends at the given point, the bottom-correct corner. This adds a line from P3 to P4.
- Then, y'all add together a directly line that starts from the current point and ends at the given bespeak, the elevation-right corner, adding a line from P4 to P5.
- You add a quadratic Bézier bend that starts from the electric current point, P5, and ends at the bottom-left corner, P1, using the handle point you created in step ii.
- Finally, you lot close the path, even though information technology's not required this fourth dimension since you are back at the get-go point on the path.
- Yous draw
curvePathon the canvas by passing information technology todrawPath()along with thepigmentobject.
Finalizing the Curve
Y'all're almost finished creating the curve. In ProfileCardPainter, get to the last line in paint() and add the following code:
//1 val curvedShapeBounds = RectFFactory.fromLTRB( shapeBounds.left, shapeBounds.peak + shapeBounds.height() * 0.35f, shapeBounds.correct, shapeBounds.bottom ) //2 drawCurvedShape(canvas, curvedShapeBounds, avatarBounds) Here, you:
- Create a
RectFthat is similar to theshapeBoundsrect, except you've shifted its acme slightly to the bottom past 35% of theshapeBounds' top: This is the crimson dashedRectFin the image higher up. - Telephone call
drawCurvedShape()and pass thecanvassobject, the curved shape bounds and the avatar bounds to information technology.
Build and run the app to see the neat background curve behind the avatar:
So you're done, correct? Almost. There's still one more finishing touch you need to add together.
Adding Slope Paint
Y'all've created your first beautiful, custom curved shape, merely your graphic designer wants you to practise one more than matter: Add together slope colors to your curved shape.
There are different types of shaders or gradients, including linear gradients, which transition through at least two colors in a directly line, and radial gradients, which transition through colors starting from a central point and radiating outward.
Correct now, y'all'll create a shader, a linear gradient described past three colors. Each color needs a cease to specify its position on a line from 0.0 to 1.0.
Start by creating a new office chosen createGradient() inside ProfileCardPainter with the post-obit code:
individual fun createGradient(bounds: RectF): LinearGradient { //one val colors = intArrayOf(color.darkerShade(), color, color.darkerShade()) //2 val stops = floatArrayOf(0.0f, 0.3f, ane.0f) //3 return LinearGradient( bounds.centerLeft.x, premises.centerLeft.y, bounds.centerRight.ten, premises.centerRight.y, colors, stops, Shader.TileMode.REPEAT ) } Hither's what'south going on in this code:
- You create a list of three colors, where the heart color is the profile color and the first and last colors are darker shades of that contour color.
- And so you lot create a list of three stops. The beginning is 0.0, which puts the corresponding color in the colors list at the zip position of the gradient colour. In the same way, the middle and the stops specify the positions of their respective colors in the color list.
- Finally, yous create a linear gradient by passing the start coordinates and the end coordinates of the gradient with the given colors and stops, and the shader TileMode to repeat the gradient in case the area which yous fill up is larger than the shader yous created.
Now go to drawCurvedShape() and update the paint object to use the new linear gradient instead of a solid color.
Supplant this line:
paint.color = color.darkerShade() With this one:
paint.shader = createGradient(bounds) Here, you create a new gradient and prepare it to the paint object.
Finally, build and run the app to come across a gradient within the groundwork bend:
Congratulations! You've created a beautiful contour card with an centre-catching custom background shape and shading.
Where to Go From Here?
Y'all can download the completed concluding projection using the Download Materials button at the summit or bottom of the tutorial.
Wow, that was a lot of work! But you learned a lot, too. In addition to taking a deep wait at Canvas and many Android Graphics APIs, you learned how to:
- Prepare your custom shape on newspaper before coding.
- Use
Pathand how to add different lines to it sequentially. - Draw a curved shape in gradient colors.
To learn more virtually Canvas and Android custom views bank check out the following links:
- Android Custom View Tutorial.
- Making your drawing Interactive.
- Custom Android Compound View.
Too, you lot can cheque RichPath library. Information technology's an open-source library that gives y'all total control over your custom shapes in vector drawable format so you lot can dispense and animate them easily at runtime.
Experience free to share your feedback, comments or enquire questions in the forum below. Don't stop cartoon. ;]
Source: https://www.raywenderlich.com/9556022-drawing-custom-shapes-in-android
0 Response to "Draw a Circle Android Drawable"
Post a Comment