Add UITapGestureRecognizer to dynamically added views - ios

Im having some issues with adding tapRecognizers to my views.
Im adding an unknown number of events, news and coupons to my UIScrollView where on click i want to open an detail view. However on click the app crashes with following error
Almhults_appen.MainActivity redirectFromHomeScreen:]: unrecognized selector sent to instance 0x7f93c2d4df20
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Almhults_appen.MainActivity redirectFromHomeScreen:]:
As I see it I could make use of an UITableView and add all views to it. However if possible I would personally like to avoid it but since I'm new to Swift I don't trust my judgement here.
if (!event_ar.isEmpty) {
for event: Event in event_ar {
... Init EventView and add to UIScrollView
// Add tapGesture
let tapGesture: UITapGestureRecognizer = UITapGestureRecognizer(
target: self,
action: "redirectFromHomeScreen:"
)
eventView.addGestureRecognizer(tapGesture)
}
}
if (!news_ar.isEmpty) {
... Add news identically to events
}
if (!coupon_ar.isEmpty) {
... Add coupons identically to events
}
Edit added action function
private func redirectFromHomeScreen(sender: UITapGestureRecognizer) -> Void{
... Do stuff
}
Thanks in advance :)

According to your crash report .. first you need to declare funtion
func redirectFromHomeScreen (sender : UITapGestureRecognizer){
}
Declare this and try again

You have to add your gesture to the view you will tap on. And the best moment to add it is within that view's viewDidLoad method. With Objective-C I do that and it works well.
- (void)viewDidLoad
{
[super viewDidLoad];
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(PanToFlipPage:)];
[self.view addGestureRecognizer:pan];
}

Try to add these lines after you have created all of your subviews and buttons.
[self.view setNeedsLayout];
[self.view layoutIfNeeded];

Related

Handling a gesture that needs to address multiple selectors?

Im dealing with some very confusing code on a project, it seems a gesture was used to trigger a func, and that func fires off a selector to a parent view the trigger a func, this is working fine after some tweaks.
Issue is, the subclass is used in a couple of different parent views, so using superview to find a selector is causing a crash, it exists in 1 use, but not in the second.
How can i handle this so that it calls different selectors based on its parent view? The current setup seems pretty hacky and obviously doesnt work as it needs to... some code below:
The reused view inits with this gesture:
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(bandBypassWasPressed:)];
[tap setDelegate:self];
[tap setCancelsTouchesInView:NO];
[self addGestureRecognizer:tap];
Calling this func in its self:
- (IBAction)bandBypassWasPressed:(UITapGestureRecognizer *)sender {
if (CGRectContainsPoint(self.bounds, [sender locationInView:self])) {
[self.superview performSelector:#selector(bandViewOn:) withObject:self];
[self setNeedsDisplay];
}
}
The issue is that 'bandViewOn' only exists in the superview in 1 use of this subview, not in the other, meaning it fires off a call and crashes the app as there isnt a func there with that name.
There is a different func I want it to call depending on its superview. This is
- (void)lowBandBypass:(NSInteger)on {
NSLog(#"lowBandBypass CALLED");
_eqData.filter[1].bypass = on;
_lowBand.on = on;
[_lowBand setNeedsDisplay];
}
How can i handle this to resolve this odd issue...
Cheers and appreciate its a bit complex!
You can use respondsToSelector to check that the superview implements the method before calling it.
if (CGRectContainsPoint(self.bounds, [sender locationInView:self])) {
if [self.superview respondsToSelector:#selector(bandViewOn:)] {
[self.superview performSelector:#selector(bandViewOn:) withObject:self];
}
[self setNeedsDisplay];
}

Is there any callback for swipe back gesture in iOS?

Sometimes when user go back to the previous UIViewController, I want to do something.
If the user clicked the back button in UINavigationBar, I can capture the event.
But if they use the swipe back gesture to go back, I cannot respond to the change.
So is there any callback for swipe back gesture?
Currently I can only disable this kind of page in my app through
interactivePopGestureRecognizer.enabled = NO;
The easiest way is to hook into the one that's already built into UINavigationController by doing something like this:
override func viewDidLoad() {
super.viewDidLoad()
navigationController?.interactivePopGestureRecognizer?.addTarget(self, action: #selector(MyViewController.handleBackswipe))
}
#objc private func handleBackswipe() {
navigationController?.interactivePopGestureRecognizer?.removeTarget(self, action: #selector(MyViewController.handleBackswipe))
// insert your custom code here
}
The remember to call removeTarget(_:action:) in your selector, otherwise it'll spam your selector until the gesture ends.
Try this.It gives you some what better solution.
- (void)viewDidLoad {
[super viewDidLoad];
UIScreenEdgePanGestureRecognizer *gesture = (UIScreenEdgePanGestureRecognizer*)[self.navigationController.view.gestureRecognizers objectAtIndex:0];
[gesture addTarget:self action:#selector(moved:)];
}
In Target method.
-(void)moved:(id)sender{
// do what you want
//finally remove the target
[[self.navigationController.view.gestureRecognizers objectAtIndex:0] removeTarget:self action:#selector(moved:)];
}

Limit Gesture Recognizer to Only One Specific UIView?

I have a UIView called myView on myViewController. I have a UIGestureRecognizer called swipeLeft (code below) that detects when a user swipes left on it.
The problem is: myViewController recognises the same gesture on the whole screen and performs another action. So I would like my app to perform myMethod when you swipeLeft in this particular area of myViewController, the area being myView.
UISwipeGestureRecognizer *swipeLeft = [[UISwipeGestureRecognizer alloc] initWithTarget:self
action:#selector(myMethod:)];
swipeLeft.direction = UISwipeGestureRecognizerDirectionLeft;
swipeLeft.delaysTouchesBegan = YES;
[self.myView addGestureRecognizer:swipeLeft];
More details: I am using RESideMenu and myViewController is the right menu, so when it is visible, the whole view of myViewController recognises swipes in all directions. I would like to change the recogniser in this particular UIView myView.
Thanks!
First you will need to add the swipe gesture to your view controllers header file.
#property (strong, nonatomic) UISwipeGestureRecognizer *swipeLeft;
If you look in DEMORootViewController.m, you will see this call:
self.rightMenuViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"rightMenuViewController"];
This will call your awakeFromNib, and it's your first chance to do something. In here you will create that swipe gesture. You can not add it to your view yet though, because your outlets are not set at this point. The first time they are set is in viewDidLoad, so that's where you will add the gesture to your view. So add this to your view controllers implementation file
- (void)awakeFromNib
{
self.swipeLeft = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:#selector(myMethod:)];
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self.swipeView addGestureRecognizer:self.swipeLeft];
}
- (void)myMethod:(UISwipeGestureRecognizer *)swipe
{
NSLog(#"Did swipe") ;
}
Finally you will need to tell the pan gesture in RESideMenu.m to fail whenever our swipeLeft gesture occurs. The way to do that is to add the following code to RESideMenu.m at line 220. That's at the end of the viewDidLoad method.
if ([self.rightMenuViewController isKindOfClass:[DEMOVC class]]) {
DEMOVC *rightVC = (DEMOVC *)self.rightMenuViewController;
if (rightVC.swipeLeft) {
[panGestureRecognizer requireGestureRecognizerToFail:rightVC.swipeGesture];
} } }
This is assuming your custom VC is called DEMOVC. You will also need to import your custom VC to RESideMenu.m like this:
#import "DEMOVC.h"
Please let me know if this worked out for you, and if there's something else I can help you with.

Adding a gesture in code gives NSInvalidArgumentException

While developing a demo app, I added a few gestures in XCode and they worked fine. However, adding gestures in code is giving an NSInvalidArgumentException at runtime, when gesture should be invoked. I was trying to add this gesture to an ImageView, but later I also attempted it with self.view. All to no avail :(
It's probably some memory related issue, but I'm not able to resolve it. Any help would be highly appreciated.
P.S. User interaction is enabled for imageView - the code worked fine when gestures were added in XCode.
This is what the debugger shows:
'NSInvalidArgumentException', reason: '-[UIView handleToyImageTap:]: unrecognized selector sent to instance.
Here is the code:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
previousRotation = 4.0;
[self.toyImageTappable addGestureRecognizer: [[UITapGestureRecognizer alloc] initWithTarget:self.toyImageTappable action:#selector(handleToyImageTap:)]];
}
- (void) handleToyImageTap:(UITapGestureRecognizer *)sender {
//Rotate image by 45 degree
self.toyImageTappable.transform = CGAffineTransformMakeRotation(M_PI/previousRotation);
previousRotation = previousRotation + 4.0;
if (previousRotation == 16.0)
previousRotation = 4.0;
}
[self.toyImageTappable addGestureRecognizer: [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleToyImageTap:)]];
The target should be the object you watch the action method to be called on, in this case self:
[self.toyImageTappable addGestureRecognizer: [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleToyImageTap:)]];

Adding tapgesture to UIImageview

Im trying to add a tapgesture to UIImageview. but the code bellow which im using right now is not working.
I have added this to my viewdidload (notice that LabelNewsImage is my UIImageview):
LabelNewsImage.userInteractionEnabled = YES;
UITapGestureRecognizer *tapGestureEnlarge = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapGesture:)];
tapGestureEnlarge.numberOfTapsRequired = 1;
[self.LabelNewsImage addGestureRecognizer:tapGestureEnlarge];
You need to properly connect LabelNewsImage to the image view instance. Presumably LabelNewsImage is an IBOutlet and your image view is created in an XIB or Storyboard. You need to drag a connection from the LabelNewsImage property to the image view to connect them.
See the docs (including the video).
The response selector tapGesture:
Is it probable that you write the method like
- (void)tapGesture
{
// TODO:
}
But it should like this
- (void)tapGesture:(NSDictonary *)dic
{
// TODO:
}

Resources