Skip to content

Commit 2489cb2

Browse files
juchengchoucartlandkhufdevcompose-devrel-github-bot
authored
feat(scalable content): add code snippets (#656)
* feat(scalable content): add code snippets Refer to go/ptz-compose-snippets-wip we put the code onto github then we can use them for new DAC page. * Remove project code style configuration (#661) * feat(scalable content): add code snippets Refer to go/ptz-compose-snippets-wip we put the code onto github then we can use them for new DAC page. * 🤖 Update Dependencies (#675) * feat(scalable content): add code snippets Refer to go/ptz-compose-snippets-wip we put the code onto github then we can use them for new DAC page. --------- Co-authored-by: Christopher Cartland <[email protected]> Co-authored-by: Kevin <[email protected]> Co-authored-by: compose-devrel-github-bot <[email protected]>
1 parent ca6cdec commit 2489cb2

File tree

1 file changed

+196
-0
lines changed

1 file changed

+196
-0
lines changed
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
/*
2+
* Copyright 2025 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.example.compose.snippets.accessibility
18+
19+
import androidx.compose.foundation.background
20+
import androidx.compose.foundation.gestures.TransformableState
21+
import androidx.compose.foundation.gestures.transformable
22+
import androidx.compose.foundation.layout.Arrangement
23+
import androidx.compose.foundation.layout.Box
24+
import androidx.compose.foundation.layout.Column
25+
import androidx.compose.foundation.layout.Row
26+
import androidx.compose.foundation.layout.Spacer
27+
import androidx.compose.foundation.layout.fillMaxSize
28+
import androidx.compose.foundation.layout.fillMaxWidth
29+
import androidx.compose.foundation.layout.height
30+
import androidx.compose.foundation.layout.padding
31+
import androidx.compose.foundation.layout.size
32+
import androidx.compose.foundation.layout.width
33+
import androidx.compose.foundation.shape.RoundedCornerShape
34+
import androidx.compose.material.icons.Icons
35+
import androidx.compose.material.icons.filled.Person
36+
import androidx.compose.material3.Card
37+
import androidx.compose.material3.Icon
38+
import androidx.compose.material3.MaterialTheme
39+
import androidx.compose.material3.Switch
40+
import androidx.compose.material3.Text
41+
import androidx.compose.runtime.Composable
42+
import androidx.compose.runtime.CompositionLocalProvider
43+
import androidx.compose.runtime.getValue
44+
import androidx.compose.runtime.mutableFloatStateOf
45+
import androidx.compose.runtime.mutableStateOf
46+
import androidx.compose.runtime.remember
47+
import androidx.compose.runtime.setValue
48+
import androidx.compose.ui.Alignment
49+
import androidx.compose.ui.Modifier
50+
import androidx.compose.ui.graphics.Color
51+
import androidx.compose.ui.platform.LocalDensity
52+
import androidx.compose.ui.text.style.TextAlign
53+
import androidx.compose.ui.tooling.preview.Preview
54+
import androidx.compose.ui.unit.Density
55+
import androidx.compose.ui.unit.dp
56+
57+
// [START android_compose_accessibility_scalable_content_density_scaling]
58+
private class DensityScalingState(
59+
// Note: For accessibility, typical min/max values are ~0.75x and ~3.5x.
60+
private val minScale: Float = 0.75f,
61+
private val maxScale: Float = 3.5f,
62+
private val currentDensity: Density
63+
) {
64+
val transformableState = TransformableState { zoomChange, _, _ ->
65+
scaleFactor.floatValue =
66+
(scaleFactor.floatValue * zoomChange).coerceIn(minScale, maxScale)
67+
}
68+
val scaleFactor = mutableFloatStateOf(1f)
69+
fun scaledDensity(): Density {
70+
return Density(
71+
currentDensity.density * scaleFactor.floatValue,
72+
currentDensity.fontScale
73+
)
74+
}
75+
}
76+
77+
// [START_EXCLUDE silent]
78+
@Preview
79+
// [END_EXCLUDE silent]
80+
@Composable
81+
fun DensityScalingSample() {
82+
val currentDensity = LocalDensity.current
83+
val scaleState =
84+
remember(currentDensity) { DensityScalingState(currentDensity = currentDensity) }
85+
86+
Box(
87+
modifier = Modifier
88+
.fillMaxSize()
89+
.transformable(state = scaleState.transformableState),
90+
contentAlignment = Alignment.TopCenter
91+
) {
92+
CompositionLocalProvider(
93+
LocalDensity provides scaleState.scaledDensity()
94+
) {
95+
DemoCard()
96+
}
97+
}
98+
}
99+
// [END android_compose_accessibility_scalable_content_density_scaling]
100+
101+
// [START android_compose_accessibility_scalable_content_font_scaling]
102+
class FontScaleState(
103+
// Note: For accessibility, typical min/max values are ~0.75x and ~3.5x.
104+
private val minScale: Float = 0.75f,
105+
private val maxScale: Float = 3.5f,
106+
private val currentDensity: Density
107+
) {
108+
val transformableState = TransformableState { zoomChange, _, _ ->
109+
scaleFactor.floatValue =
110+
(scaleFactor.floatValue * zoomChange).coerceIn(minScale, maxScale)
111+
}
112+
val scaleFactor = mutableFloatStateOf(1f)
113+
fun scaledFont(): Density {
114+
return Density(
115+
currentDensity.density,
116+
currentDensity.fontScale * scaleFactor.floatValue
117+
)
118+
}
119+
}
120+
121+
// [START_EXCLUDE silent]
122+
@Preview
123+
// [END_EXCLUDE silent]
124+
@Composable
125+
fun FontScalingSample() {
126+
val currentDensity = LocalDensity.current
127+
val scaleState = remember { FontScaleState(currentDensity = currentDensity) }
128+
129+
Box(
130+
modifier = Modifier
131+
.fillMaxSize()
132+
.transformable(state = scaleState.transformableState),
133+
contentAlignment = Alignment.TopCenter
134+
) {
135+
CompositionLocalProvider(
136+
LocalDensity provides scaleState.scaledFont()
137+
) {
138+
DemoCard()
139+
}
140+
}
141+
}
142+
// [END android_compose_accessibility_scalable_content_font_scaling]
143+
144+
// [START android_compose_accessibility_scalable_content_demo_card]
145+
@Composable
146+
private fun DemoCard() {
147+
Card(
148+
modifier = Modifier
149+
.width(360.dp)
150+
.padding(16.dp),
151+
shape = RoundedCornerShape(12.dp)
152+
) {
153+
Column(
154+
modifier = Modifier.padding(16.dp),
155+
verticalArrangement = Arrangement.spacedBy(16.dp)
156+
) {
157+
Text("Demo Card", style = MaterialTheme.typography.headlineMedium)
158+
var isChecked by remember { mutableStateOf(true) }
159+
Row(verticalAlignment = Alignment.CenterVertically) {
160+
Text("Demo Switch", Modifier.weight(1f), style = MaterialTheme.typography.bodyLarge)
161+
Switch(checked = isChecked, onCheckedChange = { isChecked = it })
162+
}
163+
Row(verticalAlignment = Alignment.CenterVertically) {
164+
Icon(Icons.Filled.Person, "Icon", Modifier.size(32.dp))
165+
Spacer(Modifier.width(8.dp))
166+
Text("Demo Icon", style = MaterialTheme.typography.bodyLarge)
167+
}
168+
Row(
169+
Modifier.fillMaxWidth(),
170+
horizontalArrangement = Arrangement.SpaceBetween
171+
) {
172+
Box(
173+
Modifier
174+
.width(100.dp)
175+
.weight(1f)
176+
.height(80.dp)
177+
.background(Color.Blue)
178+
)
179+
Box(
180+
Modifier
181+
.width(100.dp)
182+
.weight(1f)
183+
.height(80.dp)
184+
.background(Color.Red)
185+
)
186+
}
187+
Text(
188+
"Demo Text: Lorem ipsum dolor sit amet, consectetur adipiscing elit," +
189+
" sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
190+
style = MaterialTheme.typography.bodyMedium,
191+
textAlign = TextAlign.Justify
192+
)
193+
}
194+
}
195+
}
196+
// [END android_compose_accessibility_scalable_content_demo_card]

0 commit comments

Comments
 (0)