Zoom
Zooming the game board is a more complex user interaction. We need to interact with the touch API of the different target platforms.
We implement this in Android first.
private val zoomListener = object : ScaleGestureDetector.SimpleOnScaleGestureListener() {
override fun onScale(detector: ScaleGestureDetector): Boolean {
val newCellSize = cellSize * detector.scaleFactor
val oldCellSize = cellSize
cellSize = when {
newCellSize < minCellSize -> minCellSize
newCellSize > maxCellSize -> maxCellSize
else -> newCellSize
}
val realScaleFactor = cellSize / oldCellSize
val distX = detector.focusX - offsetX
val distY = detector.focusY - offsetY
val corrX = distX - distX * realScaleFactor
val corrY = distY - distY * realScaleFactor
offsetX += corrX
offsetY += corrY
invalidate()
return true
}
}
Then the iOS version.
@ViewBuilder
var body: some View {
if self.board != nil {
VStack(spacing: 2) {
ForEach(0..<Int(self.board!.rows)) { rowIdx in
HStack(spacing: 2) {
ForEach(0..<Int(self.board!.columns)) { columnIdx in
self.createCell(board: self.board!, rowIdx: rowIdx, columnIdx: columnIdx)
}
}
}
}
.gesture(MagnificationGesture()
.onChanged{value in
let delta = value / self.lastScaleValue
self.lastScaleValue = value
self.scale = self.scale * delta
}
.onEnded{value in
self.lastScaleValue = 1.0
}
)
}
else {
EmptyView()
}
}
The implementation of the zoom logic for the iOS version is quite distinct from the Android version because both platform handle touch events differently.