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.
FloatingButtonController calculs
@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
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment