Skip to content

Commit 45684d1

Browse files
authored
Merge pull request #16 from android/feature/image-snippets
Add image snippets
2 parents 2f5fab1 + fc5f02a commit 45684d1

File tree

11 files changed

+641
-2
lines changed

11 files changed

+641
-2
lines changed

compose/snippets/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ android {
4949
dependencies {
5050
def composeBom = platform('androidx.compose:compose-bom:2022.11.00')
5151
implementation(composeBom)
52-
52+
implementation("io.coil-kt:coil-compose:2.2.2")
5353
implementation 'androidx.core:core-ktx:1.9.0'
5454
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.5.1'
5555
implementation 'androidx.activity:activity-compose:1.6.1'

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,15 @@ package com.example.compose.snippets
1616
import android.os.Bundle
1717
import androidx.activity.ComponentActivity
1818
import androidx.activity.compose.setContent
19+
import androidx.compose.foundation.layout.Column
1920
import androidx.compose.foundation.layout.fillMaxSize
21+
import androidx.compose.foundation.rememberScrollState
22+
import androidx.compose.foundation.verticalScroll
2023
import androidx.compose.material3.MaterialTheme
2124
import androidx.compose.material3.Surface
2225
import androidx.compose.ui.Modifier
2326
import com.example.compose.snippets.graphics.BrushExamplesScreen
27+
import com.example.compose.snippets.images.ImageExamplesScreen
2428
import com.example.compose.snippets.ui.theme.SnippetsTheme
2529

2630
class SnippetsActivity : ComponentActivity() {
@@ -33,7 +37,12 @@ class SnippetsActivity : ComponentActivity() {
3337
modifier = Modifier.fillMaxSize(),
3438
color = MaterialTheme.colorScheme.background
3539
) {
36-
BrushExamplesScreen()
40+
// TODO - We should put these in different navigation destinations
41+
Column(modifier = Modifier
42+
.fillMaxSize()) {
43+
// BrushExamplesScreen()
44+
ImageExamplesScreen()
45+
}
3746
}
3847
}
3948
}
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
package com.example.compose.snippets.images
2+
3+
import androidx.compose.foundation.Image
4+
import androidx.compose.foundation.background
5+
import androidx.compose.foundation.layout.Box
6+
import androidx.compose.foundation.layout.padding
7+
import androidx.compose.foundation.layout.wrapContentSize
8+
import androidx.compose.runtime.Composable
9+
import androidx.compose.runtime.remember
10+
import androidx.compose.ui.Modifier
11+
import androidx.compose.ui.draw.paint
12+
import androidx.compose.ui.geometry.Size
13+
import androidx.compose.ui.graphics.BlendMode
14+
import androidx.compose.ui.graphics.Color
15+
import androidx.compose.ui.graphics.ImageBitmap
16+
import androidx.compose.ui.graphics.drawscope.DrawScope
17+
import androidx.compose.ui.graphics.painter.Painter
18+
import androidx.compose.ui.layout.ContentScale
19+
import androidx.compose.ui.res.imageResource
20+
import androidx.compose.ui.res.stringResource
21+
import androidx.compose.ui.tooling.preview.Preview
22+
import androidx.compose.ui.unit.IntOffset
23+
import androidx.compose.ui.unit.IntSize
24+
import androidx.compose.ui.unit.dp
25+
import androidx.compose.ui.unit.toSize
26+
import com.example.compose.snippets.R
27+
import kotlin.math.roundToInt
28+
29+
/*
30+
* Copyright 2022 The Android Open Source Project
31+
*
32+
* Licensed under the Apache License, Version 2.0 (the "License");
33+
* you may not use this file except in compliance with the License.
34+
* You may obtain a copy of the License at
35+
*
36+
* http://www.apache.org/licenses/LICENSE-2.0
37+
*
38+
* Unless required by applicable law or agreed to in writing, software
39+
* distributed under the License is distributed on an "AS IS" BASIS,
40+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
41+
* See the License for the specific language governing permissions and
42+
* limitations under the License.
43+
*/
44+
@Preview
45+
@Composable
46+
fun CustomPainterUsage() {
47+
// [START android_compose_images_custom_painter_usage]
48+
val rainbowImage = ImageBitmap.imageResource(id = R.drawable.rainbow)
49+
val dogImage = ImageBitmap.imageResource(id = R.drawable.dog)
50+
val customPainter = remember {
51+
OverlayImagePainter(dogImage, rainbowImage)
52+
}
53+
Image(
54+
painter = customPainter,
55+
contentDescription = stringResource(id = R.string.dog_content_description),
56+
contentScale = ContentScale.Crop,
57+
modifier = Modifier.wrapContentSize()
58+
)
59+
// [END android_compose_images_custom_painter_usage]
60+
}
61+
62+
// [START android_compose_images_custom_painter]
63+
class OverlayImagePainter constructor(
64+
private val image: ImageBitmap,
65+
private val imageOverlay: ImageBitmap,
66+
private val srcOffset: IntOffset = IntOffset.Zero,
67+
private val srcSize: IntSize = IntSize(image.width, image.height),
68+
private val overlaySize: IntSize = IntSize(imageOverlay.width, imageOverlay.height)
69+
) : Painter() {
70+
71+
private val size: IntSize = validateSize(srcOffset, srcSize)
72+
override fun DrawScope.onDraw() {
73+
// draw the first image without any blend mode
74+
drawImage(
75+
image,
76+
srcOffset,
77+
srcSize,
78+
dstSize = IntSize(
79+
this@onDraw.size.width.roundToInt(),
80+
this@onDraw.size.height.roundToInt()
81+
)
82+
)
83+
// draw the second image with an Overlay blend mode to blend the two together
84+
drawImage(
85+
imageOverlay,
86+
srcOffset,
87+
overlaySize,
88+
dstSize = IntSize(
89+
this@onDraw.size.width.roundToInt(),
90+
this@onDraw.size.height.roundToInt()
91+
),
92+
blendMode = BlendMode.Overlay
93+
)
94+
}
95+
96+
/**
97+
* Return the dimension of the underlying [ImageBitmap] as it's intrinsic width and height
98+
*/
99+
override val intrinsicSize: Size get() = size.toSize()
100+
101+
private fun validateSize(srcOffset: IntOffset, srcSize: IntSize): IntSize {
102+
require(
103+
srcOffset.x >= 0 &&
104+
srcOffset.y >= 0 &&
105+
srcSize.width >= 0 &&
106+
srcSize.height >= 0 &&
107+
srcSize.width <= image.width &&
108+
srcSize.height <= image.height
109+
)
110+
return srcSize
111+
}
112+
}
113+
// [END android_compose_images_custom_painter]
114+
115+
@Preview
116+
@Composable
117+
fun CustomPainterModifier() {
118+
// [START android_compose_custom_painter_modifier]
119+
val rainbowImage = ImageBitmap.imageResource(id = R.drawable.rainbow)
120+
val dogImage = ImageBitmap.imageResource(id = R.drawable.dog)
121+
val customPainter = remember {
122+
OverlayImagePainter(dogImage, rainbowImage)
123+
}
124+
Box(
125+
modifier =
126+
Modifier.background(color = Color.Gray)
127+
.padding(30.dp)
128+
.background(color = Color.Yellow)
129+
.paint(customPainter)
130+
) { /** intentionally empty **/ }
131+
// [END android_compose_custom_painter_modifier]
132+
}

0 commit comments

Comments
 (0)