How To apply UIGestureRecognizerDelegate On UIView Instead of UIViewController - ios

Hi all I am doing pinch zoom & pan on UIImageView which is inside a UIView for this I have written code which is working fine . My problem is when i am rotation OR pinching the image,it's not rotating OR panning from centre part of images. If i am doing same code on UIViewController this code is working great for Rotation & panning also .Please help me what i have mistaken here
in GestureRecognizer_UIView.h file :
#import <UIKit/UIKit.h>
#interface GestureRecognizer_UIView : UIView<UIGestureRecognizerDelegate>
#property (weak, nonatomic) IBOutlet UIImageView *imageView; #property CGFloat lastRotation;
#end
In GestureRecognizer_UIView.m file
#import "GestureRecognizer_UIView.h"
#implementation GestureRecognizer_UIView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
// Initialization code
}
return self;
}
-(void)awakeFromNib
{
UIRotationGestureRecognizer *rotationG = [[UIRotationGestureRecognizer alloc]
initWithTarget:self action:#selector(rotationImage:)];
rotationG.delegate = self;
UIPinchGestureRecognizer *pinchGestureRecongnizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:#selector(changeImage:)];
pinchGestureRecongnizer.delegate = self;
UIPanGestureRecognizer *panGesture=[[UIPanGestureRecognizer alloc]initWithTarget:self action:#selector(panpan:)];
panGesture.delegate = self;
[_imageView addGestureRecognizer:pinchGestureRecongnizer];
[_imageView addGestureRecognizer:rotationG];
[_imageView addGestureRecognizer:panGesture];
}
- (void)panpan:(UIPanGestureRecognizer *)sender {
[self bringSubviewToFront:_imageView];
CGPoint translation = [sender translationInView:self];
CGPoint imageViewPosition = _imageView.center;
imageViewPosition.x += translation.x;
imageViewPosition.y += translation.y;
_imageView.center = imageViewPosition;
[sender setTranslation:CGPointZero inView:self];
}
-(void)rotationImage:(UIRotationGestureRecognizer*)gesture {
[self bringSubviewToFront:gesture.view];
CGPoint location = [gesture locationInView:self];
gesture.view.center = CGPointMake(location.x, location.y);
if ([gesture state] == UIGestureRecognizerStateEnded) {
self.lastRotation = 0;
return;
}
CGAffineTransform currentTransform = _imageView.transform;
CGFloat rotation = 0.0 - (self.lastRotation - gesture.rotation);
CGAffineTransform newTransform = CGAffineTransformRotate(currentTransform, rotation);
_imageView.transform = newTransform;
self.lastRotation = gesture.rotation;
}
- (void)changeImage:(UIPinchGestureRecognizer*)pinchGestureRecognizer {
[self bringSubviewToFront:pinchGestureRecognizer.view];
CGPoint location = [pinchGestureRecognizer locationInView:self];
pinchGestureRecognizer.view.center = CGPointMake(location.x, location.y);
pinchGestureRecognizer.view.transform = CGAffineTransformScale(pinchGestureRecognizer.view.transform, pinchGestureRecognizer.scale, pinchGestureRecognizer.scale);
pinchGestureRecognizer.scale = 1;
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
#end

Related

in Xcode 6, scale value from image diff with value in UIPinchGestureRecognizer

Now i develop an app that all user drag, rotate and scale image inside uiview. but when i want to save image view data like rotate value and scale value. i found scale value from [[img.layer valueForKeyPath:#"transform.scale"] floatValue] diff with scale that i found. the scale value is like below.
-(void)scale:(id)sender {
if([(UIPinchGestureRecognizer*)sender state] == UIGestureRecognizerStateBegan) {
_lastScale = 1.0;
}
CGFloat scale = 1.0 - (_lastScale - [(UIPinchGestureRecognizer*)sender scale]);
//CGFloat scale = 1.0 + ([(UIPinchGestureRecognizer *)sender scale] - _lastScale);
CGAffineTransform currentTransform = self.transform;
CGAffineTransform newTransform = CGAffineTransformScale(currentTransform, scale, scale);
[self setTransform:newTransform];
_lastScale = [(UIPinchGestureRecognizer*)sender scale];
CGFloat size = [[self.layer valueForKeyPath:#"transform.scale"] floatValue];
self.saveScale = _lastScale;
NSLog(#"Scale %f %f",_lastScale, size);
}
so the save scale value is diff with [[img.layer valueForKeyPath:#"transform.scale"].
PLEASE HELP!!!
Declare Variable -> CGFloat currentScale;
- (void) handlePinches:(UIPinchGestureRecognizer*)paramSender{
if (paramSender.state == UIGestureRecognizerStateEnded){
currentScale = paramSender.scale;
} else if (paramSender.state == UIGestureRecognizerStateBegan &&
self.currentScale != 0.0f){
paramSender.scale = currentScale;
}
if (paramSender.scale != NAN &&
paramSender.scale != 0.0){
paramSender.view.transform =
CGAffineTransformMakeScale(paramSender.scale,
paramSender.scale);
}
}
try this
You need to add Delegate
#interface MyClass : MySuperClass <UIGestureRecognizerDelegate>
- (void)viewDidLoad
{
[super viewDidLoad];
// set up the image view
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"someImage"]];
[imageView setBounds:CGRectMake(0.0, 0.0, 120.0, 120.0)];
[imageView setCenter:self.view.center];
[imageView setUserInteractionEnabled:YES]; // <--- This is very important
// create and configure the pinch gesture
UIPinchGestureRecognizer *pinchGestureRecognizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:#selector(pinchGestureDetected:)];
[pinchGestureRecognizer setDelegate:self];
[imageView addGestureRecognizer:pinchGestureRecognizer];
// create and configure the rotation gesture
UIRotationGestureRecognizer *rotationGestureRecognizer = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:#selector(rotationGestureDetected:)];
[rotationGestureRecognizer setDelegate:self];
[imageView addGestureRecognizer:rotationGestureRecognizer];
[self.view addSubview:imageView]; // add the image view as a subview of the view controllers view
}
add this two methods
- (void)pinchGestureDetected:(UIPinchGestureRecognizer *)recognizer
{
UIGestureRecognizerState state = [recognizer state];
if (state == UIGestureRecognizerStateBegan || state == UIGestureRecognizerStateChanged)
{
CGFloat scale = [recognizer scale];
[recognizer.view setTransform:CGAffineTransformScale(recognizer.view.transform, scale, scale)];
[recognizer setScale:1.0];
}
}
- (void)rotationGestureDetected:(UIRotationGestureRecognizer *)recognizer
{
UIGestureRecognizerState state = [recognizer state];
if (state == UIGestureRecognizerStateBegan || state == UIGestureRecognizerStateChanged)
{
CGFloat rotation = [recognizer rotation];
[recognizer.view setTransform:CGAffineTransformRotate(recognizer.view.transform, rotation)];
[recognizer setRotation:0];
}
}
after add this delegate method
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
you can handle also pangesture using this method.
add pan gesture in to image.
self.panResizeGesture = [[UIPanGestureRecognizer alloc]initWithTarget:self action:#selector(handlePanGestures:)];
imgPatSelect.userInteractionEnabled = YES;
[imgPatSelect addGestureRecognizer:self.panResizeGesture];
add this method to handle pan.
- (void) handlePanGestures:(UIPanGestureRecognizer*)recognizer{
CGPoint translation = [recognizer translationInView:self.view];
CGRect recognizerFrame = recognizer.view.frame;
recognizerFrame.origin.x += translation.x;
recognizerFrame.origin.y += translation.y;
// Check if UIImageView is completely inside its superView
if (CGRectContainsRect(self.view.bounds, recognizerFrame)) {
recognizer.view.frame = recognizerFrame;
}
// Else check if UIImageView is vertically and/or horizontally outside of its
// superView. If yes, then set UImageView's frame accordingly.
// This is required so that when user pans rapidly then it provides smooth translation.
else {
// Check vertically
if (recognizerFrame.origin.y < self.view.bounds.origin.y) {
recognizerFrame.origin.y = 0;
}
else if (recognizerFrame.origin.y + recognizerFrame.size.height > self.view.bounds.size.height) {
recognizerFrame.origin.y = self.view.bounds.size.height - recognizerFrame.size.height;
}
// Check horizantally
if (recognizerFrame.origin.x < self.view.bounds.origin.x) {
recognizerFrame.origin.x = 0;
}
else if (recognizerFrame.origin.x + recognizerFrame.size.width > self.view.bounds.size.width) {
recognizerFrame.origin.x = self.view.bounds.size.width - recognizerFrame.size.width;
}
}
// Reset translation so that on next pan recognition
// we get correct translation value
[recognizer setTranslation:CGPointMake(0, 0) inView:self.view];
}

UIPanGestureRecognizer calculate frame origin to maintain adjacent subview position for image cropping

I have a cropView that holds a cropBoxView subview that also holds four subviews that are square and each have a UIPanGestureRecognizer on them to enable resizing of the crop area.
What I'm trying to do is change the frame size but maintain the adjacent square corner's position, which means I need to calculate a new origin. I'm able to successfully change the frame size, but I can't figure out how to calculate the new origin.
Currently if I pan the bottom right corner of the view it works the way I want (without needing to adjust the origin in the code below), because the adjacent corner is the top left corner so its origin doesn't need to change.
I'd appreciate any help offered.
Edit: See my answer below for a sample GIF of the result and code
CGPoint translation = [recognizer translationInView:self.cropView];
CGRect recognizerFrame = self.cropView.cropBoxView.frame;
// Todo: calculate new origin based on adjacent crop corner
CGFloat testX = recognizerFrame.size.width += translation.x;
CGFloat testY = recognizerFrame.size.height += translation.y;
recognizerFrame.origin.x = recognizerFrame.origin.x - (recognizerFrame.size.width - testX);
recognizerFrame.origin.y = recognizerFrame.origin.y - (recognizerFrame.size.height - testY);
recognizerFrame.size.width += translation.x;
recognizerFrame.size.height += translation.y;
[recognizer setTranslation:CGPointZero inView:self.cropView];
I figured this out on my own, and it seems to work quite nicely.
Result:
What I did was subclass a UIPanGestureRecognizer and define an enum for when the gesture's shouldReceiveTouch delegate method is called to determine which corner was touched in the cropBoxView. So now instead of having a seperate UIPanGestureRecognizer for each corner, I have just one for all four corners now.
Code:
CropBoxCornerPanGestureRecognizer.h
#import <UIKit/UIGestureRecognizerSubclass.h>
#import <UIKit/UIPanGestureRecognizer.h>
typedef NS_ENUM(NSUInteger, corner)
{
TopLeftCorner = 1,
TopRightCorner,
BottomLeftCorner,
BottomRightCorner
};
#interface CropBoxCornerPanGestureRecognizer : UIPanGestureRecognizer
#property (nonatomic, assign) NSUInteger corner;
#end
CropBoxCornerPanGestureRecognizer.m
#import "CropBoxCornerPanGestureRecognizer.h"
#interface CropBoxCornerPanGestureRecognizer ()
#end
#implementation CropBoxCornerPanGestureRecognizer
#end
ViewController.h:
#interface ViewController : UIViewController <UIGestureRecognizerDelegate>
#end
ViewController.m:
#interface ViewController ()
#property (nonatomic, strong) CropBoxCornerPanGestureRecognizer *cropBoxCornerPanRecognizer;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.cropBoxCornerPanRecognizer = [[CropBoxCornerPanGestureRecognizer alloc]init];
self.cropBoxCornerPanRecognizer.maximumNumberOfTouches = 1;
self.cropBoxCornerPanRecognizer.delaysTouchesBegan = NO;
self.cropBoxCornerPanRecognizer.delaysTouchesEnded = NO;
self.cropBoxCornerPanRecognizer.cancelsTouchesInView = NO;
[self.cropBoxCornerPanRecognizer addTarget:self action:#selector(panCropBoxCorner:)];
self.cropBoxCornerPanRecognizer.delegate = self;
self.cropView.cropBoxView addGestureRecognizer:self.cropBoxCornerPanRecognizer];
}
- (void)panCropBoxCorner:(CropBoxCornerPanGestureRecognizer *)recognizer
{
if (recognizer.state == UIGestureRecognizerStateBegan || recognizer.state == UIGestureRecognizerStateChanged)
{
CGPoint translation = [recognizer translationInView:self.cropView];
CGRect recognizerFrame = self.cropView.cropBoxView.frame;
if (recognizer.corner == TopLeftCorner)
{
recognizerFrame.size.width -= translation.x;
recognizerFrame.size.height -= translation.y;
recognizerFrame.origin.x += translation.x;
recognizerFrame.origin.y += translation.y;
}
else if (recognizer.corner == TopRightCorner)
{
recognizerFrame.size.width += translation.x;
recognizerFrame.size.height -= translation.y;
recognizerFrame.origin.y += translation.y;
}
else if (recognizer.corner == BottomLeftCorner)
{
recognizerFrame.size.width -= translation.x;
recognizerFrame.size.height += translation.y;
recognizerFrame.origin.x += translation.x;
}
else if (recognizer.corner == BottomRightCorner)
{
recognizerFrame.size.width += translation.x;
recognizerFrame.size.height += translation.y;
}
CGFloat minFrameSize = 40.0;
CGFloat maxFrameWidth = self.cropView.frame.size.width;
CGFloat maxFrameHeight = self.cropView.frame.size.height;
if (recognizerFrame.size.width < minFrameSize)
{
recognizerFrame.size = CGSizeMake(minFrameSize, recognizerFrame.size.height);
}
if (recognizerFrame.size.height < minFrameSize)
{
recognizerFrame.size = CGSizeMake(recognizerFrame.size.width, minFrameSize);
}
if (recognizerFrame.size.width > maxFrameWidth)
{
recognizerFrame.size = CGSizeMake(maxFrameWidth, recognizerFrame.size.height);
}
if (recognizerFrame.size.height > maxFrameHeight)
{
recognizerFrame.size = CGSizeMake(recognizerFrame.size.width, maxFrameHeight);
}
[recognizer setTranslation:CGPointZero inView:self.cropView];
}
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
if (gestureRecognizer == self.cropBoxCornerPanRecognizer)
{
CropBoxCornerPanGestureRecognizer *recognizer = (CropBoxCornerPanGestureRecognizer *)gestureRecognizer;
if (CGRectContainsPoint(self.cropView.cropBoxView.topLeftCorner.frame, [touch locationInView:self.cropView.cropBoxView]))
{
recognizer.corner = TopLeftCorner;
return YES;
}
if (CGRectContainsPoint(self.cropView.cropBoxView.topRightCorner.frame, [touch locationInView:self.cropView.cropBoxView]))
{
recognizer.corner = TopRightCorner;
return YES;
}
if (CGRectContainsPoint(self.cropView.cropBoxView.bottomLeftCorner.frame, [touch locationInView:self.cropView.cropBoxView]))
{
recognizer.corner = BottomLeftCorner;
return YES;
}
if (CGRectContainsPoint(self.cropView.cropBoxView.bottomRightCorner.frame, [touch locationInView:self.cropView.cropBoxView]))
{
recognizer.corner = BottomRightCorner;
return YES;
}
return NO;
}
return YES;
}

iOS iPhone sleep / interval before an action

in an UIRotationGestureRecognizer i will do an action drawCircleView.
But this action should start max 10 times in a second.
UIRotationGestureRecognizer *rotation = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:#selector(rotateContainerView:)];
rotation.delegate = self;
[_containerView addGestureRecognizer:rotation];
- (void)rotateContainerView:(UIRotationGestureRecognizer*)sender
{
static CGFloat initialScale;
if (sender.state == UIGestureRecognizerStateBegan) {
initialScale = (_Ro + 0.1)*-1;
_Rotation=0;
}
_Ro = (sender.rotation*-1);
sleep(.1);
[self drawCircleView];
}
I have test the following
sleep(0.1);
[NSThread sleepForTimeInterval:.1];
NSThread sleepUntilDate: [NSDate dateWithTimeIntervalSinceNow:0.1]];
[NSThread sleepForTimeInterval:.1];
But with all it seems that all the action goes in a queue.
How i can do this without a query queue?
Full code
//
// CLHoleEffect.m
//
// Created by Kevin Siml - Appzer.de on 2013/10/23.
// Copyright (c) 2013 Appzer.de. All rights reserved.
//
#import "CLSwirlEffect.h"
#import "UIView+Frame.h"
#interface CLSwirlCircle : UIView
#property (nonatomic, strong) UIColor *color;
#end
#interface CLSwirlEffect()
<UIGestureRecognizerDelegate>
#end
#implementation CLSwirlEffect
{
UIView *_containerView;
UIView *_container;
CLSwirlCircle *_circleView;
UILabel* circleLabel;
CGFloat _X;
CGFloat _Y;
CGFloat _R;
CGFloat _Ro;
CGFloat _Rotation;
}
#pragma mark-
+ (NSString*)defaultTitle
{
return NSLocalizedStringWithDefaultValue(#"CLSwirlEffect_DefaultTitle", nil, [CLImageEditorTheme bundle], #"Swirl", #"");
}
+ (BOOL)isAvailable
{
return ([UIDevice iosVersion] >= 5.0);
}
- (id)initWithSuperView:(UIView*)superview imageViewFrame:(CGRect)frame toolInfo:(CLImageToolInfo *)info
{
self = [super initWithSuperView:superview imageViewFrame:frame toolInfo:info];
if(self){
_containerView = [[UIView alloc] initWithFrame:frame];
[superview addSubview:_containerView];
_X = 0.5;
_Y = 0.5;
_R = 0.5;
_Ro = 0.5;
[self setUserInterface];
}
return self;
}
- (void)cleanup
{
[_containerView removeFromSuperview];
}
- (UIImage*)applyEffect:(UIImage*)image
{
CGFloat R = (_R + 0.1);
GPUImageSwirlFilter *stillImageFilter = [[GPUImageSwirlFilter alloc] init];
[stillImageFilter setAngle: _Ro];
[stillImageFilter setRadius:R];
[stillImageFilter setCenter:CGPointMake(_X,_Y)];
UIImage *quickFilteredImage = [stillImageFilter imageByFilteringImage:image];
return quickFilteredImage;
}
#pragma mark-
- (void)setUserInterface
{
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapContainerView:)];
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(panContainerView:)];
UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:#selector(pinchContainerView:)];
UIRotationGestureRecognizer *rotation = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:#selector(rotateContainerView:)];
pan.maximumNumberOfTouches = 1;
tap.delegate = self;
pan.delegate = self;
pinch.delegate = self;
rotation.delegate = self;
[_containerView addGestureRecognizer:tap];
[_containerView addGestureRecognizer:pan];
[_containerView addGestureRecognizer:pinch];
[_containerView addGestureRecognizer:rotation];
_circleView = [[CLSwirlCircle alloc] init];
_circleView.backgroundColor = [UIColor clearColor];
_circleView.color = [UIColor whiteColor];
[_containerView addSubview:_circleView];
[self drawCircleView];
}
#define DEGREES_TO_RADIANS(x) (M_PI * x / 180.0)
- (void)drawCircleView
{
CGFloat R = MIN(_containerView.width, _containerView.height) * (_R + 0.1) * 1.2;
_circleView.width = R;
_circleView.height = R;
_circleView.center = CGPointMake(_containerView.width * _X, _containerView.height * _Y);
[_circleView setNeedsDisplay];
[self.delegate effectParameterDidChange:self];
}
- (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 either of the gesture recognizers is the long press, don't allow simultaneous recognition
if ([gestureRecognizer isKindOfClass:[UILongPressGestureRecognizer class]] || [otherGestureRecognizer isKindOfClass:[UILongPressGestureRecognizer class]])
return NO;
return YES;
}
- (void)tapContainerView:(UITapGestureRecognizer*)sender
{
CGPoint point = [sender locationInView:_containerView];
_X = MIN(1.0, MAX(0.0, point.x / _containerView.width));
_Y = MIN(1.0, MAX(0.0, point.y / _containerView.height));
[self drawCircleView];
if (sender.state == UIGestureRecognizerStateEnded){
[self.delegate effectParameterDidChange:self];
}
}
- (void)panContainerView:(UIPanGestureRecognizer*)sender
{
CGPoint point = [sender locationInView:_containerView];
_X = MIN(1.0, MAX(0.0, point.x / _containerView.width));
_Y = MIN(1.0, MAX(0.0, point.y / _containerView.height));
[self drawCircleView];
if (sender.state == UIGestureRecognizerStateEnded){
//[self.delegate effectParameterDidChange:self];
}
}
- (void)pinchContainerView:(UIPinchGestureRecognizer*)sender
{
static CGFloat initialScale;
if (sender.state == UIGestureRecognizerStateBegan) {
initialScale = (_R + 0.1);
}
_R = MIN(1.1, MAX(0.1, initialScale * sender.scale)) - 0.1;
[self drawCircleView];
if (sender.state == UIGestureRecognizerStateEnded){
// [self.delegate effectParameterDidChange:self];
}
}
- (void)rotateContainerView:(UIRotationGestureRecognizer*)sender
{
static CGFloat initialScale;
if (sender.state == UIGestureRecognizerStateBegan) {
initialScale = (_Ro + 0.1)*-1;
_Rotation=0;
}
_Ro = (sender.rotation*-1);
[self drawCircleView];
if (sender.state == UIGestureRecognizerStateEnded){
// [self.delegate effectParameterDidChange:self];
}
}
#end
#pragma mark- UI components
#implementation CLSwirlCircle
- (void)setFrame:(CGRect)frame
{
[super setFrame:frame];
[self setNeedsDisplay];
}
- (void)setCenter:(CGPoint)center
{
[super setCenter:center];
[self setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGRect rct = self.bounds;
rct.origin.x += 1;
rct.origin.y += 1;
rct.size.width -= 2;
rct.size.height -= 2;
CGContextSetStrokeColorWithColor(context, self.color.CGColor);
CGContextStrokeEllipseInRect(context, rct);
self.alpha = 1;
[UIView animateWithDuration:kCLEffectToolAnimationDuration
delay:1
options:UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionAllowUserInteraction
animations:^{
self.alpha = 0;
}
completion:^(BOOL finished) {
}
];
}
#end
To restrict the method, rotateContainerView:, being called no more than ten times in a second you could timestamp the first call and compare each subsequent calls timestamp, allowing the method to complete only if the calls timestamp is greater than last calls timestamp plus 0.1 seconds.
Add a property of type NSDate -
#property (nonatomic, strong) NSDate *lastCall;
Then modify rotateContainerView: to something like this -
- (void)rotateContainerView:(UIRotationGestureRecognizer*)sender
{
static CGFloat initialScale;
NSDate *nowCall = [NSDate date];// timestamp
if (sender.state == UIGestureRecognizerStateBegan) {
lastCall = nowCall;
initialScale = (_Ro + 0.1)*-1;
_Rotation=0;
_Ro = (sender.rotation*-1);
[self drawCircleView];
}
else {
if ([nowCall timeIntervalSinceDate:lastCall] > 0.1) {
_Ro = (sender.rotation*-1);
[self drawCircleView];
lastCall = nowCall;
}
}
}
drawRect is what's actually drawing the view. Decouple your data changes and the drawing changes. Draw your circles from drawRect, but change the rotation from a data method that you call instead of your current calls to drawCircleView. If you need to update on intervals, use a NSTimer to schedule calls to a rotate method. But leave the drawing of the actual circles up to drawRect. That way, you have guaranteed rotations, but the drawing happens all the time (which I think is what you want).
Does that make sense?

move image following finger with fix x,y iOS7

How I can move image with fix x,y coordinate smooth (following user finger) in xcode 5.
I have make some code but it doesn't move following my finger gesture (image move instantly to new location)
here my .m
#import "ViewController.h"
#import "MyScene.h"
#interface ViewController()
#property (nonatomic, strong) UISwipeGestureRecognizer *leftSwipeGestureRecognizer;
#property (nonatomic, strong) UISwipeGestureRecognizer *rightSwipeGestureRecognizer;
#end
#implementation ViewController
- (IBAction)HandlePan:(UIPanGestureRecognizer *)recognizer{
CGPoint translation = [recognizer translationInView:self.view];
recognizer.view.center = CGPointMake(recognizer.view.center.x + translation.x, recognizer.view.center.y + translation.y);
[recognizer setTranslation:CGPointMake(0,0) inView:self.view];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.leftSwipeGestureRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(handleSwipes:)];
self.rightSwipeGestureRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(handleSwipes:)];
self.leftSwipeGestureRecognizer.direction = UISwipeGestureRecognizerDirectionLeft;
self.rightSwipeGestureRecognizer.direction = UISwipeGestureRecognizerDirectionRight;
[self.view addGestureRecognizer:self.leftSwipeGestureRecognizer];
[self.view addGestureRecognizer:self.rightSwipeGestureRecognizer];
}
- (void)handleSwipes:(UISwipeGestureRecognizer *)sender
{
if (sender.direction == UISwipeGestureRecognizerDirectionLeft)
{
CGPoint labelPosition = CGPointMake(self.pesawat.frame.origin.x - 30.0, self.pesawat.frame.origin.y);
self.pesawat.frame = CGRectMake( labelPosition.x , labelPosition.y , self.pesawat.frame.size.width, self.pesawat.frame.size.height);
}
if (sender.direction == UISwipeGestureRecognizerDirectionRight)
{
CGPoint labelPosition = CGPointMake(self.pesawat.frame.origin.x + 30.0, self.pesawat.frame.origin.y);
self.pesawat.frame = CGRectMake( labelPosition.x , labelPosition.y , self.pesawat.frame.size.width, self.pesawat.frame.size.height);
}
}
and here my .h
#interface ViewController : UIViewController
#property (nonatomic, retain) IBOutlet UIImageView *pesawat;
#end
As a very basic example,
You should use a panGestureRecognizer:
UIPanGestureRecognizer * panner = [[UIPanGestureRecognizer alloc]init];
[panner addTarget:self action:#selector(handlePan:)];
[self.view addGestureRecognizer:panner];
Then:
- (void) handlePan:(UIPanGestureRecognizer *)panner {
CGPoint translation = [panner translationInView:panner.view];
CGPoint newCenter = CGPointMake(self.pesawat.center.x + translation.x, self.pesawat.center.y);
int offset = 30; // pixels to offset
if (newCenter.x < offset) newCenter = CGPointMake(offset, newCenter.y);
else if (newCenter.x > self.view.bounds.size.width - offset) newCenter = CGPointMake(self.view.bounds.size.width - offset, newCenter.y);
self.pesawat.center = newCenter;
[panner setTranslation:CGPointMake(0, 0) inView:panner.view];
}
I suggest you to maintain the y position, change the x
basketView.center = CGPointMake(point.x, basketView.center.y);
Or I recommend you to follow these tutorials:
1) http://blog.spritebandits.com/2012/04/17/iphone-drawing-on-screen-follow-a-finger/
2) http://www.raywenderlich.com/44270/sprite-kit-tutorial-how-to-drag-and-drop-sprites
Hopefully this info will helps you.
I do this with a Long Press Gesture recognizer. Like this:
UILongPressGestureRecognizer *ges = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(lp:)];
ges.minimumPressDuration = 0.1;
self.pesawat.userInteractionEnabled = YES;
[self.pesawat addGestureRecognizer:ges];
Then add this:
-(void)lp:(UILongPressGestureRecognizer*)ges{
float x = ([ges locationInView:self.GraphicBox].x);
float y = ([ges locationInView:self.GraphicBox].y);
[imgView setCenter:CGPointMake(x,y)];
}
That should do the trick for you.

'Adapt' my current UISwipeGestureRecognizer code for flicking through images to an iPhoto style utilising UIPanGestureRecognizer

I use the following code to swipe left and right with a UISwipeGestureRecognizer to show photos in my app in a similar way to iPhoto.
CATransition *animation = [CATransition animation];
[animation setDuration:0.5];
[animation setType:kCATransitionPush];
[animation setSubtype:kCATransitionFromRight];
[animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
[[self.imageHolder layer] addAnimation:animation forKey:#"SwitchToView"];
This slides the next image in and the old image out like shown in the pictures below:
Image One:
Transition:
Image Two:
I was wondering how to make this like iPhoto when it dawned on me I should use a UIPanGestureRecognizer instead.
I need to 'control' the animation with my finger in the way iPhoto does, namely by allowing me to start dragging to the next image and then reverse the drag direction. Also, in a similar way to iPhoto I'd like the next image to slide in if I release my finger when more of the next image is showing than the first image (this HASN'T happened in the transition picture above and if I released my finger at this point in iPhoto it would slide back to the first image.
I've never used a UIPanGestureRecognizer before so if anybody can help me out that'd be great.
EDIT:
Using the code provided by Levi, I have created a solution that works nicely with 3 sample images. For anybody else who is interested in using a UIPanGestureRecognizer, the code is:
Interface:
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController <UIGestureRecognizerDelegate>
{
int imageIndex;
}
#property (nonatomic, strong) UIImageView* imageView;
#property (nonatomic, strong) UIImageView* leftImageView;
#property (nonatomic, strong) UIImageView* rightImageView;
#end
Implementation:
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self->imageIndex = 0;
float xFactor;
UIInterfaceOrientation currentOrientation = self.interfaceOrientation;
if(UIInterfaceOrientationIsLandscape(currentOrientation)){
xFactor = 256;
}
else{
xFactor = 0;
}
self.imageView = [[UIImageView alloc] initWithFrame:self.view.frame];
self.imageView.contentMode = UIViewContentModeScaleAspectFit;
self.imageView.image = [UIImage imageNamed:#"69B4356B-1CB2-4A2F-867E-9C086251DF11-12668-0000036A534E9B6D"];
self.imageView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
CGRect leftFrame = self.view.frame;
leftFrame.origin.x -= leftFrame.size.width+xFactor;
self.leftImageView = [[UIImageView alloc] initWithFrame:leftFrame];
self.leftImageView.contentMode = UIViewContentModeScaleAspectFit;
self.leftImageView.image = [UIImage imageNamed:#"42517D93-F8BF-42E7-BB44-53B099A482AA-12668-0000036A49BCECAA"];
self.leftImageView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
CGRect rightFrame = self.view.frame;
rightFrame.origin.x += rightFrame.size.width+xFactor;
self.rightImageView = [[UIImageView alloc] initWithFrame:rightFrame];
self.rightImageView.contentMode = UIViewContentModeScaleAspectFit;
self.rightImageView.image = [UIImage imageNamed:#"C6AC2508-243B-464B-A71F-96DD7F18673D-12668-00000369F3AFD3FC"];
self.rightImageView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self.view addSubview:self.imageView];
[self.view addSubview:self.leftImageView];
[self.view addSubview:self.rightImageView];
UIPanGestureRecognizer *recognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handlePan:)];
[self.view addGestureRecognizer:recognizer];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
- (void)handlePan:(UIPanGestureRecognizer *)recognizer {
if (recognizer.state == UIGestureRecognizerStateEnded) {
CGRect leftFrame = self.leftImageView.frame;
CGRect currentFrame = self.imageView.frame;
CGRect rightFrame = self.rightImageView.frame;
float duration = 0.0;
float factor;
UIInterfaceOrientation currentOrientation = self.interfaceOrientation;
if(UIInterfaceOrientationIsPortrait(currentOrientation)){
factor = 768;
}
else{
factor = 1024;
}
if (self.imageView.center.x < 0) { // Present the right image
duration = 0.3 * ABS(self.rightImageView.frame.origin.x / factor);
leftFrame.origin.x = -2 * factor;
currentFrame.origin.x = -1 * factor;
rightFrame.origin.x = 0;
self->imageIndex = 1;
} else if (self.imageView.center.x > factor) { // Present the left image
duration = 0.3 * ABS(self.leftImageView.frame.origin.x / factor);
leftFrame.origin.x = 0;
currentFrame.origin.x = factor;
rightFrame.origin.x = 2 * factor;
self->imageIndex = -1;
} else { // leave the middle image
duration = 0.3 * ABS(self.imageView.frame.origin.x / factor);
leftFrame.origin.x = -1 * factor;
currentFrame.origin.x = 0;
rightFrame.origin.x = factor;
self->imageIndex = 0;
}
[UIView animateWithDuration:duration
delay:0
options:UIViewAnimationOptionCurveEaseInOut
animations:^{
self.leftImageView.frame = leftFrame;
self.imageView.frame = currentFrame;
self.rightImageView.frame = rightFrame;
} completion:^(BOOL finished) {
}];
} else {
CGPoint translation = [recognizer translationInView:recognizer.view];
CGPoint leftCenter = self.leftImageView.center;
CGPoint currentCenter = self.imageView.center;
CGPoint rightCenter = self.rightImageView.center;
leftCenter.x += translation.x;
currentCenter.x += translation.x;
rightCenter.x += translation.x;
self.leftImageView.center = leftCenter;
self.imageView.center = currentCenter;
self.rightImageView.center = rightCenter;
[recognizer setTranslation:CGPointMake(0, 0) inView:self.imageView];
}
}
- (void)willAnimateRotationToInterfaceOrientation:
(UIInterfaceOrientation)toInterfaceOrientation
duration:(NSTimeInterval)duration
{
CGPoint leftCenter = self.leftImageView.center;
CGPoint currentCenter = self.imageView.center;
CGPoint rightCenter = self.rightImageView.center;
if(UIInterfaceOrientationIsPortrait(toInterfaceOrientation)){
leftCenter.x = 384+(((-self->imageIndex)-1)*768);
currentCenter.x = 384+((-self->imageIndex)*768);
rightCenter.x = 384+(((-self->imageIndex)+1)*768);
}
else{
leftCenter.x = 512+(((-self->imageIndex)-1)*1024);
currentCenter.x = 512+((-self->imageIndex)*1024);
rightCenter.x = 512+(((-self->imageIndex)+1)*1024);
}
self.leftImageView.center = leftCenter;
self.imageView.center = currentCenter;
self.rightImageView.center = rightCenter;
}
#end
You can add a UIPanGestureRecognizer to your image view. You would have a method assigned to it where you do something like:
- (void)handlePan:(UIPanGestureRecognizer *)recognizer {
if (recognizer.state == UIGestureRecognizerStateEnded) {
} else {
CGPoint translation = [recognizer translationInView:recognizer.view];
CGPoint center = recognizer.view.center;
UIImageView *imageViewToPresent = nil;
if (translation.x > 0) {
imageViewToPresent = [self leftImageView];
} else {
imageViewToPresent = [self leftImageView];
}
CGPoint actualCenter = recognizer.view.center;
CGPoint nextCenter = imageViewToPresent.center;
actualCenter.x += translation.x;
nextCenter.x += translation.x;
recognizer.view.center = actualCenter;
imageViewToPresent.view.center = nextCenter;
[recognizer setTranslation:CGPointMake(0, 0) inView:self.imageView];
}
}
In the UIGestureRecognizerStateEnded part, you can decide which picture to show.
Or just use a ScrollView with paging enabled. It should have the same effect. However, it would require to have all the images loaded at the same time. Using Pan Recognizer, you need 3 image views tops (left, right, current).
Hope this helps!
EDIT:
In the header file you should add 2 more Image Views:
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController <UIGestureRecognizerDelegate>
#property (nonatomic, strong) UIImageView* imageView;
#property (nonatomic, strong) UIImageView* leftImageView;
#property (nonatomic, strong) UIImageView* rightImageView;
#end
The implementation would be:
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.imageView = [[UIImageView alloc] initWithFrame:self.view.frame];
self.imageView.contentMode = UIViewContentModeScaleAspectFit;
self.imageView.image = [UIImage imageNamed:#"69B4356B-1CB2-4A2F-867E-9C086251DF11-12668-0000036A534E9B6D"];
self.imageView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
CGRect leftFrame = self.view.frame;
leftFrame.origin.x -= leftFrame.size.width;
self.leftImageView = [[UIImageView alloc] initWithFrame:leftFrame];
self.leftImageView.contentMode = UIViewContentModeScaleAspectFit;
self.leftImageView.image = [UIImage imageNamed:#"42517D93-F8BF-42E7-BB44-53B099A482AA-12668-0000036A49BCECAA"];
self.leftImageView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
CGRect rightFrame = self.view.frame;
rightFrame.origin.x += rightFrame.size.width;
self.rightImageView = [[UIImageView alloc] initWithFrame:rightFrame];
self.rightImageView.contentMode = UIViewContentModeScaleAspectFit;
self.rightImageView.image = [UIImage imageNamed:#"C6AC2508-243B-464B-A71F-96DD7F18673D-12668-00000369F3AFD3FC"];
self.rightImageView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self.view addSubview:self.imageView];
[self.view addSubview:self.leftImageView];
[self.view addSubview:self.rightImageView];
UIPanGestureRecognizer *recognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handlePan:)];
[self.view addGestureRecognizer:recognizer];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
- (void)handlePan:(UIPanGestureRecognizer *)recognizer {
if (recognizer.state == UIGestureRecognizerStateEnded) {
CGRect leftFrame = self.leftImageView.frame;
CGRect currentFrame = self.imageView.frame;
CGRect rightFrame = self.rightImageView.frame;
float duration = 0.0;
if (self.imageView.center.x < 0) { // Present the right image
duration = 0.3 * ABS(self.rightImageView.frame.origin.x / self.view.frame.size.width);
leftFrame.origin.x = -2 * self.view.frame.size.width;
currentFrame.origin.x = -1 * self.view.frame.size.width;
rightFrame.origin.x = 0;
} else if (self.imageView.center.x > self.view.frame.size.width) { // Present the left image
duration = 0.3 * ABS(self.leftImageView.frame.origin.x / self.view.frame.size.width);
leftFrame.origin.x = 0;
currentFrame.origin.x = self.view.frame.size.width;
rightFrame.origin.x = 2 * self.view.frame.size.width;
} else { // leave the middle image
duration = 0.3 * ABS(self.imageView.frame.origin.x / self.view.frame.size.width);
leftFrame.origin.x = -1 * self.view.frame.size.width;
currentFrame.origin.x = 0;
rightFrame.origin.x = self.view.frame.size.width;
}
[UIView animateWithDuration:duration
delay:0
options:UIViewAnimationOptionCurveEaseInOut
animations:^{
self.leftImageView.frame = leftFrame;
self.imageView.frame = currentFrame;
self.rightImageView.frame = rightFrame;
} completion:^(BOOL finished) {
}];
} else {
CGPoint translation = [recognizer translationInView:recognizer.view];
CGPoint currnetCenter = self.imageView.center;
CGPoint leftCenter = self.leftImageView.center;
CGPoint rightCenter = self.rightImageView.center;
currnetCenter.x += translation.x;
leftCenter.x += translation.x;
rightCenter.x += translation.x;
self.imageView.center = currnetCenter;
self.leftImageView.center = leftCenter;
self.rightImageView.center = rightCenter;
[recognizer setTranslation:CGPointMake(0, 0) inView:self.imageView];
}
}
#end
Of course it still need work (e.g. to support more than 3 hardcoded images). It may help you with the rotation issue if you would use IBOutlets, and set the auto resizing masks from the Interface Builder.
Have fun!
If you want a scrolling behaviour like the Photos application you shouldn't use a UIGestureRecognizer at all. Use a UIPageViewController with UIPageViewControllerTransitionStyleScroll, or if you need to support versions lower than iOS6, use a UIScrollView.
Check out Apple's sample project PhotoScroller for an example using UIScrollView.

Resources