Skip to content

Commit f4e4987

Browse files
authored
add in predictive back snippets for NavHost and predictive back handler (#394)
* add in predictive back snippets * Apply Spotless * add in basic predictivebackhandler composable example * Apply Spotless --------- Co-authored-by: trambui09 <[email protected]>
1 parent f595a0d commit f4e4987

File tree

1 file changed

+190
-0
lines changed

1 file changed

+190
-0
lines changed
Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
/*
2+
* Copyright 2024 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.predictiveback
18+
19+
import android.os.SystemClock
20+
import androidx.activity.BackEventCompat
21+
import androidx.activity.compose.PredictiveBackHandler
22+
import androidx.compose.animation.EnterTransition
23+
import androidx.compose.animation.core.Animatable
24+
import androidx.compose.animation.scaleOut
25+
import androidx.compose.foundation.background
26+
import androidx.compose.foundation.layout.Box
27+
import androidx.compose.foundation.layout.fillMaxSize
28+
import androidx.compose.material3.Surface
29+
import androidx.compose.runtime.Composable
30+
import androidx.compose.runtime.getValue
31+
import androidx.compose.runtime.mutableFloatStateOf
32+
import androidx.compose.runtime.mutableStateOf
33+
import androidx.compose.runtime.remember
34+
import androidx.compose.runtime.rememberCoroutineScope
35+
import androidx.compose.runtime.setValue
36+
import androidx.compose.ui.Modifier
37+
import androidx.compose.ui.geometry.Offset
38+
import androidx.compose.ui.graphics.Color
39+
import androidx.compose.ui.graphics.TransformOrigin
40+
import androidx.compose.ui.input.pointer.util.VelocityTracker
41+
import androidx.compose.ui.platform.LocalDensity
42+
import androidx.compose.ui.unit.dp
43+
import androidx.navigation.NavHostController
44+
import androidx.navigation.compose.NavHost
45+
import androidx.navigation.compose.composable
46+
import androidx.navigation.compose.rememberNavController
47+
import kotlin.coroutines.cancellation.CancellationException
48+
import kotlinx.coroutines.flow.Flow
49+
50+
@Composable
51+
private fun PredictiveBackOverrideExit(
52+
modifier: Modifier,
53+
) {
54+
val navController = rememberNavController()
55+
56+
// [START android_compose_predictiveback_navhost]
57+
NavHost(
58+
navController = navController,
59+
startDestination = "home",
60+
popExitTransition = {
61+
scaleOut(
62+
targetScale = 0.9f,
63+
transformOrigin = TransformOrigin(pivotFractionX = 0.5f, pivotFractionY = 0.5f)
64+
)
65+
},
66+
popEnterTransition = {
67+
EnterTransition.None
68+
},
69+
modifier = modifier,
70+
)
71+
// [END android_compose_predictiveback_navhost]
72+
{
73+
composable("home") {
74+
HomeScreen(
75+
modifier = modifier,
76+
navController = navController,
77+
)
78+
}
79+
composable("settings") {
80+
SettingsScreen(
81+
modifier = modifier,
82+
navController = navController,
83+
)
84+
}
85+
}
86+
}
87+
88+
@Composable
89+
private fun HomeScreen(
90+
modifier: Modifier = Modifier,
91+
navController: NavHostController
92+
) {
93+
}
94+
95+
@Composable
96+
private fun SettingsScreen(
97+
modifier: Modifier = Modifier,
98+
navController: NavHostController
99+
) {
100+
}
101+
102+
@Composable
103+
private fun PredictiveBackHandlerBasicExample() {
104+
105+
var boxScale by remember { mutableFloatStateOf(1F) }
106+
107+
Box(
108+
modifier = Modifier
109+
.fillMaxSize(boxScale)
110+
.background(Color.Blue)
111+
)
112+
113+
// [START android_compose_predictivebackhandler_basic]
114+
PredictiveBackHandler(true) { progress: Flow<BackEventCompat> ->
115+
// code for gesture back started
116+
try {
117+
progress.collect { backEvent ->
118+
// code for progress
119+
boxScale = 1F - (1F * backEvent.progress)
120+
}
121+
// code for completion
122+
} catch (e: CancellationException) {
123+
// code for cancellation
124+
boxScale = 1F
125+
}
126+
}
127+
// [END android_compose_predictivebackhandler_basic]
128+
}
129+
130+
@Composable
131+
private fun PredictiveBackHandlerManualProgress() {
132+
133+
Surface(
134+
modifier = Modifier.fillMaxSize()
135+
) {
136+
var drawerState by remember {
137+
mutableStateOf(DrawerState.Closed)
138+
}
139+
140+
val translationX = remember {
141+
Animatable(0f)
142+
}
143+
144+
val drawerWidth = with(LocalDensity.current) {
145+
DrawerWidth.toPx()
146+
}
147+
translationX.updateBounds(0f, drawerWidth)
148+
149+
val coroutineScope = rememberCoroutineScope()
150+
151+
suspend fun closeDrawer(velocity: Float = 0f) {
152+
translationX.animateTo(targetValue = 0f, initialVelocity = velocity)
153+
drawerState = DrawerState.Closed
154+
}
155+
suspend fun openDrawer(velocity: Float = 0f) {
156+
translationX.animateTo(targetValue = drawerWidth, initialVelocity = velocity)
157+
drawerState = DrawerState.Open
158+
}
159+
160+
val velocityTracker = remember {
161+
VelocityTracker()
162+
}
163+
164+
// [START android_compose_predictivebackhandler_manualprogress]
165+
PredictiveBackHandler(drawerState == DrawerState.Open) { progress ->
166+
try {
167+
progress.collect { backEvent ->
168+
val targetSize = (drawerWidth - (drawerWidth * backEvent.progress))
169+
translationX.snapTo(targetSize)
170+
velocityTracker.addPosition(
171+
SystemClock.uptimeMillis(),
172+
Offset(backEvent.touchX, backEvent.touchY)
173+
)
174+
}
175+
closeDrawer(velocityTracker.calculateVelocity().x)
176+
} catch (e: CancellationException) {
177+
openDrawer(velocityTracker.calculateVelocity().x)
178+
}
179+
velocityTracker.resetTracking()
180+
}
181+
// [END android_compose_predictivebackhandler_manualprogress]
182+
}
183+
}
184+
185+
private enum class DrawerState {
186+
Open,
187+
Closed
188+
}
189+
190+
private val DrawerWidth = 300.dp

0 commit comments

Comments
 (0)