-
-
Notifications
You must be signed in to change notification settings - Fork 368
/
BackPressActivity.kt
192 lines (179 loc) · 9.63 KB
/
BackPressActivity.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
package com.example.jetpackcompose.state.backpress
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.activity.compose.setContent
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.unit.dp
import com.example.jetpackcompose.image.TitleComponent
class BackPressActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// This is an extension function of Activity that sets the @Composable function that's
// passed to it as the root view of the activity. This is meant to replace the .xml file
// that we would typically set using the setContent(R.id.xml_file) method. The setContent
// block defines the activity's layout.
setContent {
// Reacting to state changes is core to how Jetpack Compose works. This state variable
// "appState" is used to maintain the current active screen. The value is updated
// based on the actions of the user across the different screens. Every time the value
// of this variable changes, the relevant sub-composables that depends on it is
// automatically updated/recomposed.
// remember{} is a helper composable that calculates the value passed to it only
// during the first composition. It then returns the same value for every subsequent
// composition. In the example below, it initializes the value of AppState() and does
// it only during the first composition. It's important to understand that the
// subsequent screens where this value is passed to are still allowed to modify the
// value (depending on whether it has mutable properties).
val appState = remember { AppState() }
BackPressApp(appState)
}
}
}
// We represent a Composable function by annotating it with the @Composable annotation. Composable
// functions can only be called from within the scope of other composable functions. We should
// think of composable functions to be similar to lego blocks - each composable function is in turn
// built up of smaller composable functions.
@Composable
fun BackPressApp(appState: AppState) {
// Choose which screen to show based on the value in the currentScreen variable inside AppState
when (appState.currentScreen) {
CurrentScreen.SCREEN1 -> Screen1(appState)
CurrentScreen.SCREEN2 -> Screen2(appState)
CurrentScreen.SCREEN3 -> Screen3(appState)
}
}
// We represent a Composable function by annotating it with the @Composable annotation. Composable
// functions can only be called from within the scope of other composable functions. We should
// think of composable functions to be similar to lego blocks - each composable function is in turn
// built up of smaller composable functions.
@Composable
fun Screen1(appState: AppState) {
val activity = (LocalLifecycleOwner.current as ComponentActivity)
// Column is a composable that places its children in a vertical sequence. You
// can think of it similar to a LinearLayout with the vertical orientation.
// In addition we also pass a few modifiers to it.
// You can think of Modifiers as implementations of the decorators pattern that are used to
// modify the composable that its applied to. In this example, as the Column composable to
// occupy the entire available height & width using Modifier.fillMaxSize().
Column(
modifier = Modifier.fillMaxSize().padding(16.dp),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
// TitleComponent is a composable we created in one of the files that merely renders
// text on the screen.
TitleComponent(title = "This is Screen 1")
// Button is a pre-defined Material Design implementation of a contained button -
// https://material.io/design/components/buttons.html#contained-button.
Button(
colors = ButtonDefaults.buttonColors(backgroundColor = Color.Gray),
onClick = {
appState.currentScreen = CurrentScreen.SCREEN2
}) {
TitleComponent(title = "Go To Screen 2")
}
TitleComponent(title = "Press back to exit this activity")
}
// BackButtonHandler is a custom composable we created to handle back press based on the
// context of our app. Since we are currently in Screen 1, pressing back should finish the
// acitivity. So that's exactly what we do in the lambda that we pass to the BackButtonHandler
// composable. Take a look at it to understand how that is implemented.
BackButtonHandler {
activity.finish()
}
}
// We represent a Composable function by annotating it with the @Composable annotation. Composable
// functions can only be called from within the scope of other composable functions. We should
// think of composable functions to be similar to lego blocks - each composable function is in turn
// built up of smaller composable functions.
@Composable
fun Screen2(appState: AppState) {
// Column is a composable that places its children in a vertical sequence. You
// can think of it similar to a LinearLayout with the vertical orientation.
// In addition we also pass a few modifiers to it.
// You can think of Modifiers as implementations of the decorators pattern that are used to
// modify the composable that its applied to. In this example, as the Column composable to
// occupy the entire available height & width using Modifier.fillMaxSize().
Column(
modifier = Modifier.fillMaxSize().padding(16.dp),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
// TitleComponent is a composable we created in one of the files that merely renders
// text on the screen.
TitleComponent(title = "This is Screen 2")
// Button is a pre-defined Material Design implementation of a contained button -
// https://material.io/design/components/buttons.html#contained-button.
Button(
colors = ButtonDefaults.buttonColors(backgroundColor = Color.Gray),
onClick = {
appState.currentScreen = CurrentScreen.SCREEN3
}) {
TitleComponent(title = "Go To Screen 3")
}
TitleComponent(title = "Press back to go to Screen 1")
}
// BackButtonHandler is a custom composable we created to handle back press based on the
// context of our app. Since we are currently in Screen 2, pressing back should take you to
// Screen 1. So that's exactly what we do in the lambda that we pass to the BackButtonHandler
// composable. Take a look at it to understand how that is implemented.
BackButtonHandler {
appState.currentScreen = CurrentScreen.SCREEN1
}
}
// We represent a Composable function by annotating it with the @Composable annotation. Composable
// functions can only be called from within the scope of other composable functions. We should
// think of composable functions to be similar to lego blocks - each composable function is in turn
// built up of smaller composable functions.
@Composable
fun Screen3(appState: AppState) {
// Column is a composable that places its children in a vertical sequence. You
// can think of it similar to a LinearLayout with the vertical orientation.
// In addition we also pass a few modifiers to it.
// You can think of Modifiers as implementations of the decorators pattern that are used to
// modify the composable that its applied to. In this example, as the Column composable to
// occupy the entire available height & width using Modifier.fillMaxSize().
Column(
modifier = Modifier.fillMaxSize().padding(16.dp),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
// TitleComponent is a composable we created in one of the files that merely renders
// text on the screen.
TitleComponent(title = "This is Screen 3")
// TitleComponent is a composable we created in one of the files that merely renders
// text on the screen.
TitleComponent(title = "You can only go back from here. Press back to go to Screen 2.")
}
// BackButtonHandler is a custom composable we created to handle back press based on the
// context of our app. Since we are currently in Screen 3, pressing back should take you to
// Screen 2. So that's exactly what we do in the lambda that we pass to the BackButtonHandler
// composable. Take a look at it to understand how that is implemented.
BackButtonHandler {
appState.currentScreen = CurrentScreen.SCREEN2
}
}
// Simple class that we created to hold the value for the current active screen.
class AppState {
var currentScreen by mutableStateOf(CurrentScreen.SCREEN1)
}
enum class CurrentScreen {
SCREEN1,
SCREEN2,
SCREEN3
}