0
# Coordinate Utilities
1
2
Conversion utilities between Compose coordinate systems and iOS Core Graphics coordinates, providing seamless interoperability for layout calculations, touch event handling, and UI positioning.
3
4
## Capabilities
5
6
### Core Graphics Conversion
7
8
Functions for converting between Compose coordinates and iOS Core Graphics coordinate system.
9
10
```kotlin { .api }
11
/**
12
* Converts Compose DpOffset to Core Graphics CGPoint
13
* @return CValue<CGPoint> representing the same position in Core Graphics coordinates
14
*/
15
internal fun DpOffset.toCGPoint(): CValue<CGPoint>
16
17
/**
18
* Converts Core Graphics CGPoint to Compose DpOffset
19
* @return DpOffset representing the same position in Compose coordinates
20
*/
21
internal fun CValue<CGPoint>.toDpOffset(): DpOffset
22
```
23
24
**Usage Examples:**
25
26
```kotlin
27
// Convert Compose coordinates to Core Graphics for UIKit integration
28
val composeOffset = DpOffset(100.dp, 150.dp)
29
val cgPoint = composeOffset.toCGPoint()
30
31
// Convert Core Graphics coordinates back to Compose
32
val backToCompose = cgPoint.toDpOffset()
33
assert(backToCompose == composeOffset)
34
```
35
36
### Rectangle Conversion
37
38
Functions for converting between different rectangle coordinate systems with density conversion support.
39
40
```kotlin { .api }
41
/**
42
* Converts DpRect to pixel Rect using provided density
43
* @param density - Screen density for dp-to-pixel conversion
44
* @return Rect in pixel coordinates
45
*/
46
internal fun DpRect.toRect(density: Density): Rect
47
48
/**
49
* Converts pixel Rect to DpRect using provided density
50
* @param density - Screen density for pixel-to-dp conversion
51
* @return DpRect in density-independent coordinates
52
*/
53
internal fun Rect.toDpRect(density: Density): DpRect
54
55
/**
56
* Converts Core Graphics CGRect to Compose DpRect
57
* @return DpRect representing the same rectangle in Compose coordinates
58
*/
59
internal fun CValue<CGRect>.toDpRect(): DpRect
60
```
61
62
**Usage Examples:**
63
64
```kotlin
65
runUIKitInstrumentedTest {
66
val dpRect = DpRect(
67
offset = DpOffset(10.dp, 20.dp),
68
size = DpSize(100.dp, 50.dp)
69
)
70
71
// Convert to pixel coordinates for UIKit operations
72
val pixelRect = dpRect.toRect(density)
73
74
// Convert back to dp coordinates
75
val backToDp = pixelRect.toDpRect(density)
76
}
77
```
78
79
### Rectangle Geometry Operations
80
81
Utility functions for rectangle geometry calculations and spatial relationships.
82
83
```kotlin { .api }
84
/**
85
* Calculates the center point of the rectangle
86
* @return DpOffset representing the center coordinates
87
*/
88
val DpRect.center: DpOffset
89
90
/**
91
* Creates a zero-size DpRect at origin
92
* @return DpRect with zero width and height at (0, 0)
93
*/
94
fun DpRectZero(): DpRect
95
96
/**
97
* Calculates intersection of two rectangles
98
* @param other - Rectangle to intersect with
99
* @return DpRect representing intersection area, or null if no intersection
100
*/
101
fun DpRect.intersect(other: DpRect): DpRect?
102
```
103
104
**Usage Examples:**
105
106
```kotlin
107
val rect1 = DpRect(
108
offset = DpOffset(0.dp, 0.dp),
109
size = DpSize(100.dp, 100.dp)
110
)
111
112
val rect2 = DpRect(
113
offset = DpOffset(50.dp, 50.dp),
114
size = DpSize(100.dp, 100.dp)
115
)
116
117
// Get center of rectangle
118
val center = rect1.center // DpOffset(50.dp, 50.dp)
119
120
// Calculate intersection
121
val intersection = rect1.intersect(rect2)
122
// Result: DpRect(offset=DpOffset(50.dp, 50.dp), size=DpSize(50.dp, 50.dp))
123
124
// Create zero rectangle
125
val zeroRect = DpRectZero() // DpRect(offset=DpOffset.Zero, size=DpSize.Zero)
126
```
127
128
### View Coordinate Utilities
129
130
Functions for working with UIView coordinate systems and screen-relative positioning.
131
132
```kotlin { .api }
133
/**
134
* Gets view bounds in window coordinates as DpRect
135
* @return DpRect representing view bounds in window coordinate system
136
*/
137
fun UIView.dpRectInWindow(): DpRect
138
```
139
140
**Usage Example:**
141
142
```kotlin
143
// Get UIView bounds in window coordinates
144
val viewBounds = someUIView.dpRectInWindow()
145
println("View is positioned at: ${viewBounds.offset}")
146
println("View size: ${viewBounds.size}")
147
148
// Use bounds for touch event targeting
149
val centerOfView = viewBounds.center
150
tap(centerOfView)
151
```
152
153
## Coordinate System Integration
154
155
### Compose to UIKit Coordinate Mapping
156
157
```kotlin
158
// Example: Converting Compose layout bounds to UIKit frame
159
runUIKitInstrumentedTest {
160
setContent {
161
Box(
162
modifier = Modifier
163
.offset(50.dp, 100.dp)
164
.size(200.dp, 150.dp)
165
) {
166
Text("Content")
167
}
168
}
169
170
// Calculate equivalent UIKit frame
171
val composeRect = DpRect(
172
offset = DpOffset(50.dp, 100.dp),
173
size = DpSize(200.dp, 150.dp)
174
)
175
176
val uikitFrame = composeRect.toRect(density)
177
// Use uikitFrame for UIKit view positioning
178
}
179
```
180
181
### Touch Event Coordinate Conversion
182
183
```kotlin
184
// Example: Converting touch events between coordinate systems
185
fun handleTouchEvent(cgPoint: CValue<CGPoint>) {
186
val composeOffset = cgPoint.toDpOffset()
187
188
// Process touch in Compose coordinate system
189
processComposeTouch(composeOffset)
190
191
// Convert back for UIKit if needed
192
val backToCG = composeOffset.toCGPoint()
193
}
194
```
195
196
### Layout Bounds Calculation
197
198
```kotlin
199
// Example: Complex layout bounds calculation
200
fun calculateLayoutBounds(views: List<UIView>): DpRect {
201
val bounds = views.map { it.dpRectInWindow() }
202
203
if (bounds.isEmpty()) return DpRectZero()
204
205
val minX = bounds.minOf { it.left }
206
val minY = bounds.minOf { it.top }
207
val maxX = bounds.maxOf { it.right }
208
val maxY = bounds.maxOf { it.bottom }
209
210
return DpRect(
211
offset = DpOffset(minX, minY),
212
size = DpSize(maxX - minX, maxY - minY)
213
)
214
}
215
```
216
217
## Type Definitions
218
219
```kotlin { .api }
220
// Compose coordinate types
221
typealias DpOffset = androidx.compose.ui.unit.DpOffset
222
typealias DpRect = androidx.compose.ui.geometry.DpRect
223
typealias DpSize = androidx.compose.ui.unit.DpSize
224
typealias Density = androidx.compose.ui.unit.Density
225
226
// Pixel coordinate types
227
typealias Rect = androidx.compose.ui.geometry.Rect
228
typealias Offset = androidx.compose.ui.geometry.Offset
229
typealias Size = androidx.compose.ui.geometry.Size
230
231
// iOS Core Graphics types (via Kotlin/Native)
232
// CValue<CGPoint> - Core Graphics point
233
// CValue<CGRect> - Core Graphics rectangle
234
// CValue<CGSize> - Core Graphics size
235
```
236
237
## Platform-Specific Considerations
238
239
### iOS Coordinate System Differences
240
241
- **Origin**: iOS has origin at top-left, same as Compose
242
- **Y-Axis Direction**: Both systems have Y increasing downward
243
- **Density Independence**: Compose uses dp units, iOS uses points (similar concept)
244
- **Precision**: Core Graphics uses CGFloat (Double on 64-bit), Compose uses Float for dp values
245
246
### Performance Considerations
247
248
- **Conversion Overhead**: Coordinate conversions are lightweight but should be cached for frequently accessed values
249
- **Density Lookup**: Screen density is cached within test environment for optimal performance
250
- **Batch Operations**: Group multiple coordinate conversions when possible for better performance
251
252
### Thread Safety
253
254
- **Main Thread**: All UIKit coordinate operations must occur on the main thread
255
- **Compose Thread**: Coordinate calculations can be performed on any thread
256
- **Conversion Safety**: Coordinate conversion functions are thread-safe and immutable