or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

accessibility-testing.mdcoordinate-utilities.mdindex.mdios-uikit-testing.mdtouch-simulation.md

coordinate-utilities.mddocs/

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