Skip to content

Instantly share code, notes, and snippets.

@FlorianHardyDev
Last active March 19, 2021 14:00
Show Gist options
  • Select an option

  • Save FlorianHardyDev/30479efbd835cff8d40e37f513f08553 to your computer and use it in GitHub Desktop.

Select an option

Save FlorianHardyDev/30479efbd835cff8d40e37f513f08553 to your computer and use it in GitHub Desktop.

Revisions

  1. FlorianHardyDev renamed this gist Mar 19, 2021. 1 changed file with 0 additions and 0 deletions.
  2. FlorianHardyDev created this gist Mar 19, 2021.
    115 changes: 115 additions & 0 deletions FloatingButtonController_calculs.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,115 @@
    @objc
    func panDidFire(panner: UIPanGestureRecognizer) {
    let translation = panner.translation(in: view)
    panner.setTranslation(CGPoint.zero, in: view)

    if panner.state == .began {
    // Animate the appearing of the delete button
    UIView.animate(withDuration: Constants.animationDuration) {
    self.showDeleteView()
    }
    }
    if panner.state == .changed {
    let newButtonView = UIView(frame: CGRect(x: self.button.frame.origin.x + translation.x,
    y: self.button.frame.origin.y + translation.y,
    width: Constants.buttonWidth,
    height: Constants.buttonHeight))
    // Move the delete button according to the fab button
    let ratio: CGFloat = 0.1
    var tempDeleteCenter = self.deleteView.center
    tempDeleteCenter.x += translation.x * ratio
    let yPos = tempDeleteCenter.y + translation.y * ratio
    let yMaxPos = UIScreen.main.bounds.size.height - Constants.offset - self.deleteView.bounds.size.height / 2
    tempDeleteCenter.y = yPos > yMaxPos ? yMaxPos : yPos

    // Check if the fab intersect with delete button
    let diffX = Constants.deleteWidth - (Constants.buttonWidth / 2)
    let diffY = Constants.deleteHeight - (Constants.buttonHeight / 2)
    let deleteZone = self.deleteView.frame.insetBy(dx: diffX, dy: diffY)

    var deleteTmpNewButtonOrigin = newButtonView.frame.origin
    deleteTmpNewButtonOrigin.x += (Constants.buttonWidth / 2)
    deleteTmpNewButtonOrigin.y += (Constants.buttonHeight / 2)
    let isIn = deleteZone.contains(newButtonView.frame.origin)
    if isIn {
    var tempNewButtonDeleteCenter = tempDeleteCenter
    tempNewButtonDeleteCenter.x -= (Constants.buttonWidth / 2)
    tempNewButtonDeleteCenter.y -= (Constants.buttonHeight / 2)
    newButtonView.frame.origin = tempNewButtonDeleteCenter
    }
    self.button.frame = newButtonView.frame
    self.deleteView.center = tempDeleteCenter
    // Calculate the final fab position during the drag
    self.button.center = isIn ? self.deleteView.center : newButtonView.center
    }
    if panner.state == .ended || panner.state == .cancelled {
    // The delete zone has to be calculated before reseting the delete view position !
    let diffX = Constants.deleteWidth - Constants.buttonWidth
    let diffY = Constants.deleteHeight - Constants.buttonHeight
    let deleteZone = self.deleteView.frame.insetBy(dx: diffX, dy: diffY)
    // Now, we can safely update the delete view position
    // (not in animation, otherwise it does not work)
    self.deleteView.center = CGPoint(x: self.deletingPoint.x,
    y: self.deletingPoint.y)
    UIView.animate(withDuration: Constants.animationDuration) {
    self.snapButtonToSocket(deleteZone: deleteZone)
    self.hideDeleteView()
    }
    }
    }

    private func snapButtonToSocket(deleteZone: CGRect) {
    if deleteZone.contains(button.center) {
    button.center = deletingPoint
    deletePlayer()
    self.view.isHidden = true
    } else {
    let bestSocket = getBestSocket(deleteZoneCenter: deletingPoint)
    if bestSocket == deletingPoint {
    button.center = deletingPoint
    deletePlayer()
    } else {
    button.center = bestSocket
    PlayerManager.shared.smallPlayerLastLocation = bestSocket
    }
    }
    }

    private func getPossiblePoints() -> [CGPoint] {
    var possiblePoints: [CGPoint] = []
    // the current y position
    var yPos: CGFloat = button.center.y
    let minY = Constants.offset + Constants.buttonHeight / 2
    let maxY = UIScreen.main.bounds.size.height - Constants.offset - Constants.buttonHeight / 2

    // Check if fab is out of limits
    if button.center.y < minY {
    // limit top
    yPos = minY
    } else if button.center.y > maxY {
    // limit bottom
    yPos = maxY
    }
    // limit right
    possiblePoints.append(CGPoint(x: UIScreen.main.bounds.size.width - Constants.offset - Constants.buttonWidth / 2,
    y: yPos))
    // limit left
    possiblePoints.append(CGPoint(x: Constants.offset + Constants.buttonWidth / 2, y: yPos))
    // return the possible points
    return possiblePoints
    }

    private func getBestSocket(deleteZoneCenter: CGPoint) -> CGPoint {
    var bestSocket = CGPoint.zero
    var distanceToBestSocket = CGFloat.infinity
    var possiblePoints: [CGPoint] = getPossiblePoints()
    possiblePoints.append(deleteZoneCenter)
    for socket in possiblePoints {
    let distance = hypot(button.center.x - socket.x, button.center.y - socket.y)
    if distance < distanceToBestSocket {
    distanceToBestSocket = distance
    bestSocket = socket
    }
    }
    return bestSocket
    }