Generic way to detect a touch outside UIView frame - ios

I have UIViewController with a custom UIView inside (lets call them VC and button). When button is touched, it's bounds and center changes with animation (it becomes bigger and presents a few options to choose from, after choice it resizes back). I would like to know how to "detect" (and dismiss the default action of that touch) a touch outside of the button (just to "hide" the button, in particular to make button resize to default smaller size).
Is there any generic way I could do that? VC has a lot of objects inside its view (table views, buttons, text fields, custom charts made with quartzcore, etc), do i need to block "interactivity" on all of those elements during the "big mode" of button?

You could subclass what ever view you are using and expand the coordinates that will correspond to a touch in the view by implementing
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
Read more in the docs
http://developer.apple.com/library/ios/documentation/UIKit/Reference/UIView_Class/UIView/UIView.html#//apple_ref/occ/instm/UIView/hitTest:withEvent:
This way of implementing it is suggested in some WWDC videos from last year

Add a UIButton having the frame CGRectMake(0,0,self.view.frame.size.width,self.view.frame.size.height) as the first subview to your mainview (self.view) , add a selector to this button (#selector(backgroundTap)) , now add all other subviews like UITableView , UIButton , etc (as per your requirment) . Now whenever you will click on to the blank space where no Subview is present the backgroundTap selector will be called.

Related

Disable userinteraction or touches event in UIView but still enable for subview

I have UIView like this.
I need to put my finger on that view and drag along on those button just like playing piano. Problem is that if initial touch point is on the main view and if I drag along, touches event for main view is triggered and my buttons touch events are not triggered.
As a result, I put this.
[self setUserInteractionEnabled:NO];
Problem is that it has disabled my buttons and other subviews. I want to totally ignore touch event, user interaction from main view but allow for all those subview. How shall I do?
You can set up a notification event for keyboardWillShow and inside the target function set [self setUserInteractionEnabled:NO]; for the superView and when keyboardWillHide notification re-enable it. For hiding the keyboard you could use the GO Button or to dismiss the keyboard add an invisible UIButton to the remaining part of the Screen when the keyboardWillShow event is called and use it to resign first responder.
Hope this helps.
You should create a subclass of UIView for your main view. It should overwrite - hitTest:withEvent: returning always the nearest view for a key.
An alternative solution without inheritance is giving all keys an invisible border such that their views cover the complete main view but never returning the main view.

Make UIControl only accept swipe gestures and pass along touch/tap gestures

I'm developing an iOS 8.1 app for an iPhone 5 in Objective-C using Xcode 6.1.
When a UITextView is clicked, I have an invisible UIControl view that pops up just above the keyboard, so that the user can swipe down from above the keyboard and dismiss the keyboard (and then move the UIControl out of view again). This is working fine. However, this UIControl view that pops up above the keyboard is covering another UITextView such that the covered text view cannot be tapped on. Every time I try to tap on the covered text view (which is visible because the UIControl is not opaque), nothing happens because the UIControl seems to just be taking the taps and not doing anything with them.
My question is, how do I make it so that the UIControl simply ignores taps (letting them go straight through so that the UITextView underneath can accept them), and yet accepts swipes (so that, when it is swiped downward, it can dismiss the keyboard and move out of view)?
I've tried several solutions but haven't found one that will work well for what I want.
Thanks!
This question is similar to yours. Subclass your UIControl and override - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event and call its super variant to pass it up to its view.
There is another way to do this. Change the main view of your UIViewController to a subclass of UIControl instead of UIView. Connect the following IBAction to the view in order to dismiss the keyboard when the background is tapped.
- (IBAction)backgroundTapped{
[self.view endEditing:YES];
}
Apple Documentation - endEditing:
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
Use this event. If tap gesture return no.

How to detect touch on screen in custom UIView?

I want to watch in my UIView subclass for user touches on the screen. Especially there are some additional conditions:
the touch should not be catch by my view (for example, if user taps some button or scrolls something that action should be accepted)
there can be multiple views which are watching for touch and they should not conflict with each other
the approach should be as general as possible (so we can catch taps on tabbar or navigation buttons)
I can suppose to add specific fullscreen view with customized hitTest: method. This view has interface to add/remove delegates for watching for touches. But this method is "hard" in coding terms and I would like to find more elegant and simpler solution.
you can write touchesBegan in that UIView subclass.
Because if it had any subview like button or scrollView, they would be first responders ,and touches on scrollView wont fire touchesBegan of your UIView subclass.
And it wont conflict with other touch listeners unless the listener subView is explicitly passing that touch to your Subclass.

Multiple UIView in one UIViewController

I am developing a iPad App.
There is one UIViewController which should show all relevant information.
Inside this VC there are 2 UIViews: The first UIView on the first half of the Screen shows a Image and some text. The second View on the bottom half of the screen should display some stuff like a map or a image gallery depending on the button that was pressed in the center of the screen.
My first try was to load for example a GalleyViewController and then get his View and add this as a Subview to my BottonView like this:
-(void)galleryButtonPressedInCenter{
GalleryViewController * gal = [[GalleryViewController alloc] initWithNibName:#"GalleryViewController" bundle:nil];
[gal.view setFrame:CGRectMake(0,0,620,300)];
[self.bottomView addSubview: gal.view];
But this will crash my app if I touch the View with my finger.
To show what I want to achieve:
On the last Screenshot (http://itunes.apple.com/de/app/ebookers-hotels-furs-ipad/id465464927?mt=8) you can see that in this App there is a ImageView and some other Stuff in the upper part and in the lower part there are multiple Views that are switched depending on the button that was pressed.
Make an empty fullscreen view.
then add your subviews to that view.
ViewController
-UIView (your new umbrella view)
-UIView (subView 1)
-UIView (subview 2)
I don't think I've seen it documented in the helpfiles, but I'm finding that each "ViewController" can only have one UIView directly attached. I'm kinda new at this though, try it anyway :)

Using bringSubviewToFront in Ipad scrollview

In my Ipad app, I have a split view in which the detail view is a scroll view...
I have 3 subviews to the scrollview which are tableviews...
How do I use - (void)bringSubviewToFront:(UIView *)view to bring one of the subviews of the scrollview to the front when an action is performed? (since Views are "stacked" in the order they're added with the last one on top). Should I write the code in the subview or in the detailViewController and how do I call it?
You write the code in the controller.
The controller should have access to the table views through IBOutlet properties. Or, if you didn't set them up using a nib, the controller should have been the one to create them.
If a button tap, for example, is responsible for showing a particular table view, the button's action handler method is where you call the bringSubviewToFront: method.
HOWEVER: It sounds like you have three table views on top of each other and are using bringSubviewToFront: to show the current one, and they are all inside a UIScrollView.
Each UITableView contains a UIScrollView. Don't put a scrollview inside a scrollview, they will fight over tracking touches and things will get weird. Just put the three table views inside a plain UIView.
Instead of bringSubviewToFront:, you ought to consider hiding the inactive views (call setHidden:). That way, the hidden views won't be considered part of the responder chain (won't get sent events).

Resources