Blog Infos
Author
Published
Topics
,
Published

There are multiple ways of doing the same thing. You choose which way to go.

 

Image by New18

 

The article covers how can we create a bottom sheet with round corners via XML and Canvas separately. Let’s see what we’re going to build.

First, let’s take the XML approach which is very straightforward to use. We simply create a rectangle shape with top left and right corners with some radius as follows.

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/white" />
<corners android:topLeftRadius="25dp" android:topRightRadius="25dp" />
</shape>

background_curved_corners.xml

 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/curvedContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/button_selector"
android:orientation="horizontal">
</LinearLayout>

dialog_curved_corners.xml

 

So far so good and we’re ready with our target. But we encounter an issue which you can easily spot in the image below.

 

Bottom sheet with round corners

 

class CurvedContainer @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
): LinearLayout(context, attrs, defStyleAttr) {
/* paint object for coloring the canvas */
private val mPaint = Paint()
/* path that will be drawn to achieve the shape */
private val path = Path()
/* arcs will create the effect of curved corners */
private val leftArc = RectF()
private val rightArc = RectF()
/* offset values for our curved corners */
private val xAxisOffset = 100f
private val yAxisOffset = 100f
init {
/* setting the background as transparent as we're drawing the view ourself */
setBackgroundColor(Color.TRANSPARENT)
setLayerType(View.LAYER_TYPE_HARDWARE, null)
mPaint.apply {
style = Paint.Style.FILL
color = Color.WHITE
isAntiAlias = true
clipChildren = true
}
}
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
super.onSizeChanged(w, h, oldw, oldh)
}
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
}
}

CurvedContainer.kt

Job Offers

Job Offers


    Android Engineer

    American Express
    Phoenix, USA
    • Full Time
    apply now

    (Senior) Android Developer – Machine Learning (w/m/d)

    Paradox Cat GmbH
    Munich
    • Full Time
    apply now

    API Engineer

    American Express
    New York, USA
    • Full Time
    apply now
Load more listings

OUR VIDEO RECOMMENDATION

, ,

The Evolution of Android Graphics in Android 12/13

Android 12 and 13 both added significant new capabilities to Android platform graphics, including RenderEffect, RuntimeShader, and more. At the same time, RenderScript has been deprecated and we’ve introduced the RenderScript Intrinsics Replacement Toolkit. This…
Watch Video

The Evolution of Android Graphics in Android 12/13

Daniel Galpin
Android Developer Advocate and Fast Talking YouTuber
Google

The Evolution of Android Graphics in Android 12/13

Daniel Galpin
Android Developer Ad ...
Google

The Evolution of Android Graphics in Android 12/13

Daniel Galpin
Android Developer Advocat ...
Google

Jobs

What are we doing here? We’ll draw a path and paint the enclosed area of the path. Simple! Below image shows how the path actually looks like if we simply draw it using stroke/border.

 

path with style STROKE

 

The blue line indicates our path and the points indicates the position we’re drawing our path on, in a linear clockwise fashion. We’ll create the path once we know the size of our view i.e. in onSizeChanged function.

override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
super.onSizeChanged(w, h, oldw, oldh)
/* curve from P1 to P2 */
leftArc.set(
0f,
0f,
xAxisOffset,
yAxisOffset
)
path.addArc(leftArc, 180f, 90f)
/* line from P2 to P3 */
path.lineTo(w.toFloat() - (xAxisOffset * 0.5f), 0f)
/* curve from P3 to P4 */
rightArc.set(
w.toFloat() - (xAxisOffset),
0f,
w.toFloat(),
yAxisOffset
)
path.addArc(rightArc, 270f, 90f)
/* line from P4 to P5 */
path.lineTo(w.toFloat(), h.toFloat())
/* line from P5 to P6 */
path.lineTo(0f, h.toFloat())
/* line from P6 to P1 */
path.lineTo(0f, yAxisOffset - (yAxisOffset / 2))
path.close()
}

function onSizeChanged

 

It is evident that we’re drawing our path step by step from one point to other and finally completing the path to the point P1 from where we started. This way we get our curved shape. And once we’ve our path ready, we’ll draw it on our canvas in onDraw function as follows:

override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
canvas?.drawPath(path, mPaint)
}
view raw onDraw.kt hosted with ❤ by GitHub
<style name="TransparentBackgroundDialog" parent="Theme.Design.Light.BottomSheetDialog">
<item name="android:colorBackground">@android:color/transparent</item>
</style>

We’ll set this style to our bottom sheet dialog so that it won’t draw any color to our custom view by setting the color background to transparent.

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setStyle(STYLE_NORMAL, R.style.TransparentBackgroundDialog)
}
view raw onCreate.kt hosted with ❤ by GitHub

BottomSheetContainer.kt

This article was originally published on proandroiddev.com on March 06, 2022

YOU MAY BE INTERESTED IN

YOU MAY BE INTERESTED IN

blog

How to animate BottomSheet content using Jetpack Compose

Early this year I started a new pet project for listening to random radio…
READ MORE
blog
UI created with XML is traditionally tested with Espresso and UIAutomator. However, Jetpack Compose…
READ MORE

Leave a Reply

Your email address will not be published.

Fill out this field
Fill out this field
Please enter a valid email address.

Menu