In my iOS application, I use UITouchGestureRecognizer to drag/drop, zoom and rotate UIImageView. I also store the information on the last position of the ImageView to retrieve it when the app restarts.
That was working well with iOS7 but I have recently started to test with iOS8 and I'm facing some issues, especially with the zoom. Whenever the imageview has a non-0 angle in the rotation parameter, the zoom is not acting like expected and reduces the size of the image.
I don't understand why the OS change does that, here is my code:
-(void) viewDidAppear:(BOOL)animated{
[super viewDidAppear:YES];
[self loadAllImages];
for (GIFavorite *favorite in self.favorites){
UIImage *image = favorite.image;
ImageView *imageView = [[ImageView alloc] initWithFrame:CGRectMake(0, 0, image.size.width, image.size.height)];
imageView.center = CGPointMake(favorite.x, favorite.y);
imageView.transform = CGAffineTransformMakeRotation(favorite.rotation);
imageView.transform = CGAffineTransformScale(imageView.transform, favorite.scale, favorite.scale);
imageView.image = image;
imageView.userInteractionEnabled = YES;
UIPanGestureRecognizer * panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handlePan:)];
panRecognizer.delegate = self;
[imageView addGestureRecognizer:panRecognizer];
UIRotationGestureRecognizer * rotationRecognizer = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:#selector(handleRotate:)];
rotationRecognizer.delegate = self;
[imageView addGestureRecognizer:rotationRecognizer];
UIPinchGestureRecognizer * pinchRecognizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:#selector(handlePinch:)];
pinchRecognizer.delegate = self;
[imageView addGestureRecognizer:pinchRecognizer];
[self.view addSubview:imageView];
}
}
I guess the way I am doing the transforms is wrong because when I put the CGAffineTransformMakeRotation instruction after the CGAffineTransformScale instead of reducing the size it increases it.
Where am I doing things wrong?
Edit: the code for handleRotate
- (void)handleRotate:(UIRotationGestureRecognizer *)recognizer {
recognizer.view.transform = CGAffineTransformRotate(recognizer.view.transform, recognizer.rotation);
ImageView *imageView = recognizer.view;
CGFloat radians = atan2f(imageView.transform.b, imageView.transform.a);
favorite.rotation = radians;
recognizer.rotation = 0;
}
First, you need to make your view controller implements UIGestureRecognizerDelegate.
SWIFT 3 :-
func setUpGestures () {
let panGesture = UIPanGestureRecognizer(target: self, action:#selector(self.handlePanGesture(gesture:)))
self.imageView.addGestureRecognizer(panGesture)
let rotationGesture = UIRotationGestureRecognizer(target: self, action:#selector(self.handleRotationGesture(gesture:)))
self.imageView.addGestureRecognizer(rotationGesture)
let pinchGesture = UIPinchGestureRecognizer(target: self, action:#selector(self.handlePinchGesture(gesture:)))
self.imageView.addGestureRecognizer(pinchGesture)
}
func handlePinchGesture(gesture: UIPinchGestureRecognizer) {
if gesture.state == UIGestureRecognizerState.began || gesture.state == UIGestureRecognizerState.changed{
//print("UIPinchGestureRecognizer")
gesture.view?.transform = (gesture.view?.transform)!.scaledBy(x: gesture.scale, y: gesture.scale)
gesture.scale = 1.0
}
}
func handleRotationGesture(gesture: UIRotationGestureRecognizer) {
if gesture.state == UIGestureRecognizerState.began || gesture.state == UIGestureRecognizerState.changed{
//print("UIRotationGestureRecognizer")
gesture.view?.transform = (gesture.view?.transform)!.rotated(by: gesture.rotation)
gesture.rotation = 0
}
}
func handlePanGesture(gesture: UIPanGestureRecognizer) {
if gesture.state == UIGestureRecognizerState.began || gesture.state == UIGestureRecognizerState.changed{
//print("UIPanGestureRecognizer")
let translation = gesture.translation(in: view)
gesture.view?.transform = (gesture.view?.transform)!.translatedBy(x: translation.x, y: translation.y)
gesture.setTranslation(CGPoint(x: 0, y: 0), in: view)
}
}
Hope, this is what you're looking for. Any concern get back to me. :)
First, you need to make your view controller implements UIGestureRecognizerDelegate.
Then add the gesture recognizers to your UIView (I see that you already did that, but just putting it here again to have the solution in one place).
UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handlePan:)];
panGesture.delegate = self;
UIRotationGestureRecognizer *rotationGesture = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:#selector(handleRotate:)];
rotationGesture.delegate = self;
UIPinchGestureRecognizer *pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:#selector(handlePinch:)];
pinchGesture.delegate = self;
[yourView addGestureRecognizer:panGesture];
[yourView addGestureRecognizer:rotationGesture];
[yourView addGestureRecognizer:pinchGesture];
Then, this is how your handle... methods should be:
- (void)handlePinch:(UIPinchGestureRecognizer *)pinchRecognizer
{
UIGestureRecognizerState state = [pinchRecognizer state];
if (state == UIGestureRecognizerStateBegan || state == UIGestureRecognizerStateChanged)
{
CGFloat scale = [pinchRecognizer scale];
[pinchRecognizer.view setTransform:CGAffineTransformScale(pinchRecognizer.view.transform, scale, scale)];
[pinchRecognizer setScale:1.0];
}
}
- (void)handleRotate:(UIRotationGestureRecognizer *)rotationGestureRecognizer {
UIGestureRecognizerState state = [rotationGestureRecognizer state];
if (state == UIGestureRecognizerStateBegan || state == UIGestureRecognizerStateChanged)
{
CGFloat rotation = [rotationGestureRecognizer rotation];
[rotationGestureRecognizer.view setTransform:CGAffineTransformRotate(rotationGestureRecognizer.view.transform, rotation)];
[rotationGestureRecognizer setRotation:0];
}
}
- (void)handlePan:(UIPanGestureRecognizer *)panRecognizer {
UIGestureRecognizerState state = [panRecognizer state];
if (state == UIGestureRecognizerStateBegan || state == UIGestureRecognizerStateChanged)
{
CGPoint translation = [panRecognizer translationInView:panRecognizer.view];
[panRecognizer.view setTransform:CGAffineTransformTranslate(panRecognizer.view.transform, translation.x, translation.y)];
[panRecognizer setTranslation:CGPointZero inView:panRecognizer.view];
}
}
And this is how it looks:
try doing these..
first in your ViewControllers .h do these..
#interface RotationViewController : UIViewController<UIGestureRecognizerDelegate>//Add these..
{
UIView *testView;
}
now do these in .m file of your ViewController..
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
testView=[[UIView alloc]initWithFrame:CGRectMake(100, 100, 160, 160)];
UIImageView * imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 160, 160)];
[imageView setImage:[UIImage imageNamed:#"ImageName.png"]];
[imageView setContentMode:UIViewContentModeScaleAspectFit];
[testView addSubview:imageView];
[self.view addSubview:testView];
UIRotationGestureRecognizer *rotationGestureRecognizer = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:#selector(handleRotate:)];
[testView addGestureRecognizer:rotationGestureRecognizer];
}
-(void) handleRotate:(UIRotationGestureRecognizer *)rotationGestureRecognizer
{
testView.transform = CGAffineTransformRotate(testView.transform, rotationGestureRecognizer.rotation);
rotationGestureRecognizer.rotation = 0.0;
}
i hope it helps..
I've set up my UIView to call a method when the view is panned up and to call some other method when the view is swiped up. My pan works fine and I can keep my pan disabled if my velocity.y is above a certain limit, but I can never get the swipe action to work when my pan fails. I've tried playing around with the delegate methods without much luck. Looked over this solution but no luck: https://stackoverflow.com/a/21728621/1925859
- (void)viewDidLoad
{
[super viewDidLoad];
UIPanGestureRecognizer * panRec = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handlePan:)];
panRec.delegate = self;
[panedView addGestureRecognizer:panRec];
UISwipeGestureRecognizer * swipeRec = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(handleSwipe:)];
swipeRec.delegate = self;
[panedView addGestureRecognizer:swipeRec];
[swipeRec requireGestureRecognizerToFail:panRec];
}
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]])
{
UIPanGestureRecognizer *pan = (UIPanGestureRecognizer *)gestureRecognizer;
CGPoint velocity = [pan velocityInView:gestureRecognizer.view];
if (ABS(velocity.y) > 200)
{
NSLog(#"Swipe actiavted");
return NO;
}
}
return YES;
}
- (IBAction)handleSwipe:(UISwipeGestureRecognizer *)recognizer
{
NSLog(#"In Swipe");
if(recognizer.direction == UISwipeGestureRecognizerDirectionUp)
{
panedView.frame =CGRectOffset( panedView.frame, 0, -1*self.view.bounds.size.height*.80);
}
}
If you remove your delegate method, add direction to the swipe and change the receiver of requireGestureRecognizerToFail then it will work. Note that pans must be way slower than sweeps in order to be recognized.
- (void)viewDidLoad
{
[super viewDidLoad];
UIPanGestureRecognizer * panRec = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handlePan:)];
[panedView addGestureRecognizer:panRec];
UISwipeGestureRecognizer * swipeRec = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(handleSwipe:)];
swipeRec.direction = UISwipeGestureRecognizerDirectionUp;
[panedView addGestureRecognizer:swipeRec];
[panRec requireGestureRecognizerToFail:swipeRec];
}
- (IBAction)handleSwipe:(UISwipeGestureRecognizer *)recognizer
{
NSLog(#"In Swipe");
if(recognizer.direction == UISwipeGestureRecognizerDirectionUp)
{
panedView.frame =CGRectOffset( panedView.frame, 0, -1*self.view.bounds.size.height*.80);
}
}
- (IBAction)handlePan:(UISwipeGestureRecognizer *)recognizer
{
NSLog(#"PAN");
}
I have a UIScrollView as a subview in another UIScrollView I am trying to prevent scrolling from occurring in the subview and pass the touch to the superview.
- (void)viewDidLoad
{
self.outerScrollView = [[UIScrollView alloc] initWithFrame:self.view.bounds];
self.outerScrollView.showsVerticalScrollIndicator = NO;
self.gestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handlePanGesture:)];
self.gestureRecognizer.delegate = self;
[self.tableViewController.tableView addGestureRecognizer:self.gestureRecognizer];
[self.outerScrollView addSubview:self.tableViewController.tableView];
[self.view addSubview:self.outerScrollView];
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
- (void)handlePanGesture:(UIPanGestureRecognizer *)gesture
{
if (gesture.state == UIGestureRecognizerStateBegan) {
if (gesture.view == self.tableViewController.tableView) {
self.tableViewController.tableView.contentOffset = CGPointMake(0, 0);
// Pass to self.outerScrollView
// Trying to make self.outerScrollView take over the touch
}
}
}
I am using JTRevealSideBarDemoV2 for the implementation of the side panels like facebook and Path application. I have configured it in every sense and just want to add one more feature into this library. What I want is to apply gesture recognizer control in this library just similar to facebook. can somebody help?
The link for downloading this library is:-https://www.cocoacontrols.com/controls/jtrevealsidebar
Thanks!
#wattson:- this is the code which I have added for implementing Gesture Recognizer. BBut it is behaving very abnormally. If you have downloaded the code for JTRevealSideBarDemoV2 then you can analyze the code which i have written for.
The code is:
(void)setUpGestures{
UIPanGestureRecognizer *panRecognizer = [[UIPanGestureRecognizer alloc]
initWithTarget:self action:#selector(movePanel:)];
[panRecognizer setMinimumNumberOfTouches:1];
[panRecognizer setMaximumNumberOfTouches:1];
[panRecognizer setDelegate:self];
[self.view addGestureRecognizer:panRecognizer];
}
-(void)movePanel:(id)sender {
[[[(UITapGestureRecognizer*)sender view] layer] removeAllAnimations];
CGPoint translatedPoint = [(UIPanGestureRecognizer*)sender
translationInView:self.view];
CGPoint velocity = [(UIPanGestureRecognizer*)sender velocityInView:[sender view]];
if([(UIPanGestureRecognizer*)sender state] == UIGestureRecognizerStateBegan) {
//UIView *childView = nil;
if(velocity.x > 0) {
if (!JTRevealedStateRight) {
[self revealLeftSidebar:(UIPanGestureRecognizer *)sender];
}
} else {
if (!JTRevealedStateLeft) {
[self revealRightSidebar:(UIPanGestureRecognizer *)sender];
}
}
// Make sure the view you're working with is front and center.
//[self.view sendSubviewToBack:];
[[sender view] bringSubviewToFront:[(UIPanGestureRecognizer*)sender view]];
}
if([(UIPanGestureRecognizer*)sender state] == UIGestureRecognizerStateEnded) {
if(velocity.x > 0) {
// NSLog(#"gesture went right");
} else {
// NSLog(#"gesture went left");
}
if (!_showPanel) {
[self revealLeftSidebar:(UIPanGestureRecognizer *)sender];
} else {
if (JTRevealedStateLeft) {
[self revealRightSidebar:(UIPanGestureRecognizer *)sender];
} else if (JTRevealedStateRight) {
[self revealLeftSidebar:(UIPanGestureRecognizer *)sender];
}
}
}
if([(UIPanGestureRecognizer*)sender state] == UIGestureRecognizerStateChanged) {
if(velocity.x > 0) {
// NSLog(#"gesture went right");
} else {
// NSLog(#"gesture went left");
}
// Are you more than halfway? If so, show the panel when done dragging by setting this
value to YES (1).
_showPanel = abs([sender view].center.x - self.view.frame.size.width/2) >
self.view.frame.size.width/2;
// Allow dragging only in x-coordinates by only updating the x-coordinate with
translation position.
[sender view].center = CGPointMake([sender view].center.x + translatedPoint.x, [sender
view].center.y);
[(UIPanGestureRecognizer*)sender setTranslation:CGPointMake(0,0) inView:self.view];
// If you needed to check for a change in direction, you could use this code to do so.
if(velocity.x*_preVelocity.x + velocity.y*_preVelocity.y > 0) {
// NSLog(#"same direction");
} else {
// NSLog(#"opposite direction");
}
_preVelocity = velocity;
}
}
this is my code but not working
`- (void)webViewDidFinishLoad:(UIWebView *)webView
{
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(longPress:)];
longPress.minimumPressDuration = 2;
[self.webview addGestureRecognizer:longPress];
[longPress release];
}
(void)longPress:(UILongPressGestureRecognizer*)gesture {
if ( gesture.state == UIGestureRecognizerStateEnded ) {
NSLog(#"Long Press");
//do something
}
}`