How to Create a Signature Draw View in Jetpack Compose and Save It as a Drawable

Zahid Muneer
3 min readSep 19, 2024

--

Jetpack Compose makes building UIs for Android simpler and more efficient. One interesting UI component you might need is a signature draw view, where users can sign on the screen. In this article, we’ll walk through creating a signature box using Jetpack Compose and show how to save the signature as a drawable.

Screenshot of Final view

Prerequisites

  • Basic understanding of Jetpack Compose
  • Familiarity with StateFlow and Jetpack Compose State
  • Basic knowledge of drawing on Canvas using Compose

Step 1: Setting up the Signature Box Composable

We start by creating the SignatureBox composable function, which contains a Canvas for capturing the user’s signature along with other UI elements.

@Composable
fun SignatureBox(
) {
val path by remember { mutableStateOf(Path()) }
var saveBitmap by remember { mutableStateOf(false) }
var isSigned by remember { mutableStateOf(false) }
var currentPosition by remember { mutableStateOf(Offset.Unspecified) }
val density = LocalDensity.current
val canvasHeight = 300.dp
var bitmap by remember { mutableStateOf<Bitmap?>(null) }

Explanation

  • We define a Path to capture the signature strokes and use mutableStateOf to manage states like saveBitmap, isSigned, bitmap, and currentPosition.

Step 2: Creating the Signature Drawing Canvas

Here, we set up the UI and include the Canvas component to allow users to draw their signatures using touch gestures.

    Scaffold(
topBar = {
//your App bar here
}
) {
Column(
Modifier
.padding(it)
.fillMaxWidth()
.padding(start = 16.dp, end = 16.dp)
.verticalScroll(state = rememberScrollState(), enabled = true)
) {

Text(
text = stringResource(R.string.please_sign_in_the_box_below),
style = MaterialTheme.typography.titleMedium
)
Canvas(
modifier = Modifier
.fillMaxWidth()
.height(canvasHeight)
.background(AppColors.whiteColor, RoundedCornerShape(4.dp))
.border(1.dp, AppColors.grayCommonColor, RoundedCornerShape(4.dp))
.clipToBounds()
.pointerInput(true) {
detectDragGestures(
onDragStart = { offset ->
path.moveTo(offset.x, offset.y)
isSigned = true
currentPosition = offset
},
onDrag = { change, _ ->
path.lineTo(change.position.x, change.position.y)
currentPosition = change.position
isSigned = true
}
)
}
) {
if (currentPosition != Offset.Unspecified) {
drawPath(
path = path,
color = AppColors.onPrimaryColor,
style = Stroke(
width = 4.dp.toPx(),
cap = StrokeCap.Round,
join = StrokeJoin.Round
)
)
}
if (saveBitmap) {
// create and save bitmap in remeber variable
onEvent(
bitmap = createSignatureBitmap(
path,
size.width,
with(density) { canvasHeight.toPx() }.toInt()
)
)
saveBitmap = false
}
}
RoundedBorderCenteredContentCorneredButton(buttonText = stringResource(id = R.string.done)) {
if (isSigned) saveBitmap = true
// Custom Button, you can create your own button here
}

Explanation

  • Canvas: A Canvas with a defined size is used to draw the signature.
  • pointerInput: The pointerInput modifier captures the user's touch gestures to draw the path.
  • onDragStart initializes the Path at the touch's starting point.
  • onDrag draws lines as the user's finger moves, creating the signature.
  • drawPath: The path is drawn on the canvas whenever the user interacts with it.
  • Save Bitmap: If saveBitmap is true, the signature is converted into a bitmap using the createSignatureBitmap function.

Step 3: Create Signature Bitmap

private fun createSignatureBitmap(
path: Path,
width: Float,
height: Int,
): Bitmap {
val bitmap = Bitmap.createBitmap(
width.roundToInt(),
height,
Bitmap.Config.ARGB_8888
)

// Create a Canvas to draw on the Bitmap
val canvas = android.graphics.Canvas(bitmap)
canvas.drawColor(android.graphics.Color.WHITE)

// Set up paint for the drawing
val paint = Paint().apply {
color = android.graphics.Color.BLACK
style = Paint.Style.STROKE
strokeCap = Paint.Cap.ROUND
strokeJoin = Paint.Join.ROUND
}

// Draw the signature path onto the Android Canvas
canvas.drawPath(path.asAndroidPath(), paint)

return bitmap
}

Explanation

  • Creates a blank bitmap with the specified width and height.
  • Initializes a Canvas for drawing on the bitmap.
  • Sets up a Paint object to define the stroke color and style.
  • Uses drawPath to render the signature on the canvas.
  • Returns the bitmap containing the drawn signature.

Wrapping Up

In this article, we covered how to create a signature draw view using Jetpack Compose’s Canvas and gestures. Additionally, we demonstrated how to convert the drawn signature into a Bitmap that can be uploaded or saved locally.

This SignatureBox component can be further customized and integrated into various applications, such as accepting terms and conditions or signing waivers in fitness apps. Happy coding!

--

--