Awesome
<a href="https://getstream.io/chat/compose/tutorial/?utm_source=Github&utm_campaign=Devrel_oss&utm_medium=sketchbook"><img src="https://user-images.githubusercontent.com/24237865/155820258-1a80aaa3-2855-41a9-9cbe-bfde5483b7ca.png" /></a><br><br>
<p align="center"> <a href="https://devlibrary.withgoogle.com/products/android/repos/GetStream-sketchbook-compose"><img alt="Google" src="https://skydoves.github.io/badges/google-devlib.svg"/></a><br> <a href="https://opensource.org/licenses/Apache-2.0"><img alt="License" src="https://img.shields.io/badge/License-Apache%202.0-blue.svg"/></a> <a href="https://android-arsenal.com/api?level=21"><img alt="API" src="https://img.shields.io/badge/API-21%2B-brightgreen.svg?style=flat"/></a> <a href="https://github.com/GetStream/sketchbook-compose/actions/workflows/android.yml"><img alt="Build Status" src="https://github.com/GetStream/sketchbook-compose/actions/workflows/android.yml/badge.svg"/></a> <a href="https://androidweekly.net/issues/issue-507"><img alt="Android Weekly" src="https://skydoves.github.io/badges/android-weekly.svg"/></a> <a href="https://getstream.github.io/sketchbook-compose/"><img alt="Dokka" src="preview/dokka-badge.svg"/></a> </p><br> <p align="center"> 🎨 Jetpack Compose canvas library that helps you draw paths and images on canvas with color pickers and palettes. Sketchbook also provides useful components and functions that can easily interact with canvas. </p><br>Preview
<p align="center"> <img src="https://user-images.githubusercontent.com/24237865/154213747-438e4e27-57d8-4fe2-98bd-e29d89a6bb8c.gif" width="270"/> <img src="https://user-images.githubusercontent.com/24237865/154213763-47af36de-61b3-446e-9d6c-563bae87bfda.gif" width="270"/> <img src="/preview/preview1.gif" width="270"/> </p><a href="https://getstream.io/chat/compose/tutorial/?utm_source=Github&utm_campaign=Devrel_oss&utm_medium=sketchbook"><img src="https://user-images.githubusercontent.com/24237865/138428440-b92e5fb7-89f8-41aa-96b1-71a5486c5849.png" align="right" width="13%"/></a>
Contribution 💙
Sketchbook is maintained by Stream. If you’re interested in adding powerful In-App Messaging to your app, check out the Stream Chat Tutorial for Jetpack Compose! Also, anyone can contribute to improving code, docs, or something following our Contributing Guideline.
Download
Gradle
Add the dependency below to your module's build.gradle
file:
dependencies {
implementation "io.getstream:sketchbook:1.0.4"
}
SNAPSHOT
<details> <summary>See how to import the snapshot</summary>Including the SNAPSHOT
Snapshots of the current development version of Sketchbook are available, which track the latest versions.
To import snapshot versions on your project, add the code snippet below on your gradle file.
repositories {
maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
}
Next, add the below dependency to your module's build.gradle
file.
dependencies {
implementation "io.getstream:sketchbook:1.0.5-SNAPSHOT"
}
</details>
Usage
First, you should initialize SketchbookController
, which allows you to control the Sketchbook
and all components.
private val sketchbookController = rememberSketchbookController()
Next, you can implement your drawing canvas with the Sketchbook
composable function:
Sketchbook(
modifier = Modifier.fillMaxSize(),
controller = sketchbookController,
backgroundColor = Color.White
)
Sketchbook
Sketchbook implements canvas, which allows you to draw paths with custom properties. It interacts with SketchbookController to control other components.
You can use the Sketchbook
as the following example:
Sketchbook(
modifier = Modifier.fillMaxSize(),
controller = sketchbookController,
backgroundColor = Color.White,
onEventListener = { x, y -> .. },
onRevisedListener = { canUndo, canRedo -> .. }
)
SketchbookController
SketchbookController interacts with Sketchbook
and it allows you to control the canvas and all of the components with it.
Undo and Redo
SketchbookController
supports undo
and redo
to cancel or reverse drawn paths and recover the previous canvas state.
You can implement it with the following functions below:
sketchbookController.undo() // undo the drawn path if possible.
sketchbookController.redo() // redo the drawn path if possible.
<img src="https://user-images.githubusercontent.com/24237865/154213789-c5f6b885-e890-44d2-91b8-81e09177f678.gif" width="270" align="right" />
Erase Mode
By enabling Erase Mode, you can erase the colored paths following the transparent path. You can set the mode with the function below:
sketchbookController.setEraseMode(true)
Also, you can toggle the erase mode with the following function below:
sketchbookController.toggleEraseMode()
You can get the State
of the erase mode with the following function below:
val isEraseMode = sketchbookController.isEraseMode.value
Note: If you use the erase mode, make sure you set the
backgroundColor
on theSketchbook
properly.
You can changes the radius size of the erase circle:
sketchbookController.setEraseRadius(50f)
<img src="https://user-images.githubusercontent.com/24237865/154213763-47af36de-61b3-446e-9d6c-563bae87bfda.gif" width="270" align="right" />
Customize Paint
You can custom the paint to support various drawing options as the following:
.setPaintColor(color)
.setPaintAlpha(alpha)
.setPaintStrokeWidth(stroke)
.setPaintShader(shader)
.setLinearShader(colorList)
.setPaintingStyle(paintStyle)
.setPathEffect(pathEffect)
Also, you can set your own paint with the setPaint
method:
sketchbookController.setPaint(paint)
You can set the rainbow shader to the paint with the setRainbowShader
method:
sketchbookController.setRainbowShader()
ImageBitmap
<img src="/preview/preview1.gif" width="27%" align="right" />Sketchbook supports to set an ImageBitmp
on the canvas and draw paths over the bitmap. You can set an initial ImageBitmap
on the Sketchbook
composable as the following:
Sketchbook(
imageBitmap = ImageBitmap.imageResource(R.drawable.poster),
..
)
Also, you can set an ImageBitmap
dynamically with the SketchbookController
as the following:
sketchbookController.setImageBitmap(imageBitmap)
You can clear the image bitmap on canvas with the clearImageBitmap
method:
sketchbookController.clearImageBitmap()
Note: This demo project demonstrates an image picker with ModernStorage's Photo Picker.
Sketchbook Bitmap
You can get the final ImageBitmap
of the current canvas of the Sketchbook
with the following:
val imageBitmap = sketchbookController.getSketchbookBitmap()
If you'd like to get the Android's bitmap, you can get it as the following:
val bitmap = sketchbookController.getSketchbookBitmap().asAndroidBitmap()
Clear
You can clear all the drawn paths and paths and the image bitmap as the following:
sketchbookController.clear()
Also, you can clear only the drawn paths and redo paths as the following:
sketchbookController.clearPaths()
PaintColorPalette
<img src="/preview/preview0.png" align="right" width="300">PaintColorPalette provides a color palette to let users choose desired colors from a provided color list. It provides default color palettes and shapes, which are fully customizable. You can simply implement this as the following example:
PaintColorPalette(
controller = sketchbookController,
borderColor = MaterialTheme.colors.onPrimary
)
You can customize UI themes with PaintColorPaletteTheme
as the following example:
PaintColorPalette(
theme = PaintColorPaletteTheme(
shape = CircleShape,
itemSize = 48.dp,
selectedItemSize = 58.dp,
borderColor = Color.White,
borderWidth = 2.dp,
borderColor = MaterialTheme.colors.onPrimary
),
Also, you can set an index for selecting a color initially with the initialSelectedIndex
parameter:
initialSelectedIndex = 2
onColorSelected
You can track the selected color's index and color value with the onColorSelected
listener:
PaintColorPalette(
onColorSelected = { index, color -> .. },
)
Header and Footer
You can add your own composable on the very first of the palette or on the end as the following example:
PaintColorPalette(
header = { Text("Header") },
footer = { Text("Footer") }
)
Custom Content
You can customize the entire content with your own composable as the following example:
PaintColorPalette(
content = { index, color ->
Box(modifier = Modifier
.size(60.dp)
.background(color)
.clickable { .. }
)
}
)
<img src="https://user-images.githubusercontent.com/24237865/154215023-14c50460-f55d-417e-b11a-a6e3961c864c.gif" align="right" width="300" />Note: Make sure if you use the custom content, you should implement all interactions and listeners by yourself.
ColorPickerDialog
Sketchbook supports ColorPickerDialog
, which lets you choose your desired color from an HSV color palette.
You can implement ColorPickerDialog
with the following codes:
val expandColorPickerDialog = remember { mutableStateOf(false) }
Image(
modifier =
Modifier.clickable { expandColorPickerDialog.value = true },
bitmap = ImageBitmap.imageResource(R.drawable.palette),
contentDescription = null
)
ColorPickerDialog(
controller = sketchbookController,
expanded = expandColorPickerDialog,
initialColor = controller.currentPaintColor.value,
onColorSelected = { color ->
controller.setPaintShader(null)
controller.setSelectedColorIndex(-1)
}
)
ColorPickerPaletteIcon
ColorPickerPaletteIcon
implements the example code above internally, so you can use like an icon, which shows up a color picker dialog as the following example:
ColorPickerPaletteIcon(
modifier = Modifier
.size(60.dp)
.padding(6.dp),
controller = sketchbookController,
bitmap = ImageBitmap.imageResource(R.drawable.palette)
)
You can use the ColorPickerPaletteIcon
with hearder
or footer
custom composable for the PaintColorPalette
.
PaintColorPalette(
header = {
ColorPickerPaletteIcon(
..
)
}
)
<a href="https://getstream.io/chat/compose/tutorial/?utm_source=Github&utm_campaign=Devrel_oss&utm_medium=sketchbook"><img src="https://user-images.githubusercontent.com/24237865/146505581-a79e8f7d-6eda-4611-b41a-d60f0189e7d4.jpeg" align="right" /></a>
Find this library useful? :heart:
Support it by joining stargazers for this repository. :star: <br> Also, follow Stream on Twitter for our next creations!
License
Copyright 2022 Stream.IO, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.