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.

There are multiple ways of doing the same thing. You choose which way to go. 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 Software Engineer (f/m/d)

    Paradox Cat GmbH
    Munich
    • Full Time
    apply now

    Mobile Engineer

    OLX Group
    Remote, Portugal, Spain, Romania, Poland
    • Full Time
    apply now

    Senior Android Software Engineer (f/m/d)

    Paradox Cat GmbH
    Munich
    • Full Time
    apply now

OUR VIDEO RECOMMENDATION

, ,

From Scoped Storage to Photo Picker: Everything to know about Storage

Persistence is a core element of every mobile app. Android provides different APIs to access or expose files with different tradeoffs.
Watch Video

From Scoped Storage to Photo Picker: Everything to know about Storage

Yacine Rezgui
Android developer advocate
Google

From Scoped Storage to Photo Picker: Everything to know about Storage

Yacine Rezgui
Android developer ad ...
Google

From Scoped Storage to Photo Picker: Everything to know about Storage

Yacine Rezgui
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. Required fields are marked *

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

Menu