Skip to content

Commit 21a691c

Browse files
Update Bitmap to image snippet to use new Graphics Layers (#254)
* Update libs.versions.toml (#251) * Replace Graphics bitmap snippets with new Graphics Layer snippets. * Replace Graphics bitmap snippets with new Graphics Layer snippets. * Apply Spotless --------- Co-authored-by: Simona <[email protected]> Co-authored-by: riggaroo <[email protected]>
1 parent a9f1084 commit 21a691c

File tree

4 files changed

+52
-56
lines changed

4 files changed

+52
-56
lines changed

compose/snippets/src/main/java/com/example/compose/snippets/SnippetsActivity.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ import com.example.compose.snippets.components.ScaffoldExample
3939
import com.example.compose.snippets.components.SliderExamples
4040
import com.example.compose.snippets.components.SwitchExamples
4141
import com.example.compose.snippets.graphics.ApplyPolygonAsClipImage
42-
import com.example.compose.snippets.graphics.BitmapFromComposableSnippet
42+
import com.example.compose.snippets.graphics.BitmapFromComposableFullSnippet
4343
import com.example.compose.snippets.graphics.BrushExamplesScreen
4444
import com.example.compose.snippets.images.ImageExamplesScreen
4545
import com.example.compose.snippets.landing.LandingScreen
@@ -70,7 +70,7 @@ class SnippetsActivity : ComponentActivity() {
7070
Destination.BrushExamples -> BrushExamplesScreen()
7171
Destination.ImageExamples -> ImageExamplesScreen()
7272
Destination.AnimationQuickGuideExamples -> AnimationExamplesScreen()
73-
Destination.ScreenshotExample -> BitmapFromComposableSnippet()
73+
Destination.ScreenshotExample -> BitmapFromComposableFullSnippet()
7474
Destination.ComponentsExamples -> ComponentsScreen {
7575
navController.navigate(
7676
it.route

compose/snippets/src/main/java/com/example/compose/snippets/graphics/AdvancedGraphicsSnippets.kt

Lines changed: 43 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,16 @@ import android.content.Context
2121
import android.content.Intent
2222
import android.content.Intent.createChooser
2323
import android.graphics.Bitmap
24-
import android.graphics.Picture
2524
import android.media.MediaScannerConnection
2625
import android.net.Uri
2726
import android.os.Build
2827
import android.os.Environment
2928
import android.provider.MediaStore
3029
import androidx.compose.foundation.Image
3130
import androidx.compose.foundation.background
31+
import androidx.compose.foundation.clickable
3232
import androidx.compose.foundation.layout.Arrangement
33+
import androidx.compose.foundation.layout.Box
3334
import androidx.compose.foundation.layout.Column
3435
import androidx.compose.foundation.layout.aspectRatio
3536
import androidx.compose.foundation.layout.fillMaxSize
@@ -44,18 +45,17 @@ import androidx.compose.material3.SnackbarHostState
4445
import androidx.compose.material3.SnackbarResult
4546
import androidx.compose.material3.Text
4647
import androidx.compose.runtime.Composable
47-
import androidx.compose.runtime.getValue
4848
import androidx.compose.runtime.remember
4949
import androidx.compose.runtime.rememberCoroutineScope
50-
import androidx.compose.runtime.setValue
5150
import androidx.compose.ui.Alignment
5251
import androidx.compose.ui.Modifier
5352
import androidx.compose.ui.draw.drawWithCache
53+
import androidx.compose.ui.draw.drawWithContent
5454
import androidx.compose.ui.graphics.Brush
5555
import androidx.compose.ui.graphics.Color
56-
import androidx.compose.ui.graphics.drawscope.draw
57-
import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
58-
import androidx.compose.ui.graphics.nativeCanvas
56+
import androidx.compose.ui.graphics.asAndroidBitmap
57+
import androidx.compose.ui.graphics.layer.drawLayer
58+
import androidx.compose.ui.graphics.rememberGraphicsLayer
5959
import androidx.compose.ui.layout.ContentScale
6060
import androidx.compose.ui.platform.LocalContext
6161
import androidx.compose.ui.res.painterResource
@@ -87,14 +87,44 @@ import kotlinx.coroutines.suspendCancellableCoroutine
8787
* limitations under the License.
8888
*/
8989

90+
@Preview
91+
@Composable
92+
private fun CreateBitmapFromGraphicsLayer() {
93+
// [START android_compose_graphics_layer_bitmap_basics]
94+
val coroutineScope = rememberCoroutineScope()
95+
val graphicsLayer = rememberGraphicsLayer()
96+
Box(
97+
modifier = Modifier
98+
.drawWithContent {
99+
// call record to capture the content in the graphics layer
100+
graphicsLayer.record {
101+
// draw the contents of the composable into the graphics layer
102+
this@drawWithContent.drawContent()
103+
}
104+
// draw the graphics layer on the visible canvas
105+
drawLayer(graphicsLayer)
106+
}
107+
.clickable {
108+
coroutineScope.launch {
109+
val bitmap = graphicsLayer.toImageBitmap()
110+
// do something with the newly acquired bitmap
111+
}
112+
}
113+
.background(Color.White)
114+
) {
115+
Text("Hello Android", fontSize = 26.sp)
116+
}
117+
// [END android_compose_graphics_layer_bitmap_basics]
118+
}
119+
90120
@OptIn(ExperimentalPermissionsApi::class)
91121
@Preview
92122
@Composable
93-
fun BitmapFromComposableSnippet() {
123+
fun BitmapFromComposableFullSnippet() {
94124
val context = LocalContext.current
95125
val coroutineScope = rememberCoroutineScope()
96126
val snackbarHostState = remember { SnackbarHostState() }
97-
val picture = remember { Picture() }
127+
val graphicsLayer = rememberGraphicsLayer()
98128

99129
val writeStorageAccessState = rememberMultiplePermissionsState(
100130
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
@@ -104,14 +134,15 @@ fun BitmapFromComposableSnippet() {
104134
listOf(Manifest.permission.WRITE_EXTERNAL_STORAGE)
105135
}
106136
)
137+
107138
// This logic should live in your ViewModel - trigger a side effect to invoke URI sharing.
108139
// checks permissions granted, and then saves the bitmap from a Picture that is already capturing content
109140
// and shares it with the default share sheet.
110141
fun shareBitmapFromComposable() {
111142
if (writeStorageAccessState.allPermissionsGranted) {
112143
coroutineScope.launch {
113-
val bitmap = createBitmapFromPicture(picture)
114-
val uri = bitmap.saveToDisk(context)
144+
val bitmap = graphicsLayer.toImageBitmap()
145+
val uri = bitmap.asAndroidBitmap().saveToDisk(context)
115146
shareBitmap(context, uri)
116147
}
117148
} else if (writeStorageAccessState.shouldShowRationale) {
@@ -140,39 +171,22 @@ fun BitmapFromComposableSnippet() {
140171
}
141172
}
142173
) { padding ->
143-
// [START android_compose_draw_into_bitmap]
144174
Column(
145175
modifier = Modifier
146176
.padding(padding)
147177
.fillMaxSize()
148178
.drawWithCache {
149-
// Example that shows how to redirect rendering to an Android Picture and then
150-
// draw the picture into the original destination
151-
val width = this.size.width.toInt()
152-
val height = this.size.height.toInt()
153-
154179
onDrawWithContent {
155-
val pictureCanvas =
156-
androidx.compose.ui.graphics.Canvas(
157-
picture.beginRecording(
158-
width,
159-
height
160-
)
161-
)
162-
// requires at least 1.6.0-alpha01+
163-
draw(this, this.layoutDirection, pictureCanvas, this.size) {
180+
graphicsLayer.record {
164181
this@onDrawWithContent.drawContent()
165182
}
166-
picture.endRecording()
167-
168-
drawIntoCanvas { canvas -> canvas.nativeCanvas.drawPicture(picture) }
183+
drawLayer(graphicsLayer)
169184
}
170185
}
171186

172187
) {
173188
ScreenContentToCapture()
174189
}
175-
// [END android_compose_draw_into_bitmap]
176190
}
177191
}
178192

@@ -207,25 +221,6 @@ private fun ScreenContentToCapture() {
207221
}
208222
}
209223

210-
private fun createBitmapFromPicture(picture: Picture): Bitmap {
211-
// [START android_compose_draw_into_bitmap_convert_picture]
212-
val bitmap = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
213-
Bitmap.createBitmap(picture)
214-
} else {
215-
val bitmap = Bitmap.createBitmap(
216-
picture.width,
217-
picture.height,
218-
Bitmap.Config.ARGB_8888
219-
)
220-
val canvas = android.graphics.Canvas(bitmap)
221-
canvas.drawColor(android.graphics.Color.WHITE)
222-
canvas.drawPicture(picture)
223-
bitmap
224-
}
225-
// [END android_compose_draw_into_bitmap_convert_picture]
226-
return bitmap
227-
}
228-
229224
private suspend fun Bitmap.saveToDisk(context: Context): Uri {
230225
val file = File(
231226
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),

compose/snippets/src/main/java/com/example/compose/snippets/layouts/PagerSnippets.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,7 @@ private fun CustomSnapDistance() {
426426
HorizontalPager(
427427
state = pagerState,
428428
pageSize = PageSize.Fixed(200.dp),
429-
outOfBoundsPageCount = 10,
429+
beyondViewportPageCount = 10,
430430
flingBehavior = fling
431431
) {
432432
PagerSampleItem(page = it)

gradle/libs.versions.toml

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ accompanist = "0.32.0"
33
androidGradlePlugin = "8.2.2"
44
androidx-activity-compose = "1.9.0-alpha03"
55
androidx-appcompat = "1.6.1"
6-
androidx-compose-bom = "2024.01.00"
6+
androidx-compose-bom = "2024.04.01"
7+
androidx-compose-ui-test = "1.7.0-alpha03"
78
androidx-constraintlayout = "2.1.4"
89
androidx-constraintlayout-compose = "1.0.1"
910
androidx-coordinator-layout = "1.2.0"
@@ -13,16 +14,16 @@ androidx-fragment-ktx = "1.6.2"
1314
androidx-glance-appwidget = "1.0.0"
1415
androidx-lifecycle-compose = "2.7.0"
1516
androidx-lifecycle-runtime-compose = "2.7.0"
16-
androidx-navigation = "2.7.6"
17+
androidx-navigation = "2.7.7"
1718
androidx-paging = "3.2.1"
1819
androidx-test = "1.5.0"
1920
androidx-test-espresso = "3.5.1"
20-
androidxHiltNavigationCompose = "1.1.0"
21+
androidxHiltNavigationCompose = "1.2.0"
2122
coil = "2.5.0"
2223
# @keep
2324
compileSdk = "34"
2425
compose-compiler = "1.5.4"
25-
compose-latest = "1.7.0-alpha03"
26+
compose-latest = "1.7.0-alpha07"
2627
coroutines = "1.7.3"
2728
google-maps = "18.2.0"
2829
gradle-versions = "0.51.0"
@@ -66,7 +67,7 @@ androidx-compose-runtime = { module = "androidx.compose.runtime:runtime" }
6667
androidx-compose-runtime-livedata = { module = "androidx.compose.runtime:runtime-livedata" }
6768
androidx-compose-ui = { module = "androidx.compose.ui:ui" }
6869
androidx-compose-ui-googlefonts = { module = "androidx.compose.ui:ui-text-google-fonts" }
69-
androidx-graphics-shapes = "androidx.graphics:graphics-shapes:1.0.0-alpha04"
70+
androidx-graphics-shapes = "androidx.graphics:graphics-shapes:1.0.0-alpha05"
7071
androidx-compose-ui-graphics = { module = "androidx.compose.ui:ui-graphics" }
7172
androidx-compose-ui-test = { module = "androidx.compose.ui:ui-test" }
7273
androidx-compose-ui-test-junit4 = { module = "androidx.compose.ui:ui-test-junit4" }

0 commit comments

Comments
 (0)