I have a button which I want to move each time I try to drag, and then move a segue each time I tap. For drag I have put that method:
skillsButtonReal.addTarget(self, action: #selector(ViewController.wasDragged(_:event:)), forControlEvents: UIControlEvents.TouchDragInside)
func wasDragged (buttn : UIButton, event :UIEvent)
{
let buttonView = buttn as UIView;
let touches : Set<UITouch> = event.touchesForView(buttonView)!
let touch = touches.first!
let location = touch.locationInView(buttonView)
let previousLocation : CGPoint = touch .previousLocationInView(buttonView)
let delta_x :CGFloat = location.x - previousLocation.x
let delta_y :CGFloat = location.y - previousLocation.y
buttn.center = CGPointMake(buttn.center.x + delta_x,
buttn.center.y + delta_y);
}
Which is being called but it does not move. What else do I need to put or invoke?
I think this could be useful to you:
var panGesture: UIPanGestureRecognizer = UIPanGestureRecognizer(target: self, action: Selector("recognizePanGesture:"))
panGesture.minimumNumberOfTouches = 1
panGesture.maximumNumberOfTouches = 1
buttonView.addGestureRecognizer(panGesture)
func recognizePanGesture(sender: UIPanGestureRecognizer)
{
var translate = sender.translationInView(self.view)
sender.view!.center = CGPoint(x:sender.view!.center.x + translate.x,
y:sender.view!.center.y + translate.y)
sender.setTranslation(CGPointZero, inView: self.view)
}
Related
I calculated the speed of UIGestureRecognizer and I want to use it as velocity of Physicsbody in SpriteKit.
How can I do that since Speed is calculated in touches began and touches ended method, while my Physicsbody is wrapped in swipeUp & swipeDown etc functions, which does not have access to the Speed variable?
Here is my code:
class GameScene: SKScene, SKPhysicsContactDelegate, SKViewDelegate, UIGestureRecognizerDelegate, UIViewControllerTransitioningDelegate {
var Kite = SKSpriteNode(imageNamed: "ASC_8025_large.jpg")
#objc let minusButton = SKSpriteNode(imageNamed: "minus.jpg")
#objc let plusButton = SKSpriteNode(imageNamed: "plus.png")
//override init(Kite: SKSpriteNode) {
//For long Long press gesture to work
let longPressGestureRecPlus = UILongPressGestureRecognizer()
let longPressGestureRecMinus = UILongPressGestureRecognizer(target: self, action: #selector(longPressed(press:)))
//First we declare all of our Gestures...
//swipes
let swipeRightRec = UISwipeGestureRecognizer()
let swipeLeftRec = UISwipeGestureRecognizer()
let swipeUpRec = UISwipeGestureRecognizer()
let swipeDownRec = UISwipeGestureRecognizer()
//rotate
let rotateRec = UIRotationGestureRecognizer()
//taps
let tapRec = UITapGestureRecognizer()
let tapRec2 = UITapGestureRecognizer()
override func didMove(to view: SKView) {
// Get label node from scene and store it for use later
Kite.size = CGSize(width: 40.0, height: 40.0)
Kite.position = CGPoint(x: frame.midX, y: frame.midY)
plusButton.size = CGSize(width: 30.0, height: 30.0)
plusButton.position = CGPoint(x: frame.midX, y: frame.minY + 20.0)
plusButton.name = "plusButton"
//plusButton.isUserInteractionEnabled = true
addChild(Kite)
addChild(plusButton)
swipeRightRec.addTarget(self, action: #selector(GameScene.swipedRight) )
swipeRightRec.direction = .right
self.view!.addGestureRecognizer(swipeRightRec)
swipeLeftRec.addTarget(self, action: #selector(GameScene.swipedLeft) )
swipeLeftRec.direction = .left
self.view!.addGestureRecognizer(swipeLeftRec)
swipeUpRec.addTarget(self, action: #selector(GameScene.swipedUp) )
swipeUpRec.direction = .up
self.view!.addGestureRecognizer(swipeUpRec)
swipeDownRec.addTarget(self, action: #selector(GameScene.swipedDown) )
swipeDownRec.direction = .down
self.view!.addGestureRecognizer(swipeDownRec)
//notice the function this calls has (_:) after it because we are passing in info about the gesture itself (the sender)
rotateRec.addTarget(self, action: #selector (GameScene.rotatedView (_:) ))
self.view!.addGestureRecognizer(rotateRec)
// again notice (_:), we'll need this to find out where the tap occurred.
tapRec.addTarget(self, action:#selector(GameScene.tappedView(_:) ))
tapRec.numberOfTouchesRequired = 1
tapRec.numberOfTapsRequired = 1
self.view!.addGestureRecognizer(tapRec)
tapRec2.addTarget(self, action:#selector(GameScene.tappedView2(_:) ))
tapRec2.numberOfTouchesRequired = 1
tapRec2.numberOfTapsRequired = 2 //2 taps instead of 1 this time
self.view!.addGestureRecognizer(tapRec2)
longPressGestureRecPlus.addTarget(self, action: #selector(longPressed(press:)))
longPressGestureRecPlus.minimumPressDuration = 2.0
self.view?.addGestureRecognizer(longPressGestureRecPlus)
}
//the functions that get called when swiping...
#objc func swipedRight() {
print("Right")
Kite.physicsBody?.velocity = CGVector(dx: 60, dy: 60)
//Tilts the Kite towards Right
let tiltRight = SKAction.rotate(toAngle: -1.00, duration: 0.1)
Kite.run(tiltRight)
}
#objc func swipedLeft() {
Kite.physicsBody?.velocity = CGVector(dx: -60, dy: 60)
//Tilts the Kite towards Right
let tiltLeft = SKAction.rotate(toAngle: 1.00, duration: 0.1)
Kite.run(tiltLeft)
print("Left")
}
#objc func swipedUp() {
Kite.physicsBody?.velocity = CGVector(dx: 60, dy: 60)
//Straightens the Kite
let straightens = SKAction.rotate(toAngle: 0.00, duration: 0.1)
Kite.run(straightens)
print("Up")
}
#objc func swipedDown() {
Kite.physicsBody?.velocity = CGVector(dx: 0, dy: -60)
print("Down")
}
// what gets called when there's a single tap...
//notice the sender is a parameter. This is why we added (_:) that part to the selector earlier
#objc func tappedView(_ sender:UITapGestureRecognizer) {
let point:CGPoint = sender.location(in: self.view)
print("Single tap")
print(point)
}
// what gets called when there's a double tap...
//notice the sender is a parameter. This is why we added (_:) that part to the selector earlier
#objc func tappedView2(_ sender:UITapGestureRecognizer) {
let point:CGPoint = sender.location(in: self.view)
print("Double tap")
print(point)
}
//what gets called when there's a rotation gesture
//notice the sender is a parameter. This is why we added (_:) that part to the selector earlier
#objc func rotatedView(_ sender:UIRotationGestureRecognizer) {
if (sender.state == .began) {
print("rotation began")
}
if (sender.state == .changed) {
print("rotation changed")
//you could easily make any sprite's rotation equal this amount like so...
//thePlayer.zRotation = -sender.rotation
//convert rotation to degrees...
let rotateAmount = Measurement(value: Double(sender.rotation), unit: UnitAngle.radians).converted(to: .degrees).value
print("\(rotateAmount) degreess" )
}
if (sender.state == .ended) {
print("rotation ended")
}
}
func removeAllGestures(){
//if you need to remove all gesture recognizers with Swift you can do this....
for gesture in (self.view?.gestureRecognizers)! {
self.view?.removeGestureRecognizer(gesture)
}
//this is good to do before a SKScene transitions to another SKScene.
}
func removeAGesture()
{
//To remove a single gesture you can use...
self.view?.removeGestureRecognizer(swipeUpRec)
}
//Fix the gesture recognizing the plusButton
#objc func longPressed(press: UILongPressGestureRecognizer) {
if press.state == .began {
isUserInteractionEnabled = true
let positionInScene = press.location(in: self.view)
let touchedNode = self.atPoint(positionInScene)
plusButton.name = "plusButton"
Kite.physicsBody?.velocity = CGVector(dx: 0, dy: 60.0*3)
print("Pressed on the screen")
if let name = touchedNode.name {
if name == "plusButton" {
print("LONG TAPPED")
}
}
}
}
var start: CGPoint?
var startTime: TimeInterval?
var taps = 0
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
print("Began")
Kite.physicsBody = SKPhysicsBody(rectangleOf: Kite.size)
Kite.physicsBody?.affectedByGravity = false
//Kite.physicsBody?.velocity = CGVector(dx: 0, dy: 0)
Kite.physicsBody?.applyImpulse(CGVector(dx: 0, dy: 5))
plusButton.name = "plusButton"
plusButton.isUserInteractionEnabled = false
//We figure how to interact with BUTTON in Spritekit
let touch = touches.first
let positionInScene = touch!.location(in: self)
let touchedNode = self.atPoint(positionInScene)
if let name = touchedNode.name {
if name == "plusButton" {
taps += 1
Kite.size = CGSize(width: 200, height: 200)
print("tapped")
print("Taps", taps)
}
}
for touch in touches {
let location:CGPoint = touch.location(in: self.view!)
start = location
startTime = touch.timestamp
}
}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
print("Ended")
//Calculating Speed of the Gestures
for touch in touches {
let location:CGPoint = touch.location(in: self.view!)
var dx:CGFloat = location.x - start!.x;
var dy:CGFloat = location.y - start!.y;
var magnitude:CGFloat = sqrt(dx*dx+dy*dy)
//Calculate Time
var dt:CGFloat = CGFloat(touch.timestamp - startTime!)
//Speed = Distance / Time
var speed:CGFloat = magnitude / dt
var speedX:CGFloat = dx/dt
var speedY:CGFloat = dy/dt
print("SpeedY", speedX)
print("SpeedY", speedY)
}
}
so calculating the speed from a vector like dx and dy is
let speed = sqrtf(Float(pow(dx!, 2) + pow(dy!, 2)))
So if you want apply the speed as velocity to an object you need at least one of the directions.
let newDx = 0 // means in no x direction
// next you can change the formula to your new dy to match the given speed
let newDy = sqrtf(pow(speed, 2) - Float(pow(newDx, 2)))
yourNode.physicsBody?.velocity = CGVector(dx: newDx, dy: CGFloat(newDy))
I have added UIDynamics to imageview and used pan gesture for that. It is working fine with pan gesture but when I apply pinch gesture with that it is not working. It is showing large imageview but when I start dragging then it is changed to original size.
Here is my code:
func handleAttachmentGesture(_ sender: UIPanGestureRecognizer) {
let location = sender.location(in: emojiSuperView!)
let boxLocation = sender.location(in: self)
switch sender.state {
case .began:
print("Your touch start position is \(location)")
print("Start location in image is \(boxLocation)")
animator.removeAllBehaviors()
let centerOffset = UIOffset(horizontal: boxLocation.x - self.bounds.midX, vertical: boxLocation.y - self.bounds.midY)
attachmentBehavior = UIAttachmentBehavior(item: self, offsetFromCenter: centerOffset, attachedToAnchor: location)
animator.addBehavior(attachmentBehavior)
case .ended:
print("Your touch end position is \(location)")
print("End location in image is \(boxLocation)")
animator.removeAllBehaviors()
// 1
let velocity = sender.velocity(in: emojiSuperView!)
let magnitude = sqrt((velocity.x * velocity.x) + (velocity.y * velocity.y))
if magnitude > ThrowingThreshold {
// 2
let pushBehavior = UIPushBehavior(items: [self], mode: .instantaneous)
pushBehavior.pushDirection = CGVector(dx: velocity.x / 10, dy: velocity.y / 10)
pushBehavior.magnitude = magnitude / ThrowingVelocityPadding
self.pushBehavior = pushBehavior
animator.addBehavior(pushBehavior)
// 3
let angle = Int(arc4random_uniform(20)) - 10
itemBehavior = UIDynamicItemBehavior(items: [self])
itemBehavior.friction = 0.2
itemBehavior.allowsRotation = true
itemBehavior.addAngularVelocity(CGFloat(angle), for: self)
animator.addBehavior(itemBehavior)
}
default:
attachmentBehavior.anchorPoint = sender.location(in: emojiSuperView!)
break
}
}
func recognizePinchGesture(sender: UIPinchGestureRecognizer)
{
weak var dynamicItem: UIDynamicItem?
// whatever your item is, probably a UIView
dynamicItem = self
let behavior = UIGravityBehavior(items: [dynamicItem!])
let animator = UIDynamicAnimator(referenceView: emojiSuperView!)
// or however you're getting your animator
animator.addBehavior(behavior)
sender.view!.transform = sender.view!.transform.scaledBy(x: sender.scale, y: sender.scale)
animator.updateItem(usingCurrentState: self)
self.animator.updateItem(usingCurrentState: self)
sender.scale = 1
}
When a user does any transform event, save current transform to a global variable.
after that when panning start assigns new transform in began state using UIAttachmentBehavior's action property.
attachmentBehavior.action = {
self.attachmentBehavior.items[0].transform = self.aTransform
}
I am trying to rotate an ImageView I have depending on the X coordinate it is on. Basically, I want it to have a rotation of 0º when x = 300 and a rotation of 180º when x = 190.
I had to program the UIPanGestureRecognizer programmatically. Here is the code I currently have right now:
#objc func personDrag(recognizer: UIPanGestureRecognizer) {
let rotationSub: CGFloat = 1
let translation = recognizer.translation(in: rView)
if let view = recognizer.view {
view.center = CGPoint(x:view.center.x + translation.x, y:view.center.y + translation.y)
view.transform = view.transform.rotated(by: CGFloat.pi - rotationSub)
}
recognizer.setTranslation(CGPoint.zero, in: rView)
}
I was going to attempt to change the rotation degree by 1 every time they panned but it doesn't really work/make sense. Any help would be appreciated. Thank you so much!
Cheers, Theo
You can build your implementation on this:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var imageview: UIImageView!
private var currentRotation: Rotation = .none
/* Certain rotation points (rotation of 0º when x = 300 and a rotation of 180º when x = 190) */
enum Rotation {
case none, xPoint190, xPoint300
}
override func viewDidLoad() {
super.viewDidLoad()
let gestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(handlePan))
imageview.addGestureRecognizer(gestureRecognizer)
imageview.isUserInteractionEnabled = true
}
#IBAction func handlePan(_ gestureRecognizer: UIPanGestureRecognizer) {
guard gestureRecognizer.state == .began || gestureRecognizer.state == .changed else {
return
}
guard let imgView = gestureRecognizer.view else {
return
}
let translation = gestureRecognizer.translation(in: self.view)
imgView.center = CGPoint(x: imgView.center.x + translation.x, y: imgView.center.y + translation.y)
gestureRecognizer.setTranslation(CGPoint.zero, in: self.view)
let angle: CGFloat = self.degreesToRadians(180.0)
/* After reaching x point case - rotating and setting rotation occured to prohibit further rotation */
if imgView.layer.frame.origin.x <= 190, currentRotation != .xPoint190 {
imgView.transform = imgView.transform.rotated(by: angle)
currentRotation = .xPoint190
} else if imgView.layer.frame.origin.x >= 300, currentRotation != .xPoint300 {
imgView.transform = imgView.transform.rotated(by: angle)
currentRotation = .xPoint300
}
private func degreesToRadians(_ deg: CGFloat) -> CGFloat {
return deg * CGFloat.pi / 180
}
}
I hope this will help you.
#objc func rotateViewPanGesture(_ recognizer: UIPanGestureRecognizer) {
touchLocation = recognizer.location(in: superview)
let center = CGRectGetCenter(frame)
switch recognizer.state {
case .began:
deltaAngle = atan2(touchLocation!.y - center.y, touchLocation!.x - center.x) - CGAffineTrasformGetAngle(transform)
initialBounds = bounds
initialDistance = CGpointGetDistance(center, point2: touchLocation!)
case .changed:
let ang = atan2(touchLocation!.y - center.y, touchLocation!.x - center.x)
let angleDiff = deltaAngle! - ang
let a = transform.a
let b = transform.b
let c = transform.c
let d = transform.d
let sx = sqrt(a * a + b * b)
let sy = sqrt(c * c + d * d)
let currentScale = CGPoint(x: sx, y: sy)
let scale = CGAffineTransform(scaleX: currentScale.x, y: currentScale.y)
self.transform = scale.rotated(by: -angleDiff)
layoutIfNeeded()
case .ended:
print("end gesture status")
default:break
}
}
Using Swift5
Programmatically
Rotate view by single point touch
import UIKit
class ViewController: UIViewController {
//Variable for rotating
private var deltaAngle:CGFloat = 0
let squareView : UIView = {
let anyView = UIView()
anyView.backgroundColor = .red
anyView.isUserInteractionEnabled = true
anyView.isMultipleTouchEnabled = true
return anyView
}()
let rotateButton : UIButton = {
let button = UIButton()
button.backgroundColor = .black
button.setImage(UIImage(systemName: "rotate.right"), for: .normal)
return button
}()
override func viewDidLoad() {
super.viewDidLoad()
squareView.frame = CGRect(x: 50, y: 50, width: 100, height: 100)
rotateButton.frame = CGRect(x: 0, y: squareView.frame.height-30, width: 30, height: 30)
squareView.center = view.center
view.addSubview(squareView)
squareView.addSubview(rotateButton)
let PanToRotate = UIPanGestureRecognizer(target: self, action: #selector(handleRotateGesture(_:)))
rotateButton.addGestureRecognizer(PanToRotate)
}
#objc func handleRotateGesture(_ recognizer : UIPanGestureRecognizer){
let touchLocation = recognizer.location(in: squareView.superview)
let center = squareView.center
switch recognizer.state{
case .began :
self.deltaAngle = atan2(touchLocation.y - center.y, touchLocation.x - center.x) - atan2(squareView.transform.b, squareView.transform.a)
case .changed:
let angle = atan2(touchLocation.y - center.y, touchLocation.x - center.x)
let angleDiff = self.deltaAngle - angle
squareView.transform = CGAffineTransform(rotationAngle: -angleDiff)
default: break
}
}
}
I get two problem by using gestures. First I want remove a gesture called "panRecognizer" on double tap, but it doesn't work. Second Problem I use the panRecognizer to move the view but I can't move to the outer edges it stops 200 or 150 px before I reached the edge from the view.
Here is my code:
self.view.gestureRecognizers = self.pageViewController?.gestureRecognizers
let tap = UITapGestureRecognizer(target: self, action: #selector(miningCatalouge.doubleTapped(_:)))
tap.numberOfTapsRequired = 2
self.view.addGestureRecognizer(tap)
}
func doubleTapped(tap: UITapGestureRecognizer) {
let panRecognizer = UIPanGestureRecognizer(target: self, action: #selector(miningCatalouge.handlePan(_:)))
let curScale = self.view!.layer.valueForKeyPath("transform.scale.x")!.floatValue
if (curScale == 1) {
pageViewController!.view.userInteractionEnabled = false
self.view.transform = CGAffineTransformMakeScale(3, 3)
panRecognizer.minimumNumberOfTouches = 1
panRecognizer.maximumNumberOfTouches = 1
self.view.addGestureRecognizer(panRecognizer)
} else {
self.view.transform = CGAffineTransformMakeScale(1, 1)
self.view.center = CGPointMake(512, 391)
pageViewController!.view.userInteractionEnabled = true
//Don´t removed the gesture "panRecognizer"
self.view.removeGestureRecognizer(panRecognizer)
}
print("doubleTapped")
}
func handlePan(recognizer:UIPanGestureRecognizer) {
let translation = recognizer.translationInView(self.view)
if let view = recognizer.view {
view.center = CGPoint(x:view.center.x + translation.x,
y:view.center.y + translation.y)
}
recognizer.setTranslation(CGPointZero, inView: self.view)
if recognizer.state == UIGestureRecognizerState.Ended {
// 1
let velocity = recognizer.velocityInView(self.view)
let magnitude = sqrt((velocity.x * velocity.x) + (velocity.y * velocity.y))
let slideMultiplier = magnitude / 200
// print("magnitude: \(magnitude), slideMultiplier: \(slideMultiplier)")
// 2
let slideFactor = 0.1 * slideMultiplier //Increase for more of a slide
// 3
var finalPoint = CGPoint(x:recognizer.view!.center.x + (velocity.x * slideFactor),
y:recognizer.view!.center.y + (velocity.y * slideFactor))
// 4
finalPoint.x = min(max(finalPoint.x, 0), self.view.bounds.size.width)
finalPoint.y = min(max(finalPoint.y, 0), self.view.bounds.size.height)
// 5
UIView.animateWithDuration(Double(slideFactor),
delay: 0,
// 6
options: UIViewAnimationOptions.CurveEaseOut,
animations: {recognizer.view!.center = finalPoint },
completion: nil)
}
}
for gesture in view.gestureRecognizers!
{
if let recognizer = gesture as? UITapGestureRecognizer {
view.removeGestureRecognizer(recognizer)
}
}
Hope this code could help
Here is the solution from J.Wang:
class miningCatalouge: UIViewController, UIPageViewControllerDelegate, UIGestureRecognizerDelegate, UIScrollViewDelegate {
// I created a new Variable
var panRecognizer: UIPanGestureRecognizer?
override func viewDidLoad() {
super.viewDidLoad()
self.view.gestureRecognizers = self.pageViewController?.gestureRecognizers
let tap = UITapGestureRecognizer(target: self, action: #selector(miningCatalouge.doubleTapped(_:)))
tap.numberOfTapsRequired = 2
self.view.addGestureRecognizer(tap)
//initialized action to panRecognizer
panRecognizer = UIPanGestureRecognizer(target: self, action: #selector(miningCatalouge.handlePan(_:)))
}
func doubleTapped(tap: UITapGestureRecognizer) {
let curScale = self.view!.layer.valueForKeyPath("transform.scale.x")!.floatValue
if (curScale == 1) {
pageViewController!.view.userInteractionEnabled = false
self.view.transform = CGAffineTransformMakeScale(3, 3)
panRecognizer!.minimumNumberOfTouches = 1
panRecognizer!.maximumNumberOfTouches = 1
self.view.addGestureRecognizer(panRecognizer!)
} else {
self.view.transform = CGAffineTransformMakeScale(1, 1)
self.view.center = CGPointMake(512, 391)
pageViewController!.view.userInteractionEnabled = true
self.view.removeGestureRecognizer(panRecognizer!)
}
print("doubleTapped")
}
func handlePan(recognizer:UIPanGestureRecognizer) {
let translation = recognizer.translationInView(self.view)
if let view = recognizer.view {
view.center = CGPoint(x:view.center.x + translation.x,
y:view.center.y + translation.y)
}
recognizer.setTranslation(CGPointZero, inView: self.view)
if recognizer.state == UIGestureRecognizerState.Ended {
let velocity = recognizer.velocityInView(self.view)
let magnitude = sqrt((velocity.x * velocity.x) + (velocity.y * velocity.y))
let slideMultiplier = magnitude / 200
// print("magnitude: \(magnitude), slideMultiplier: \(slideMultiplier)")
let slideFactor = 0.15 * slideMultiplier //Increase for more of a slide
let finalPoint = CGPoint(x:recognizer.view!.center.x + (velocity.x * slideFactor),
y:recognizer.view!.center.y + (velocity.y * slideFactor))
UIView.animateWithDuration(Double(slideFactor),
delay: 0,
// 6
options: UIViewAnimationOptions.CurveEaseOut,
animations: {recognizer.view!.center = finalPoint },
completion: nil)
}
}
I am trying to move a UIView on slide up gesture from its initial position to a fixed final position. The image should move with the hand gesture, and not animate independently.
I haven't tried anything as I have no clue where to start, which gesture class to use.
Finally did it like below.
let gesture = UIPanGestureRecognizer(target: self, action: Selector("wasDragged:"))
slideUpView.addGestureRecognizer(gesture)
slideUpView.userInteractionEnabled = true
gesture.delegate = self
The following function is called when the gesture is detected, (here I am restricting the view to have a maximum centre.y of 555, & I'm resetting back to 554 when the view moves past this point)
func wasDragged(gestureRecognizer: UIPanGestureRecognizer) {
if gestureRecognizer.state == UIGestureRecognizerState.Began || gestureRecognizer.state == UIGestureRecognizerState.Changed {
let translation = gestureRecognizer.translationInView(self.view)
print(gestureRecognizer.view!.center.y)
if(gestureRecognizer.view!.center.y < 555) {
gestureRecognizer.view!.center = CGPointMake(gestureRecognizer.view!.center.x, gestureRecognizer.view!.center.y + translation.y)
}else {
gestureRecognizer.view!.center = CGPointMake(gestureRecognizer.view!.center.x, 554)
}
gestureRecognizer.setTranslation(CGPointMake(0,0), inView: self.view)
}
}
You probably want to use a UIPanGestureRecognizer.
let gesture = UIPanGestureRecognizer(target: self, action: Selector("wasDragged:"))
customView.addGestureRecognizer(gesture)
gesture.delegate = self
And to drag the object only along the y-axis:
func wasDragged(gesture: UIPanGestureRecognizer) {
let translation = gesture.translationInView(self.view)
// Use translation.y to change the position of your customView, e.g.
customView.center.y = translation.y // Customize this.
}
Swift 4:
#objc func wasDragged(_ gestureRecognizer: UIPanGestureRecognizer) {
if gestureRecognizer.state == UIGestureRecognizer.State.began || gestureRecognizer.state == UIGestureRecognizer.State.changed {
let translation = gestureRecognizer.translation(in: self.view)
print(gestureRecognizer.view!.center.y)
if(gestureRecognizer.view!.center.y < 555) {
gestureRecognizer.view!.center = CGPoint(x: gestureRecognizer.view!.center.x, y: gestureRecognizer.view!.center.y + translation.y)
}else {
gestureRecognizer.view!.center = CGPoint(x:gestureRecognizer.view!.center.x, y:554)
}
gestureRecognizer.setTranslation(CGPoint(x: 0, y: 0), in: self.view)
}
}
Call
let gesture = UIPanGestureRecognizer(target: self, action: self.wasDragged(gestureRecognizer:))
customView.addGestureRecognizer(gesture)
gesture.delegate = self
Update for Swift 3.x
When assigning the selector, the syntax has changed and now requires #selector
let gesture = UIPanGestureRecognizer(target: self, action: #selector(navViewDragged(gesture:)))
self.navLayoutView.addGestureRecognizer(gesture)
self.navLayoutView.isUserInteractionEnabled = true
gesture.delegate = self
Function implementation:
func navViewDragged(gesture: UIPanGestureRecognizer){
//Code here
}
Move view anywhere in Swift 3
let panGesture = UIPanGestureRecognizer(target: self, action: #selector(dragged(gestureRecognizer:)))
demoView.isUserInteractionEnabled = true
demoView.addGestureRecognizer(panGesture)
Function
#objc func dragged(gestureRecognizer: UIPanGestureRecognizer) {
if gestureRecognizer.state == UIGestureRecognizerState.began || gestureRecognizer.state == UIGestureRecognizerState.changed {
let translation = gestureRecognizer.translation(in: self.view)
gestureRecognizer.view!.center = CGPoint(x: gestureRecognizer.view!.center.x + translation.x, y: gestureRecognizer.view!.center.y + translation.y)
gestureRecognizer.setTranslation(CGPoint(x: 0, y: 0), in: self.view)
}
}
This is how you really do it like the news view in the Stocks app
First add 2 constraints in Storyboard to the sliding view, one for it's state when it's fully opened and one for when it's closed. Don't forget to leave one of the constraints disabled / not installed so that your view will look opened or closed when the scene is reached.
Reference them in your code
#IBOutlet weak var optionsOpenedConstraint: NSLayoutConstraint!
#IBOutlet weak var optionsVisiableConstraint: NSLayoutConstraint!
now add the UIPanGestureRecognizer to your view in the viewDidLoad function.
let gesture = UIPanGestureRecognizer(target: self, action: #selector(type(of: self).wasDragged(gestureRecognizer:)))
optionsView.addGestureRecognizer(gesture)
finally add this callback and 2 functions:
#objc func wasDragged(gestureRecognizer: UIPanGestureRecognizer) {
let distanceFromBottom = screenHeight - gestureRecognizer.view!.center.y
if gestureRecognizer.state == UIGestureRecognizer.State.began || gestureRecognizer.state == UIGestureRecognizer.State.changed {
optionsOpenedConstraint.isActive = false
optionsVisiableConstraint.isActive = false
let translation = gestureRecognizer.translation(in: self.view)
if((distanceFromBottom - translation.y) < 100) {
gestureRecognizer.view!.center = CGPoint(x: gestureRecognizer.view!.center.x, y: gestureRecognizer.view!.center.y + translation.y)
gestureRecognizer.setTranslation(CGPoint(x: 0, y: 0), in: self.view)
}
}
if gestureRecognizer.state == UIGestureRecognizer.State.ended{
if distanceFromBottom > 6{
openOptionsPanel()
}else{
closeOptionsPanel()
}
}
}
func openOptionsPanel(){
optionsOpenedConstraint.isActive = true
optionsVisiableConstraint.isActive = false
UIView.animate(withDuration: 0.5) {
self.view.layoutIfNeeded()
}
}
func closeOptionsPanel(){
optionsOpenedConstraint.isActive = false
optionsVisiableConstraint.isActive = true
UIView.animate(withDuration: 0.5) {
self.view.layoutIfNeeded()
}
}
and voalá
#IBAction func handlePanGesture(_ recognizer: UIPanGestureRecognizer) {
if MainView.bounds.contains(mainImage.frame) {
let recognizerCenter = recognizer.location(in: MainView)
mainImage.center = recognizerCenter
}
if MainView.bounds.intersection(mainImage.frame).width > 50 && MainView.bounds.intersection(mainImage.frame).height > 0 {
let recognizerCenter = recognizer.location(in: MainView)
print(recognizerCenter)
mainImage.center = recognizerCenter
}
}
#IBAction func handlePinchGesture(_ recognizer: UIPinchGestureRecognizer) {
mainImage.transform = mainImage.transform.scaledBy(x: recognizer.scale, y: recognizer.scale)
recognizer.scale = 1.0
}
#IBAction func handleRotateGesture(_ recognizer: UIRotationGestureRecognizer) {
mainImage.transform = mainImage.transform.rotated(by: recognizer.rotation)
recognizer.rotation = 0.0
}