My UIRotationGestureRecgonizer handler callback not getting called in iOS - ios

I am trying to rotate the custom view added to the main view. I have tried to add the gesture recognizer to both main view and sub view. Here is my code
- (void)viewDidLoad
{
[super viewDidLoad];
UIView *demoView = [[UIView alloc]initWithFrame:CGRectMake(100, 100, 100, 100)];
UIRotationGestureRecognizer *rg= [[UIRotationGestureRecognizer alloc]initWithTarget:self action:#selector(handleTap:)];
[rg setDelegate:self];
self.view.userInteractionEnabled = YES;
demoView.userInteractionEnabled = YES;
[demoView addGestureRecognizer:rg];
[self.view addGestureRecognizer:rg];
demoView.backgroundColor = [UIColor orangeColor];
[self.view addSubview:demoView];
}
-(IBAction)handleTap:(UIRotationGestureRecognizer *)recognizer
{
//NSLog(#"HERE");
recognizer.view.transform = CGAffineTransformMakeRotation([recognizer rotation]);
recognizer.rotation = 0;
//NSLog(#"AND HERE");
}

the problem is that one geturerecognizer can only ever be attached to one view. for your requirements, you need two gesturerecognizers, but you can make them call the same selector, so theres no need to implement it two times.
EDIT:
Its kinda hard to find this stated clearly in the docs, but considering that the view- property is a single view, and not an array or set or whatever, it makes alot of sense.
Heres the docs:
https://developer.apple.com/library/ios/documentation/uikit/reference/UIGestureRecognizer_Class/Reference/Reference.html#//apple_ref/occ/instp/UIGestureRecognizer/view
Next EDIT
This stackoverflow-answer also illustrates my point:
Can you attach a UIGestureRecognizer to multiple views?
so whoever downvoted my answer, at least tell me why.

Related

Testing autolayout with XCTest

I'm trying to figure out if there is a way to test the layout of an iOS view in unit tests when using autolayout. Right now I try to simply initialize the view controller, and then check the frames of the views. However, the frame on each view remains origin=(x=0, y=0) size=(width=0, height=0).
- (void)setUp {
[super setUp];
_viewController = [[AddPlayerViewController alloc] init];
_viewController.view.frame = CGRectMake(0, 0, 320, 460);
[_viewController view];
}
- (void)testViewsAreInsideWindow {
[self checkIfViewIsInsideWindow:_viewController.txtfNewPlayer];
[self checkIfViewIsInsideWindow:_viewController.btnNewPlayer];
[self checkIfViewIsInsideWindow:_viewController.tblPlayers];
}
- (void)checkIfViewIsInsideWindow:(UIView *)view {
CGRect windowFrame = _viewController.view.frame;
CGRect viewFrame = view.frame;
XCTAssertTrue(CGRectContainsRect(windowFrame, viewFrame));
}
I've tried adding
[_viewController.view needsUpdateConstraints];
or
[_viewController.view updateConstraints];
or
[_viewController updateViewConstraints];
or
[_viewController viewWillAppear:YES];
but none of them have helped.
Is it at all possible to get autolayout to run when using XCTest?
Have you tried setNeedsLayout followed by layoutIfNeeded?
You can definitely get layout to run in tests, I do it here, but that doesn't have a view controller, just views.
I believe what you are trying to see is whether elements are visible to the user. You may use isHittable property in XCUIElement.
From documentation https://developer.apple.com/documentation/xctest/xcuielement/1500561-ishittable
isHittable returns true if the element exists and can be clicked, tapped, or pressed at its current location. It returns false if the element does not exist, is offscreen, or is covered by another element.

How to move cell in tableViewCell with animation with usage of swipe action

using: objective-C
I have a tableView with rows. I want that user can move cell a little aside and additional action shown to him.
What was done:
Currently create separately table in xib file and cell in xib file.
Cell is very simple
I want to move viewWIthLabel.
In cell class file for using animation I use next code
- (void)awakeFromNib
{
UISwipeGestureRecognizer * leftGestrudeRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(swipeLeft:)];
leftGestrudeRecognizer.direction = UISwipeGestureRecognizerDirectionLeft;
UISwipeGestureRecognizer * rightGestrudeRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(swipeRight:)];
rightGestrudeRecognizer.direction = UISwipeGestureRecognizerDirectionRight;
[self addGestureRecognizer:rightGestrudeRecognizer];
[self addGestureRecognizer:leftGestrudeRecognizer];
}
and actions:
- (IBAction)swipeLeft:(id)sender{
NSLog(#"swipeL");
[UIView animateWithDuration:0.5 animations:^{
self.viewWIthLabel.frame = CGRectMake(-100, 0, self.viewWIthLabel.frame.size.width, self.viewWIthLabel.frame.size.height);
} ];
}
- (IBAction)swipeRight:(id)sender{
NSLog(#"swipeR");
[UIView animateWithDuration:.5 animations:^{
self.viewWIthLabel.frame = CGRectMake(0, 0, self.viewWIthLabel.frame.size.width, self.viewWIthLabel.frame.size.height);
}];
}
So idea to swipe the cell and move it with animation for some distance to show a hidden button.
Result of this code - almoust like I want:
But if you start to scroll the tableView you can get duplicates of "swiped cells" in random (depending on scrolling speed) positions:
Any idea why it happened?
You might have to clear/reset the swiped state of the cell in – tableView:cellForRowAtIndexPath:. Since the cells get re-used (I am assuming you are doing that as would be required for good performance of the tableview). Probably something like this -
self.viewWIthLabel.frame = CGRectMake(0, 0, self.viewWIthLabel.frame.size.width, self.viewWIthLabel.frame.size.height);

drag and drop images if placed on certain area call function

I think the title is pretty self explaining. I need an icon that is dragged by users touch. If this icon is droped on a certain area I would like to call a function. How´s that possible?
Thanks a lot,
Tyler
Add UIPanGesture to the View.
- (void)viewDidLoad
{
[super viewDidLoad];
UIPanGestureRecognizer *pangesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(imageIsMoved:)];
pangesture.minimumNumberOfTouches = 1;
[self.myView addGestureRecognizer:pangesture];
}
Write a gesture method when drag is over
-(void)imageIsMoved:(UIPanGestureRecognizer *)gesture{
CGRect frameToBeCompared;
if (gesture.state == UIGestureRecognizerStateEnded) {
UIView *v = [gesture view];
CGRect viewFrame = v.frame;
if (CGRectEqualToRect(frameToBeCompared, viewFrame)) {
[self callMyMethod];
}
}
}
Check out this thread. Once you have the basics down, you can use an if statement to check the bounds of your icon and if they hit a specific spot call your next function.
Here's another example from one of my favorite iOS tutorial sites, www.raywenderlich.com

Smooth Animation to Slide

I followed that tutorial to implement the basic setup of the ECSLidingViewController:
http://www.youtube.com/watch?v=tJJMyzdB9uI
Now I want to change the transition of opening the leftView like the Default Example of the TransitionFun example.
I added the following code to the leftView:
UISwipeGestureRecognizer *rightRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(closeSettings)];
[rightRecognizer setDirection:UISwipeGestureRecognizerDirectionRight];
[self.slidingViewController.topViewController.view addGestureRecognizer:rightRecognizer];
Additionaly I added the line
[self.slidingViewController.topViewController.view addGestureRecognizer:self.slidingViewController.panGesture];
After the first start of the app, the topview is following my fingers while opening/closing. But after choosing one point of the leftview tableview, it's not working anymore.
In all my topViews, I have the following code in the viewDidLoad method:
UIScreenEdgePanGestureRecognizer *leftRecognizer = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self action:#selector(openSettings:)];
leftRecognizer.edges = UIRectEdgeLeft;
[self.view addGestureRecognizer:leftRecognizer];
Can anybody tell me what to change, that the behaviour of the first start is all the time?
sorry that was a stupid mistake:
I forgot to add
[self.view addGestureRecognizer:self.slidingViewController.panGesture];
to each topViewController. Now it's working.

Can I put the code for a gesture recogniser in the subclass of a view?

I have a main view in my program with a draggable view in it. This view can be dragged around with pan gestures. Currently though it uses a lot of code which I want to put in a subclass to reduce complexity. (I eventually want to increase functionality by allowing the user to expand with view with further pan gestures. This means there will be lots more code clogging up my view controller if I can't sort this out first)
Is it possible to have the code for a gesture recogniser in the subclass of a class and still interact with views in the parent class.
This is the current code I am using to enable pan gesture in the parent class:
-(void)viewDidLoad {
...
UIView * draggableView = [[UIView alloc]initWithFrame:CGRectMake(highlightedSectionXCoordinateStart, highlightedSectionYCoordinateStart, highlightedSectionWidth, highlightedSectionHeight)];
draggableView.backgroundColor = [UIColor colorWithRed:121.0/255.0 green:227.0/255.0 blue:16.0/255.0 alpha:0.5];
draggableView.userInteractionEnabled = YES;
[graphView addSubview:draggableView];
UIPanGestureRecognizer * panner = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(panWasRecognized:)];
[draggableView addGestureRecognizer:panner];
}
- (void)panWasRecognized:(UIPanGestureRecognizer *)panner {
UIView * draggedView = panner.view;
CGPoint offset = [panner translationInView:draggedView.superview];
CGPoint center = draggedView.center;
// We want to make it so the square won't go past the axis on the left
// If the centre plus the offset
CGFloat xValue = center.x + offset.x;
draggedView.center = CGPointMake(xValue, center.y);
// Reset translation to zero so on the next `panWasRecognized:` message, the
// translation will just be the additional movement of the touch since now.
[panner setTranslation:CGPointZero inView:draggedView.superview];
}
(Thanks to Rob Mayoff for getting me this far)
I have now added a subclass of the view but can't figure out how or where I need to create the gesture recogniser as the view is now being created in the subclass and added to the parent class.
I really want the target for the gesture recogniser to be in this subclass but when I try to code it nothing happens.
I have tried putting all the code in the subclass and adding the pan gesture to the view but then I get a bad access crash when I try to drag it.
I am currently trying to use
[graphView addSubview:[[BDraggableView alloc] getDraggableView]];
To add it to the subview and then setting up the view (adding the pan gesture etc) in the function getDraggableView in the subclass
There must be a more straight forward way of doing this that I haven't conceptualised yet - I am still pretty new dealing with subclasses and so am still learning how they all fit together.
Thanks for any help you can give
I think I might of figured this one out.
In the parent class I created the child class variable:
BDraggableView * draggableViewSubClass;
draggableViewSubClass = [[BDraggableView alloc] initWithView:graphView andRangeChart: [rangeSelector getRangeChart]];
This allowed me to initialise the child class with the view I wanted to have the draggable view on: graphView
Then in the child view I set up the pan gesture as I normally would but added it to this view carried through:
- (id)initWithView:(UIView *) view andRangeChart: (ShinobiChart *)chart {
self = [super initWithNibName:nil bundle:nil];
if (self) {
// Custom initialization
parentView = view;
[self setUpViewsAndPans];
}
return self;
}
- (void)setUpViewsAndPans {
draggableView = [[UIView alloc]initWithFrame:CGRectMake(highlightedSectionXCoordinateStart, highlightedSectionYCoordinateStart, highlightedSectionWidth, highlightedSectionHeight)];
draggableView.backgroundColor = [UIColor colorWithRed:121.0/255.0 green:227.0/255.0 blue:16.0/255.0 alpha:0.5];
draggableView.userInteractionEnabled = YES;
// Add the newly made draggable view to our parent view
[parentView addSubview:draggableView];
[parentView bringSubviewToFront:draggableView];
// Add the pan gesture
UIPanGestureRecognizer * panner = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(panWasRecognized:)];
[draggableView addGestureRecognizer:panner];
}
- (void)panWasRecognized:(UIPanGestureRecognizer *)panner {
UIView * draggedView = panner.view;
CGPoint offset = [panner translationInView:draggedView.superview];
CGPoint center = draggedView.center;
CGFloat xValue = center.x + offset.x;
draggedView.center = CGPointMake(xValue, center.y);
// Reset translation to zero so on the next `panWasRecognized:` message, the
// translation will just be the additional movement of the touch since now.
[panner setTranslation:CGPointZero inView:draggedView.superview];
}
It took me a while to straighten it in my head that we want to do all the setting up in our subclass and then add this view with its characteristics to the parent view.
Thanks for all the answers provided they got me thinking along the right lines to solve it
I think you want to subclass UIView and make your own DraggableView class. Here, you can add swipe and pan gesture recognizers. This would be in the implementation of a subclass of UIView
- (id)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
UIGestureRecognizer *gestRec = [[UIGestureRecognizer alloc] initWithTarget:self
action:#selector(detectMyMotion:)];
[self addGestureRecognizer:gestRec];
}
return self;
}
- (void)detectMyMotion:(UIGestureRecognizer *)gestRect
{
NSLog(#"Gesture Recognized");
// maybe even, if you wanted to alert your VC of a gesture...
[self.delegate alertOfGesture:gestRect];
// your VC would be alerted by delegation of this action.
}

Resources