Regarding views and gesture recognizers - ios

So I have somewhat of a silly requirement, I am trying to put an "easter egg" type function into the app, where if you tap a certain area 3 times, a special view controller comes up with some silly pictures, etc...
I created a UIView and added a UITapGestureRecognizer to it. but when I set the background color to "clear" (to effectively hide the view) it doesn't respond to the tap.
How can I make the view "invisible" and yet still active? I want to use a UIView because I've set it to respond to multiple taps, which is why I didn't use a UIButton

If it is the case where alpha < 0.1 starts ignoring events (I never heard that either), you could drop in a 1x1pt custom view/control where the 1px showing has a color that matches its background and has an alpha > 0.1,
Then override:
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
to return YES for a larger area than the 1x1 pt.

Related

iOS - View that handle taps, but let swipes go through to the superview

I have an app with quite a complex UI, there's a big UIView called the cover with a UITableView underneath it. The tableView is configured with a tableHeaderView of the same height as the cover. As the tableView scrolls up, the cover moves up the screen (with various fancy animations) using a UIScrollViewDelegate. To allow users to scroll the tableView by swiping the cover, I've overridden the - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event method to always return false.
I've now added some UIButton views to the cover. I've managed to make them respond to taps by changing the way I've overriden the pointInside method like this:
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
BOOL isInside = [_directionsButton pointInside:[_directionsButton convertPoint:point fromView:self] withEvent:event];
return isInside;
}
The only problem now is that if you start a swipe gesture on the button, it's caught by the button and the tableView doesn't scroll. I want to be able to ignore swipe gestures on the button (so really let them pass to the view below).
Normally, I would just make the cover view the tableHeaderView, which seems to handle this kind of behaviour really well. However, I can't do this here, due to some unique animations done on the cover as the table scrolls.
Did you tried identifying the Gestures using Gesture Recognisers and doing action method that is to be called when the specified gesture is detected?
Please check this link. This may help you for that.

How to make UIView stop receiving touch events?

I'm working on an app where the user is expected to rapidly touch and swipe across multiple UIViews, each of which is supposed to do an action once the user's finger has reached it. I've got a lot of views and so the typical thing to do, where I'd iterate over each view to see if a touch is inside of its bounds, is a no-go - there's just too much lag. Is there any other way to get touch events from one view to another (that is beside the first one)? I thought maybe there is some way to cancel the touch event, but I've searched and so far have come up empty.
One of the big problems I have is that if I implement my touch handling in my view controller, touchesBegan only fires for the first touch - if the user touches something and then, without moving the first finger, taps on something else, that tap is not recorded in either touchesBegan or touchesMoved. But if I implement my touch handling in the UIViews themselves, once a view registers a touch, if the user does not lift their finger up and moves it, the views around the first view do not register the touch. Only if the user lifts his finger and then puts it back down will the surrounding views register the touch.
So my question is, lets say I have two views side by side, my touch handling code is implemented in the views, and I put my finger down on view 1. I then slide my finger over to view 2 - what do I need to do to make view 2 register that touch, which started in view 1 and never "ended"?
Set userInteractionEnabled property of UIView to NO.
view.userInteractionEnabled = NO;
UIView has the following property:
#property(nonatomic, getter=isUserInteractionEnabled) BOOL userInteractionEnabled
Ok, I figured out what was going on. Thing is, I have my views as subviews of a scrollview, which is itself a subview of my main view. With scrollEnabled = NO, I could touch my subviews - but apparently the scrollview was only forwarding me the initial touch event, and all subsequent touches were part of that initial event. Because of that, I had many weird problems such as touching two views one after the other, both would select and highlight, but if I took the first finger off the screen both views would de-select. This was not the desired behavior.
So what I did is I subclassed the scrollview and overrode the touch handling methods to send the events to its first responder, which is its superview, which is the view where I'm doing my touch handling. Now it works!

Touch Event in Scrollview ios

Scrolling is not stopping when I touch over the contact labels. How can I add this feature for this open project.
https://www.cocoacontrols.com/controls/scroller
If I touch the background, it is working perfectly. I would like to have same thing for the contacts labels too.
Basically, it uses scrollview and there is an animation while scrolling. I can not make stop it when I touch over the labels.
Any help is welcome.
Though I am unfamiliar with the scroller project, maybe this can at least get you on the right path.
The likely reason why touching the contacts isn't stopping the scrolling is because the labels are receiving their own touch events for their own purpose, which is probably the desired behavior, since you would probably want to touch one of the contacts and have it do something. It's possible that since the touch events are being intercepted in that view for that reason, that you can not interact with the scroll view using the same event.
You may need to set the userInteractionEnabled property of the view surrounding each contact to false until the scrollview has stopped scrolling. There are several ways you could do this, but this might be enough to get you started on a good solution.
My condition may be similar with yours.
I build a scroll view in storyboard and a view is added to the scroll view.All of my UI component was placed in the content view including two textfields.Generally speaking, I would like to rewrite the - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event method, and end editing actions in this view.
However,rewrite the method in scrollview's superview has little help.But when I subclass the view and rewrite that method in this subclass Every thing is OK.
According to my condition ,subclass the view and rewrite - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event.Process the logic in view level.

UIStepper swallows the touch

I'm using an UIStepper to change a value that is displayed in a UITextField, with the option of being editable entering the value in the UITextField.
Everything works fine, but there is a undesired behavior: the UITextField can only be edited pressing the upper half of the object itself, because the touch in the lower half is swallowed by the UIStepper.
I've looking for an answer, but I haven't find any. I have some hint though.
UIStepper has 2 buttons and 1 ImageView, and the touch is detected in the entire ImageView (not visible or editable).
Any ideas?
To fix this would most likely require subclassing. You can override pointInside:withEvent: in a UIStepper subclass and return NO unless strictly within the bounds of the stepper:
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
return CGRectContainsPoint(self.bounds, point);
}
One option is to put both the stepper and the text field inside a container view that overrides -hitTest:withEvent: such that it queries the text field before querying the stepper. If the text field says that it's hit, return a pointer to the text field. If not, check the stepper and return that if it says it's hit.
Controls sometimes pretend to be larger than they are so that they're easier to touch. Using the preceding technique should let you keep as much of the stepper's extra touchable area as possible without hindering use of the text view.

Should "clickable" areas in iOS be buttons?

Should "clickable" areas in iOS be buttons or is it ok to just use a generic UIView, UIImage and so on?
Say i have a block of text with an icon, borders, shadows and so on. It looks like a bilboard. What would be the best way to implement that? Using a custom UIButton and just add subviews to it or creating just a generic UIView?
Any thoughts appreciated!
You can simply add UIGestureRecognizers to your UIView and handle them. You can find the documentation here and a tutorial here.
Probably for a view containing multiple subviews, you want to use a UIView subclass. While a UIButton would be OK for adding views, state changes, enabling/disabling may do wonky things to the view as a whole (including the subviews). Using your own UIView subclass will ensure that what gets displayed doesn't get toyed around with by any state changes, giving you complete control. You can override
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
to intercept touches on your custom view. If you're going to do this, remember that the userInteractionEnabled field MUST be set to true.
An additional note: you mentioned shadows as one of the elements in your question. If you're using CALayer to do this, definitely avoid using UIButton, as it's set of layers to handle different states is quite complex.
If the target area is big enough, you could place a transparent UIButton (switch the button type to custom, but don't supply an image) over the top of the clickable view to intercept the taps.

Resources