-
-
Notifications
You must be signed in to change notification settings - Fork 368
/
MeasuringScaleActivity.kt
211 lines (197 loc) · 10.3 KB
/
MeasuringScaleActivity.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
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
package com.example.jetpackcompose.customview
import android.os.Bundle
import androidx.activity.compose.setContent
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.background
import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.rememberScrollState
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.material.darkColors
import androidx.compose.material.lightColors
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
class MeasuringScaleActivity : 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 {
CustomTheme {
MeasuringScaleComponent()
}
}
}
}
// 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 MeasuringScaleComponent() {
// We create a ScrollState that's "remember"ed to add proper support for a scrollable component.
// This allows us to also control the scroll position and other scroll related properties.
// remember calculates the value passed to it only during the first composition. It then
// returns the same value for every subsequent composition. More details are available in the
// comments below.
val scrollState = rememberScrollState()
// Row is a composable that places its children in a horizontal sequence. You
// can think of it similar to a LinearLayout with the horizontal orientation.
// 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, we assign a
// padding of 16dp and specify it to occupy the entire available width.
// In addition, we make use of the horizontalScroll modifier. This modifier makes the using
// composable to have scroll functionality in the horizontal direction.
Row(modifier = Modifier.horizontalScroll(scrollState).padding(top = 16.dp).fillMaxWidth(),
content = {
for (i in -20..1020) {
ScaleLineComponent(i)
}
})
// 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.
Column(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.padding(top = 16.dp).fillMaxWidth()
) {
ScaleCenterPointer()
}
}
// 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 ScaleLineComponent(index: Int) {
val isDivisibleBy10 = index % 10 == 0
// Surface color from the color palette specified by the applied Theme. In our case, its
// what we specify in the CustomTheme composable.
val surfaceColor = MaterialTheme.colors.surface
// The color configured for rendering content on top of surfaces that use the surface color.
val onSurfaceColor = MaterialTheme.colors.onSurface
// 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. We also give it a
// modifier.
// 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, we add background
// color to the Column using the drawBackground(color) modifier.
Column(modifier = Modifier.background(color = surfaceColor)) {
// We use the Canvas composable that gives you access to a canvas that you can draw
// into. We also pass it a modifier.
Canvas(
modifier = Modifier.padding(5.dp).height(100.dp).width(3.dp)
) {
// Allows you to draw a line between two points (p1 & p2) on the canvas.
drawLine(
color = onSurfaceColor,
start = Offset(0f, 0f),
end = Offset(0f, if (isDivisibleBy10) size.height else size.height * 0.2f),
strokeWidth = if (isDivisibleBy10) size.width else size.width * 0.3f
)
}
// Text is a predefined composable that does exactly what you'd expect it to - display text
// on the screen. It allows you to customize its appearance using style, fontWeight,
// fontSize, etc.
Text(
// Adding an empty string to ensure that that it also gets the background color
// assigned otherwise it results in bad looking UI.
text = if (isDivisibleBy10) "${index / 10}" else "",
textAlign = TextAlign.Center,
style = TextStyle(fontFamily = FontFamily.Monospace),
color = onSurfaceColor,
modifier = Modifier.fillMaxWidth()
)
}
}
// 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 ScaleCenterPointer() {
// Primary color from the color palette specified by the applied Theme. In our case, its
// what we specify in the CustomTheme composable.
val primaryColor = MaterialTheme.colors.primary
// 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.
Column {
// We use the Canvas composable that gives you access to a canvas that you can draw
// into. We also pass it a modifier.
// 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, we give it a
// padding of 5 dp, height of 120dp & width of 3dp.
Canvas(
modifier = Modifier.padding(5.dp).height(120.dp).width(3.dp)
) {
// Allows you to draw a line between two points (p1 & p2) on the canvas.
drawLine(
color = primaryColor,
start = Offset(0f, 0f),
end = Offset(0f, size.height),
strokeWidth = size.width
)
}
}
}
// 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.
// Below we have created a composable called CustomTheme that in turn accepts Composable
// functions as a parameter. This is simply a high order function.
@Composable
fun CustomTheme(children: @Composable() () -> Unit) {
// lightColors is a default implementation of the ColorPalette from the MaterialDesign
// specification https://material.io/design/color/the-color-system.html#color-theme-creation.
// for easy use. In this case, I'm just using the default values and not overriding any
// properties like primaryColor, secondaryColor, etc.
val lightColors = lightColors()
// darkColors is a default implementation of dark mode ColorPalette from the
// Material Design specification
// https://material.io/design/color/the-color-system.html#color-theme-creation.
val darkColors = darkColors()
// We check if the device has activated dark mode and based on this state we pass the
// appropriate value to the MaterialTheme.
val color = if (isSystemInDarkTheme()) darkColors else lightColors
// A MaterialTheme comprises of colors, typography and the child composables that are going
// to make use of this styling.
MaterialTheme(colors = color) {
children()
}
}
/**
* Android Studio lets you preview your composable functions within the IDE itself, instead of
* needing to download the app to an Android device or emulator. This is a fantastic feature as you
* can preview all your custom components(read composable functions) from the comforts of the IDE.
* The main restriction is, the composable function must not take any parameters. If your composable
* function requires a parameter, you can simply wrap your component inside another composable
* function that doesn't take any parameters and call your composable function with the appropriate
* params. Also, don't forget to annotate it with @Preview & @Composable annotations.
*/
@Preview
@Composable
fun MeasuringScaleComponentPreview() {
CustomTheme {
MeasuringScaleComponent()
}
}