I'm using a rotation gesture recognizer to rotate a UIView. After I've rotated the view the x and y coordinates of the pan gesture are off their axis and I can't see why.
Here is my current gesture setup:
open func handleRotate(sender: UIRotationGestureRecognizer) {
if sender.state == .began || sender.state == .changed {
sender.view?.transform = (sender.view?.transform)!.rotated(by: sender.rotation)
sender.rotation = 0
}
}
#objc fileprivate func handleDrag(sender: UIPanGestureRecognizer) {
let translation = sender.translation(in: self)
sender.view!.center = CGPoint(x: sender.view!.center.x + translation.x, y: sender.view!.center.y + translation.y)
sender.setTranslation(.zero, in: self)
}
So when I rotate the UIView the x and y panning are off (Moving up moves the uiview to the left or right depending upon the UIview's rotated state).
Thanks
There's quite a lot to unpack with the code example provided, but for starters the drag handler is setting the center point of the view, which might be a hint as to why the rotation gesture is askew.
Rather than setting the transform property of the view independently in each handler, you might get the result you're looking for if you modify the existing transforms.
The SO answer here goes into a bit more depth, and might help:
Using multiple UIGestureRecognizers simultaneously like UIRotationGestureRecognizer & UIPanGestureRecognizer in Swift 3
Related
I am working on TextView as like Sticker View.I am successfully done but I can not wrap as I want. I want like this please check this clip and I am getting this output please check this output clip. From 1st clip I want like that and second video I am getting that.
In 1st video you can see when scaling the TextView It doesn't scale with center and when panning from right side of the TextView you can see it will decrease/increase width only.
In 2nd video(This is I am getting) you can see when scaling the TextView it will scale from the center that I don't want.
I want scale like 1st video. Hope you are understand.
I'm using this code
#objc func scaleGesture(_ recognizer: UIPanGestureRecognizer) {
touchLocation = recognizer.location(in: superview)
if recognizer.state == .began {
initialBounds = bounds
}
if recognizer.state == .changed {
let horizontalChange = recognizer.translation(in: self).x
let verticalChange = recognizer.translation(in: self).y
bounds = CGRect(x: initialBounds!.origin.x, y: initialBounds!.origin.y, width: initialBounds!.width + horizontalChange, height: initialBounds!.height + verticalChange)
}
}
Please help me. Thanks in advance.
I have a sticker which is draggable as I drag it and while dragging it when my finger reaches below the white board and that delete imageview appears and when I have reached there location. How do I detect touch on that imageview.
I am using pan gesture for dragging and pinch and rotation gestures also at the same time. But how will I know that I have touched my delete ImageView
Here is the image which has a stickerView on the back which is draggable and has a delete imageView on the front of the stickerView which is fixed.
#objc func handlePanGesture(_ gestureRecognizer:UIPanGestureRecognizer){
switch gestureRecognizer.state {
case .began:
// panGestureInStickerViewClosure?(true)
break
case .changed:
// panGestureInStickerViewClosure?(true)
let deleteImageView = gestureRecognizer.view?.superview?.subviews.filter{$0.isKind(of: UIImageView.self)}[safe: 0]
deleteImageView?.addGestureRecognizer(BlockGestureRecognizer())
let stickerImageViewFrame = gestureRecognizer.view?.superview?.subviews.filter{$0.isKind(of: HBStickerView.self)}[safe: 0]
let translation = gestureRecognizer.translation(in: self)
print("translation=\(translation),deleteImageView?.frame=\(deleteImageView?.frame),stickerImageViewFrame?.frame=\(stickerImageViewFrame?.frame)")
break
case .ended:
break
default:
break
}
print(gestureRecognizer.numberOfTouches)
if gestureRecognizer.numberOfTouches == 1{
panGestureInStickerViewClosure?(true)
}else if gestureRecognizer.numberOfTouches > 1{
panGestureInStickerViewClosure?(false)
}
let translation = gestureRecognizer.translation(in: self.superview)
self.center = CGPoint(x: self.center.x + translation.x, y: self.center.y + translation.y)
gestureRecognizer.setTranslation(CGPoint.zero, in: self.superview)
print(gestureRecognizer.location(in: self.superview))
//print("self.frame.maxY=\(self.frame.maxY),self.superview?.frame.maxY=\(self.superview?.frame.maxY),self.center=\(self.center),gestureRecognizer.location(in: self)=\(gestureRecognizer.location(in: self))")
// panGestureInStickerViewClosure?(true)
}
I have above code written for pan gesture
I am using this gesture recognizer for panning. But getting translation location also does not work for me. If I can get the gesture location for my thumb or any finger and perform my need.
All I want to get touch event on that delete ImageView in front of all Subview while I am dragging the StickerView below that Subview.
Let me give you an example of Instagram. An Instagram has stickers which you can drag around and pinch and rotate and when it comes to deleting you have to touch on that delete button then the delete button gets scaled to max size and StickerView gets to scaled-down and finally is removed from the superView.
I have a subview in a viewController to which I added a UIPanGestureRecognizer. I'd like to expand such subview when the user drags it down, so I'm trying to handle the gesture recognizer status like this:
#objc func panning(_ gestureRecognizer: UIPanGestureRecognizer) {
let translation = gestureRecognizer.translation(in: view)
if gestureRecognizer.state == .began {
originalFrame = self.mySubview.frame
} else if gestureRecognizer.state == .changed {
if translation.y > 0 {
var newFrame = originalFrame
newFrame.size.height += translation.y
mySubview.frame = newFrame
}
}
}
when I set a breakpoint at mySubview.frame = newFrame, I see that newFrame is updated with the translation. However, I don't see the frame changes in the screen, the subview looks always like at the beginning.
What could I be missing?
PanGesture is a tricky, but working with it is very interesting...
I am assuming you have added pan gesture correctly to the view. So writing down the handling of the gesture only.
func handlePanGesture(_ gesture: UIPanGestureRecognizer) {
var translatedPoint: CGPoint = gesture.translation(in: self.superview)
let playerCenterX: CGFloat = (gesture.view?.center.x)! + translatedPoint.x
let playerCenterY: CGFloat = (gesture.view?.center.y)! + translatedPoint.y
translatedPoint = CGPoint.init(x: playerCenterX,
y: playerCenterY)
gesture.view?.center = translatedPoint
gesture.setTranslation(CGPoint.zero, in: self.superview)
}
Important thing is that you set its translation back to zero every time at the end of gesture movement.
As per your requirement change this self.superview and use the coordinates to update your view frame...
If your view's frame is set by the autolayout you should update constraints, not the view's frame itself.
I have a movable UIAction Button similar to Reddit's Scroll up button and the Assistive Touch Feature. Right now I'm having a hard time finding a way to either:
1. Not go out of bounds in the first place or
2. Bounce Back to the screen similar tot he way that Assistive Touch does.
Here's what I have in my UIPanGesture function:
#IBAction func dragSettingsButton(_ sender: UIPanGestureRecognizer) {
if sender.state == .began || sender.state == .changed {
if displayView.frame.contains(sender.location(in: self.view)) {
let translation = sender.translation(in: displayView)
// note: 'view' is optional and need to be unwrapped
sender.view!.center = CGPoint(x: sender.view!.center.x + translation.x, y: sender.view!.center.y + translation.y)
sender.setTranslation(CGPoint.zero, in: displayView)
}
else {
print("WOW BRO YOURE OUT OF BOUNDS")
}
}
}
Things to note: I have a ViewController where there are 3 views: A view to act as a custom navigation bar, a view to act as a custom segmented view, and a display view to display different views when the segmented view is switched.
There is also a Tab bar on the bottom
To bounce back:
On sender.state == .end use the same logic to determine if its out of bounds. If so calculate where it should be. Then animate it to that location.
I have the following code that drags a UIView. All works fine visually.
func moveView(sender: UIPanGestureRecognizer) {
let translate = sender.translationInView(self.view)
if sender.state == UIGestureRecognizerState.Changed {
sender.view!.center = CGPoint(x:sender.view!.center.x + translate.x, y:sender.view!.center.y + translate.y)
sender.setTranslation(CGPointZero, inView: self.view)
}
if sender.state == UIGestureRecognizerState.Ended {
let newX: CGFloat = sender.view!.center.x + translate.x
let newY: CGFloat = sender.view!.center.y + translate.y
sender.view!.center = CGPoint(x:newX, y:newY)
}
}
However after completing this drag, the view seems to lose the gesture connection such that I can't drag it again or trigger any tap gesture associated with it etc.
If I add an NSLog I can see that tapping where the view used to be triggers the log but not if I tap on the actual current view location.
I establish the gesture to view thisView with the following within viewDidLoad
let moveGesture = UIPanGestureRecognizer(target: self, action: Selector("moveView:"))
thisView.addGestureRecognizer(moveGesture)
What am I missing that keeps the gestures connected to the new view location?
Thanks.
I think that when you call this sender.setTranslation(CGPointZero, inView: self.view) maybe you should set the translation relative to superview and not to the view itself. Setting the translation relative to itself change the position of the view contents but not the view area, which means that if you set the view layer to mask to its bounds you shouldn't see anything that it's outside of the view initial area.
So you should do sender.setTranslation(CGPointZero, inView: self.view.superview).