touchesBegan, touchesEnded, touchesMoved for moving UIView - ios

I need to drag my UIView object. I use this code, but it does not work
float oldX, oldY;
BOOL dragging;
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:self];
if ([[touch.view class] isSubclassOfClass:[UILabel class]]) {
UILabel *label = (UILabel *)touch.view;
if (CGRectContainsPoint(label.frame, touchLocation)) {
dragging = YES;
oldX = touchLocation.x;
oldY = touchLocation.y;
}
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
dragging = NO;
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:self];
if ([[touch.view class] isSubclassOfClass:[UILabel class]]) {
UILabel *label = (UILabel *)touch.view;
if (dragging) {
CGRect frame = label.frame;
frame.origin.x = label.frame.origin.x + touchLocation.x - oldX;
frame.origin.y = label.frame.origin.y + touchLocation.y - oldY;
label.frame = frame;
}
}
}

I would suggest using a UIPanGestureRecognizer:
-(void)dragging:(UIPanGestureRecognizer *)gesture
{
// Check if this is the first touch
if(gesture.state == UIGestureRecognizerStateBegan)
{
// Store the initial touch so when we change positions we do not snap
self.panCoord = [gesture locationInView:gesture.view];
[self.view bringSubviewToFront:gesture.view];
}
CGPoint newCoord = [gesture locationInView:gesture.view];
// Create the frame offsets to use our finger position in the view.
float dX = newCoord.x-self.panCoord.x;
float dY = newCoord.y-self.panCoord.y;
gesture.view.frame = CGRectMake(gesture.view.frame.origin.x+dX,
gesture.view.frame.origin.y+dY,
gesture.view.frame.size.width,
gesture.view.frame.size.height);
}
This is just a preference of mine. To me it is a lot simpler using a gesture recognizer then using touchesBegan, touchesEnded, touchesMoved. I will use these in cases where the UIPanGestureRecognizer will not work.

This is work code for move UIView objects
float oldX, oldY;
BOOL dragging;
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:touch.view];
if ([[touch.view class] isSubclassOfClass:[UILabel class]]) {
dragging = YES;
oldX = touchLocation.x;
oldY = touchLocation.y;
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
dragging = NO;
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:touch.view];
if ([[touch.view class] isSubclassOfClass:[UILabel class]]) {
UILabel *label = (UILabel *)touch.view;
if (dragging) {
CGRect frame = label.frame;
frame.origin.x = label.frame.origin.x + touchLocation.x - oldX;
frame.origin.y = label.frame.origin.y + touchLocation.y - oldY;
label.frame = frame;
}
}
}

There's something a bit strange in your code.
You ask for the location in self, some UIView which presumably contains the UILabel you want to check. This begs the question as to why you do not add the touchesXXX to some UILabel subclass of yours.
This cancels out as you're using the label.frame which is defined in terms of its superview.bounds (your parent UIView you asked the touch location with respect to), but this doesn't make for the most straightforward way to follow what's going on.

With this code i could move my UIView Object anywhere.
My ViewController.swift looks like this.
// code from below
import UIKit
class ViewController: UIViewController {
var location = CGPoint(x: 0, y: 0)
#IBOutlet weak var Person: UIImageView!
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
var touch : UITouch! = touches.first! as UITouch
location = touch.location(in: self.view)
Person.center = location
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
var touch : UITouch! = touches.first! as UITouch
location = touch.location(in: self.view)
Person.center = location
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
Person.center = CGPoint(x: 160, y: 330)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
//ends
Hope it helps although it is another way to do it than the one mentioned in question.

Related

gesture.view on top [UIPanGestureRecognizer]

I have many of views added as subview for UIScrollView where is already a subview for self.view, during dragging the object i can't see object outside of its superview (UIScrollView) and self.view thus I use bringSubviewToFront but it doesn't work
Any hint please?
-(void)handlePan:(UIPanGestureRecognizer *)gesture {
static CGPoint originalCenter;
static CGPoint originalforScroll;
CGPoint newCoord = [gesture locationInView:self.view];
int viewTag = gesture.view.tag;
if(gesture.state == UIGestureRecognizerStateBegan)
{
[gesture.view.superview bringSubviewToFront:gesture.view];
originalCenter = gesture.view.center;
originalforScroll = [gesture locationInView:self.view];
}
if (gesture.state == UIGestureRecognizerStateChanged)
{
CGPoint translate = [gesture translationInView:gesture.view];
gesture.view.center = CGPointMake(originalCenter.x + translate.x, originalCenter.y + translate.y);
}
if (gesture.state == UIGestureRecognizerStateEnded ||
gesture.state == UIGestureRecognizerStateFailed ||
gesture.state == UIGestureRecognizerStateCancelled)
{
}
}

Objective-C Properties and Pointers to Swift

I just started learning Swift and I have been consulting Apple's Dev Guide but some of the syntax when dealing with properties and pointers is throwing me off. Apple explains that properties just use dot syntax and even the API seems to reflect that but it's not working to my desired to effect. Here's what I've been working on specifically. I am also struggling with instance initialization. I have already properly created a bridging header Any guidance would be appreciated. Thanks!
This is the code I am trying to emulate in swift.
#property (nonatomic) SFWaterNode *waterSurface;
#property (nonatomic) NSTimeInterval lastUpdateTime;
#end
#implementation GameScene
- (void)didMoveToView:(SKView *)view {
self.backgroundColor = [SKColor blackColor];
CGPoint startPoint = CGPointMake(-1, self.size.height/2);
CGPoint endPoint = CGPointMake(self.size.width, self.size.height/2);
self.waterSurface = [SFWaterNode nodeWithStartPoint:startPoint endPoint:endPoint depth:self.size.height/2 color:[SKColor blueColor]];
[self addChild:self.waterSurface];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
[self.waterSurface splash:location speed:-50];
}
- (void)update:(CFTimeInterval)currentTime {
[self.waterSurface update:currentTime];
}
#end
Try this code below:
public var waterSurface:SFWaterNode?
var lastUpdateTime:NSTimeInterval
func didMoveToView(view:SKView) {
self.backgroundColor = .black
let startPoint:CGPoint = CGPoint.init(x: -1, y: self.size.height/2)
let endPoint:CGPoint = CGPoint(x: -1, y: self.size.height/2)
self.waterSurface = SFWaterNode.nodeWithStartPoint(startPoint, endPoint:endPoint, depth:self.size.height/2, color:.blue)
self.addChild(self.waterSurface)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch:UITouch = touches.anyObject()
let location:CGPoint = touch.location(inNode: self)
self.waterSurface.splash(location, speed:-50)
}
func update(curentTime:CFTimeInterval) {
self.waterSurface.update(currentTime)
}

SpriteKit SKSpriteNode velocity on touch and hold

I have SKSpriteNode which is forced to fall to the ground because of self.physicsWorld.gravity = CGVectorMake(0.0, -4.0);. When user taps on display and holds it, I'd like the SKSpriteNode to fly up, and after user stops holding touch, it again falls down to the ground.
I have tried to change velocity, but it only makes small bounce, like applyImpulse method...:
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
/* Called when a touch begins */
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
flyingObject.physicsBody.velocity = CGVectorMake(0, 100)
}
}
edit:
here's my scene initialization code
override func didMoveToView(view: SKView) {
/* Setup your scene here */
// Physics
self.physicsWorld.gravity = CGVectorMake(0.0, -4.0);
// flyingObject
var flyingObjectTexture = SKTexture(imageNamed:"flyingObject")
flyingObject.filteringMode = SKTextureFilteringMode.Nearest
flyingObject = SKSpriteNode(texture: flyingObjectTexture)
flyingObject.setScale(1)
flyingObject.position = CGPoint(x: self.frame.size.width * 0.35, y: self.frame.size.height * 0.6)
flyingObject.physicsBody = SKPhysicsBody(circleOfRadius:flyingObject.size.height/2.0)
flyingObject.physicsBody.dynamic = true
flyingObject.physicsBody.allowsRotation = false
self.addChild(flyingObject)
// Ground
var groundTexture = SKTexture(imageNamed:"Ground")
var sprite = SKSpriteNode(texture:groundTexture)
sprite.setScale(0.5)
sprite.position = CGPointMake(self.size.width/2 - 100, sprite.size.height)
self.addChild(sprite)
var ground = SKNode()
ground.position = CGPointMake(0, groundTexture.size().height / 2)
ground.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(self.frame.width, groundTexture.size().height * 0.5))
ground.physicsBody.dynamic = false
self.addChild(ground)
}
thanks to Code Monkey I was able to come up with solution, it's easier than I thought:
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
/* Called when a touch begins */
isTouching = true
}
override func touchesEnded(touches: NSSet!, withEvent event: UIEvent!) {
/* Called when a touch begins */
isTouching = false
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
if isTouching {
flyingObject.physicsBody.applyImpulse(CGVectorMake(0, 5))
}
}
touches began:
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch * touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
flyingObject.physicsBody.velocity = CGVectorMake(0, 100)
}
touches ended:
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch * touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
flyingObject.physicsBody.velocity = CGVectorMake(0, 0)
}

move and rotate an image with fingers on a view ios xcode

Moving and rotating an image with finger's
- (void)viewDidLoad
{
self.imageview.image = [UIImage imageNamed:#"Image.png"];
[self.view addSubview: self.imageview];
[super viewDidLoad];
}
This code is to move image
-(void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event
{
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:touch.view];
self.imageview.center = touchLocation;
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
// get touch event
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:self.PlayVideo];
if ([touch view] == self.view)
{
self.imageview.center = touchLocation;
}
}
This code is to rotate image (T dropped a rotation gesture on to the image and draghed on to .h file)
- (IBAction)regRotation:(UIGestureRecognizer *)sender
{
NSLog(#"rotation");
CGFloat netRotation =0.0;
CGFloat rotation =[(UIRotationGestureRecognizer *)sender rotation];
CGAffineTransform transform=CGAffineTransformMakeRotation(rotation+netRotation);
sender.view.transform=transform;
if(sender.state==UIGestureRecognizerStateEnded)
{
netRotation+=rotation;
}
}
The image is moving and not perfectly rotating
CGFloat firstX;
CGFloat firstY;
CGFloat lastRotation;
- (void)viewDidLoad
{
lastRotation = 0.0;
self.imageview.image = [UIImage imageNamed:#"Image.png"];
[self.view addSubview: self.imageview];
[super viewDidLoad];
UIPanGestureRecognizer* panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(move:)];
[panRecognizer setMinimumNumberOfTouches:1];
[panRecognizer setMaximumNumberOfTouches:1];
[panRecognizer setDelegate:self];
[self.imageview addGestureRecognizer:panRecognizer];
UIRotationGestureRecognizer* rotationRecognizer = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:#selector(rotate:)];
[rotationRecognizer setDelegate:self];
[self.view addGestureRecognizer:rotationRecognizer];
}
-(void)move:(id)sender {
[self.view bringSubviewToFront:[(UIPanGestureRecognizer*)sender view]];
CGPoint translatedPoint = [(UIPanGestureRecognizer*)sender translationInView:self.view];
if([(UIPanGestureRecognizer*)sender state] == UIGestureRecognizerStateBegan) {
firstX = [[sender view] center].x;
firstY = [[sender view] center].y;
}
translatedPoint = CGPointMake(firstX+translatedPoint.x, firstY+translatedPoint.y);
[[sender view] setCenter:translatedPoint];
if([(UIPanGestureRecognizer*)sender state] == UIGestureRecognizerStateEnded) {
CGFloat finalX = translatedPoint.x + (0*[(UIPanGestureRecognizer*)sender velocityInView:self.imageview].x);
CGFloat finalY = translatedPoint.y + (0*[(UIPanGestureRecognizer*)sender velocityInView:self.imageview].y);
[[sender view] setCenter:CGPointMake(finalX, finalY)];
}
}
-(void)rotate:(id)sender {
if([(UIRotationGestureRecognizer*)sender state] == UIGestureRecognizerStateEnded) {
lastRotation = 0.0;
return;
}
CGFloat rotation = 0.0 - (lastRotation - [(UIRotationGestureRecognizer*)sender rotation]);
CGAffineTransform currentTransform = self.imageview.transform;
CGAffineTransform newTransform = CGAffineTransformRotate(currentTransform,rotation);
[self.imageview setTransform:newTransform];
lastRotation = [(UIRotationGestureRecognizer*)sender rotation];
}
Its working for me..
Swift 4 answer for Pan, Zoom and Rotate:
var lastRotation : CGFloat = 0.0
var previousScale : CGFloat = 1.0
var beginX : CGFloat = 0.0
var beginY : CGFloat = 0.0
override func viewDidLoad(){
super.viewDidLoad()
let rotationGesture = UIRotationGestureRecognizer.init(target: self, action: #selector(ViewController.rotate(sender:)))
self.imageView.addGestureRecognizer(rotationGesture)
let pinchGesture = UIPinchGestureRecognizer.init(target: self, action: #selector(ViewController.scale(sender:)))
self.imageView.addGestureRecognizer(pinchGesture)
let panGesture = UIPanGestureRecognizer.init(target: self, action: #selector(ViewController.pan(sender:)))
panGesture.minimumNumberOfTouches = 1
panGesture.maximumNumberOfTouches = 1
self.imageView.addGestureRecognizer(panGesture)
}
#objc func rotate(sender : Any){
if let sender = sender as? UIRotationGestureRecognizer, let imageView = self.imageView{
if sender.state == .ended{
lastRotation = 0.0
return
}
let rotation : CGFloat = 0.0 - (lastRotation - sender.rotation)
let currentTransform = imageView.transform
let newTransform = currentTransform.rotated(by: rotation)
imageView.transform = newTransform
lastRotation = sender.rotation
}
}
#objc func scale(sender : Any){
if let sender = sender as? UIPinchGestureRecognizer, let imageView = self.imageView{
if sender.state == .ended{
previousScale = 1.0
return
}
let newScale = 1.0 - (previousScale - sender.scale)
let currentTransform = imageView.transform
let newTransform = currentTransform.scaledBy(x: newScale, y: newScale)
imageView.transform = newTransform
previousScale = sender.scale
}
}
#objc func pan(sender : Any){
if let sender = sender as? UIPanGestureRecognizer, let imageView = self.imageView{
var newCenter = sender.translation(in: self.view)
if(sender.state == .began){
beginX = imageView.center.x
beginY = imageView.center.y
}
newCenter = CGPoint.init(x: beginX + newCenter.x, y: beginY + newCenter.y)
imageView.center = newCenter
}
}

Pan, zoom, rotate UIView around anchorPoint using UIGestureRecognizer (iOS)

I'm trying to rotate, pan and zoom an UIView using UIGestureRecognizers. The recognisers are added to the superview, while the rotation,zoom etc is applied to a subview (_baseImage) this is to enable me to overlay other things on top of the subview in future while still receiving the gesture events.
The idea is that the UIView should scale/rotate around an "anchor" point on the subview underneath the two touch points as this seems the most natural. What I'm having problems with is the position of the subview after setting the anchorPoint, and also that the scale and rotation doesn't seem to use the set anchorPoint. My lack of understanding of overlapping co-ordinate systems/CGAffine transforms may be getting me into trouble. Code is pulled from various examples.
Here's my code as it stands at the moment:
-(void)setAnchorPoint:(CGPoint)anchorPoint forView:(UIView *)view
{
CGPoint oldOrigin = view.frame.origin;
view.layer.anchorPoint = anchorPoint;
CGPoint newOrigin = view.frame.origin;
CGPoint transition;
transition.x = newOrigin.x - oldOrigin.x;
transition.y = newOrigin.y - oldOrigin.y;
view.center = CGPointMake (view.center.x - transition.x, view.center.y - transition.y);
}
- (void) updateTransformWithOffset: (CGPoint) translation
{
// Create a blended transform representing translation,
// rotation, and scaling
_baseImage.transform = CGAffineTransformMakeTranslation(translation.x + tx, translation.y + ty);
_baseImage.transform = CGAffineTransformRotate(_baseImage.transform, theta);
_baseImage.transform = CGAffineTransformScale(_baseImage.transform, scale, scale);
}
- (void)adjustAnchorPointForGestureRecognizer:(UIGestureRecognizer *)uigr {
if (uigr.state == UIGestureRecognizerStateBegan) {
UIView *piece = self.view;
CGPoint locationInView = [uigr locationInView:_baseImage];
myFrame = _baseImage.frame;
CGPoint newAnchor = CGPointMake( (locationInView.x / piece.bounds.size.width), (locationInView.y / piece.bounds.size.height ));
[self setAnchorPoint:newAnchor forView:_baseImage];
}
}
- (void) handlePinch: (UIPinchGestureRecognizer *) uigr
{
[self adjustAnchorPointForGestureRecognizer:uigr];
if (uigr.state == UIGestureRecognizerStateBegan) {
initScale = scale;
}
scale = initScale*uigr.scale;
[self updateTransformWithOffset:CGPointZero];
}
I've found a solution to my specific problem with the anchorPoint. I was trying to apply transforms to a UIView added in Interface Builder which caused problems with the anchor point and setting new centre point, removing then re-adding the subview seemed to fix it. If anyone has similar problems here is the final code I used on my view controller, it does scale,rotate and pan on a UIView using the touch position as centre for rotate and scale:
#import "ViewController.h"
#interface ViewController (){
CGFloat tx; // x translation
CGFloat ty; // y translation
CGFloat scale; // zoom scale
CGFloat theta; // rotation angle
CGFloat initScale ;
CGFloat initTheta ;
}
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UIRotationGestureRecognizer *rotationGesture = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:#selector(handleRotation:)];
[rotationGesture setDelegate:self];
[self.view addGestureRecognizer:rotationGesture];
UIPinchGestureRecognizer *pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:#selector(handlePinch:)];
[pinchGesture setDelegate:self];
[self.view addGestureRecognizer:pinchGesture];
UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handlePan:)];
[panGesture setDelegate:self];
[panGesture setMinimumNumberOfTouches:1];
[panGesture setMaximumNumberOfTouches:1];
[self.view addGestureRecognizer:panGesture];
_baseImage.transform = CGAffineTransformIdentity;
tx = 0.0f; ty = 0.0f; scale = 1.0f; theta = 0.0f;
scale = 1.0;
//removing and adding back to the view seems to fix problems with anchor point I was having, I suspect because of IB layout/scaling and constraints etc
UIView *mySuperView =_baseImage.superview;
[_baseImage removeFromSuperview];
[mySuperView addSubview:_baseImage];
}
-(void)setAnchorPoint:(CGPoint)anchorPoint forView:(UIView *)myview
{
CGPoint oldOrigin = myview.frame.origin;
myview.layer.anchorPoint = anchorPoint;
CGPoint newOrigin = myview.frame.origin;
CGPoint transition;
transition.x = (newOrigin.x - oldOrigin.x);
transition.y = (newOrigin.y - oldOrigin.y);
CGPoint myNewCenter = CGPointMake (myview.center.x - transition.x, myview.center.y - transition.y);
myview.center = myNewCenter;
}
- (void) updateTransformWithOffset: (CGPoint) translation
{
// Create a blended transform representing translation,
// rotation, and scaling
_baseImage.transform = CGAffineTransformMakeTranslation(translation.x + tx, translation.y + ty);
_baseImage.transform = CGAffineTransformRotate(_baseImage.transform, theta);
_baseImage.transform = CGAffineTransformScale(_baseImage.transform, scale, scale);
}
- (void)adjustAnchorPointForGestureRecognizer:(UIGestureRecognizer *)uigr {
if (uigr.state == UIGestureRecognizerStateBegan) {
tx =_baseImage.transform.tx;
ty =_baseImage.transform.ty;
CGPoint locationInView = [uigr locationInView:_baseImage];
CGPoint newAnchor = CGPointMake( (locationInView.x / _baseImage.bounds.size.width), (locationInView.y / _baseImage.bounds.size.height ));
[self setAnchorPoint:newAnchor forView:_baseImage];
}
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
// if the gesture recognizers are on different views, don't allow simultaneous recognition
if (gestureRecognizer.view != otherGestureRecognizer.view)
return NO;
if (![gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]] && ![otherGestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]) {
return YES;
}
return NO;
}
- (void) handleRotation: (UIRotationGestureRecognizer *) uigr
{
if (uigr.state == UIGestureRecognizerStateBegan) {
initTheta = theta;
}
theta = initTheta+uigr.rotation;
[self adjustAnchorPointForGestureRecognizer:uigr];
[self updateTransformWithOffset:CGPointZero];
}
- (void) handlePinch: (UIPinchGestureRecognizer *) uigr
{
if (uigr.state == UIGestureRecognizerStateBegan) {
initScale = scale;
}
scale = initScale*uigr.scale;
[self adjustAnchorPointForGestureRecognizer:uigr];
[self updateTransformWithOffset:CGPointZero];
}
- (void) handlePan: (UIPanGestureRecognizer *) uigr
{
CGPoint translation = [uigr translationInView:_baseImage.superview];
[self adjustAnchorPointForGestureRecognizer:uigr];
[self updateTransformWithOffset:translation];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
The OP's original solution translated to Swift 2.0. I left out the workaround since it doesn't seem to be an issue anymore.
class ViewController: UIViewController {
var tx:CGFloat = 0.0 // x translation
var ty:CGFloat = 0.0 // y translation
var scale:CGFloat = 1.0 // zoom scale
var theta:CGFloat = 0.0 // rotation angle
var initScale:CGFloat = 1.0
var initTheta:CGFloat = 0.0
var transformedView: UIView = UIView()
override func viewDidLoad() {
super.viewDidLoad()
transformedView.frame = CGRect(x: 0, y: 0, width: 200, height: 200)
transformedView.backgroundColor = UIColor.blueColor()
view.addSubview(transformedView)
let rotationGesture = UIRotationGestureRecognizer(target: self, action: #selector(OHPlastyViewController.handleRotation(_:)))
rotationGesture.delegate = self
view.addGestureRecognizer(rotationGesture)
let pinchGesture = UIPinchGestureRecognizer(target: self, action: #selector(OHPlastyViewController.handlePinch(_:)))
pinchGesture.delegate = self
view.addGestureRecognizer(pinchGesture)
let panGesture = UIPanGestureRecognizer(target: self, action: #selector(OHPlastyViewController.handlePan(_:)))
panGesture.delegate = self
panGesture.minimumNumberOfTouches = 1
panGesture.maximumNumberOfTouches = 1
view.addGestureRecognizer(panGesture)
}
func setAnchorPoint(anchorPoint: CGPoint, forView myView: UIView) {
let oldOrigin: CGPoint = myView.frame.origin
myView.layer.anchorPoint = anchorPoint
let newOrigin = myView.frame.origin
let transition = CGPoint(x: newOrigin.x - oldOrigin.x, y: newOrigin.y - oldOrigin.y)
let myNewCenter = CGPoint(x: myView.center.x - transition.x, y: myView.center.y - transition.y)
myView.center = myNewCenter
}
func updateTransformWithOffset(translation: CGPoint) {
transformedView.transform = CGAffineTransformMakeTranslation(translation.x + tx, translation.y + ty)
transformedView.transform = CGAffineTransformRotate(transformedView.transform, theta)
transformedView.transform = CGAffineTransformScale(transformedView.transform, scale, scale)
}
func adjustAnchorPointForGestureRecognizer(recognizer: UIGestureRecognizer) {
if (recognizer.state == .Began) {
tx = transformedView.transform.tx
ty = transformedView.transform.ty
let locationInView = recognizer.locationInView(transformedView)
let newAnchor = CGPoint(x: (locationInView.x / transformedView.bounds.size.width), y: (locationInView.y / transformedView.bounds.size.height))
setAnchorPoint(newAnchor, forView: transformedView)
}
}
func handleRotation(recognizer: UIRotationGestureRecognizer) {
if recognizer.state == .began {
initTheta = theta
}
theta = initTheta + recognizer.rotation
adjustAnchorPointForGestureRecognizer(recognizer)
updateTransformWithOffset(CGPointZero)
}
func handlePinch(recognizer: UIPinchGestureRecognizer) {
if recognizer.state == .began {
initScale = scale
}
scale = initScale * recognizer.scale
adjustAnchorPointForGestureRecognizer(recognizer)
updateTransformWithOffset(CGPointZero)
}
func handlePan(recognizer: UIPanGestureRecognizer) {
let translation = recognizer.translationInView(transformedView.superview)
adjustAnchorPointForGestureRecognizer(recognizer)
updateTransformWithOffset(translation)
}
}
extension ViewController: UIGestureRecognizerDelegate {
func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWithGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool {
if gestureRecognizer.view != otherGestureRecognizer.view {
return false
}
if !gestureRecognizer.isKindOfClass(UITapGestureRecognizer.self) && !otherGestureRecognizer.isKindOfClass(UITapGestureRecognizer.self) {
return true
}
return false
}
}

Resources