Common Zoom

Source Code

Although the zooming code is quite distinct for both platforms let´s move it to the common library as good as we can. This will help us later when we implement additional clients such as JavaFx or JavaScript.

var cellSize = 15.0f
var minCellSize = 7.0f
var maxCellSize = 60.0f
var cellPadding = 3.0f

fun scale(scaleFactor: Float) {
    val newCellSize = cellSize * scaleFactor

    cellSize = when {
        newCellSize < minCellSize -> minCellSize
        newCellSize > maxCellSize -> maxCellSize
        else -> newCellSize
    }
}

Once again we integrate the common function first into our Android project and then into our iOS project.

private val zoomListener = object : ScaleGestureDetector.SimpleOnScaleGestureListener() {
    override fun onScale(detector: ScaleGestureDetector): Boolean {

        val oldCellSize = board.cellSize
        board.scale(detector.scaleFactor)
        val realScaleFactor = board.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
    }

}
    
    @ViewBuilder
    var body: some View {
        if self.board != nil {
            VStack(spacing: CGFloat(self.board!.cellPadding)) {
                ForEach(0..<Int(self.board!.rows)) { rowIdx in
                    HStack(spacing: CGFloat(self.board!.cellPadding)) {
                        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.board!.scale(scaleFactor: Float(delta))
            }.onEnded{value in
                self.lastScaleValue = 1.0
            })

        }
        else {
            EmptyView()
        }
    }