UITapGestureRecognizer in the subview of a UIScrollView - objective-c

I have a view controller that has a UIScrollView IBOutlet hooked up via storyboard. This view controller has a property that holds on to another view controller. I then add the view from this view controller into the UIScrollView as follows:
[scrollView addSubview:self.derpController.view];
Within derpController, I add a UITapGestureRecognizer as follows:
[self.view addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(singleFingerTap:)]];
Now, the problem that I run into is that the singleFingerTap: selector only gets called in the area within the starting area of the UIScrollView. That is, if I scroll the view and tap in a location that was not initially visible, the UITapGestureRecognizer is not triggered.
I can't seem to figure out how to solve this issue.
EDIT:
On the iPad implementation, the tap gesture is actually recognized a bit beyond the initial startup screen, but it does not cover the entire subview in scrollview.

Related

How can I dynamically fit a xib file view into a storyboard view?

I have setup a simple layout with a button which, when pressed, causes the storyboard subview to load a xib file and assigns its view to the storyboard subview. The problem is that the xib view causes the storyboard subview to 'break' its original constraints:
Here's the main storyboard (left) and xib view (right):
Here's what happens when I press the button on the main storyboard.
- (IBAction)btnShowView:(id)sender {
xibViewController *xib_VC = [[xibViewController alloc] initWithNibName:nil bundle:nil];
xib_VC.modalPresentationStyle = UIModalTransitionStyleCrossDissolve;
//xib_VC.view.frame.size = self.myView.frame.size;
UIView *view = xib_VC.view;
[self.myView addSubview:view];
}
And here's the result - you can see that the xib view has caused the main storyboard subview to go outside of its constraints.
I'm guessing that dynamically changing the storyboard subview overwrites its original view and constraints? Do I have to programatically add these constraints again before assigning the xib view to the storyboard subview?
By your descriptions, it looks like your intention is to put newly created view(xib_VC.view) in the position of myView.
By code you mentioned is adding xib_VC.view to myview as a subview,It doesn't any constraints to it or provides a frame to view.
Setting xib_VC.view.frame.size will not going to work, this is frame for view in xib_VC.
If you just need view, then you don't have to create view controller xib. Just create view xib.
Following line no use, since you are not using a controller.
xib_VC.modalPresentationStyle = UIModalTransitionStyleCrossDissolve;

Detecting UIButton touches on a subview

I have added a subview which contains a UIButton control. This subview is added to its superview programatically. I need to perform an action when this button is tapped, but since it's contained within its own subview, I can't hook an IBAction up to the view controller in order to push another view controller.
Is there an easy way to detect that the button is tapped and call a method within its super view?
You can do everything programmatically:
[buttonName addTarget:self action:#selector(methodName:) forControlEvents:UIControlEventTouchUpInside];
and then create your method:
- (void)methodName:(id)sender
{
// Do something.
}
This is all you have to code.

Detect touches on a UIView inside UIScrollView preferably with Interaction disabled

I have a UIScrollView with some UIViews in it.
What I am trying to do, is catch the touches events when the UIViews are touched/untouched.
The problem I am having, is the UIScrollView seems to swallow all the touch events, especially if you hold for too long on a UIView.
I preferably want the UIScrollView to have userInteraction disabled as it scrolls automatically.
Is this possible?
I have tried subclassing the UIViews but the touches events are never called in it.
You can attach a tapGesture to your scrollview with something along those lines:
UITapGestureRecognizer* tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapGestureUpdated:)];
tapGesture.delegate = self;
tapGesture.numberOfTapsRequired = 1;
tapGesture.numberOfTouchesRequired = 1;
[self addGestureRecognizer:_tapGesture];
then in your - (void)tapGestureUpdated:(UITapGestureRecognizer *)tapGesture method this is your responsability to determine the location of the touch and find out if there was a picking on one of your subviews. You could call then a method on a delegate that notify that a specific view has been touched.
Perhaps reordering your views so that a view that has a touch recognizer object associated with it is what the app recognizes. Move it in the document outline to the top (scroll view)

UINavigationController with UIView and UITableView

I'm creating a navigation-based app which displays a graph, rendered with openGL, and a tableview listing disclosure buttons of all of the elements that are displayed on the graph, and a settings disclosure button.
The navigation controller is also a tableview delegate and datasource, and the tableview is added to the view programatically and has its' delegate and datasource set to 'self'. The OpenGL based graph view is added via IB.
The problem I'm having is that I'm trying to push a view controller (either settings or graph element properties) within the didSelectRowAtIndexPath method. The method registers and the new view is pushed on, but the tableview stays and obscures part of the view that was pushed on, as if it has a different navigation controller.
I can't seem to set the tableview's navigation controller to be the same as the rest of the UINavigationControllers' view.
Does anyone know how I could fix this?
My navigation controllers' initWithCoder method, where the tableview is added, appears as follows:
elementList = [[UITableView alloc] initWithFrame:tableFrame style:UITableViewStyleGrouped];
elementList.dataSource = self;
elementList.delegate = self;
[self.view addSubview:elementList];
Further in the source file, the DidSelectRowAtIndexPath method where the navigation controller is pushed appears as follows:
Settings* Controller = [[Settings alloc] init];
[self pushViewController:Controller animated:YES];
[Controller release];
Fixed by just adding a UITableView in IB, adding IBOutlet to elementList, and setting the UIViewController as the delegate and datasource via IB.
Stack Overflow can be really useful for putting your problems to words so the solution becomes obvious.

Adding a UINavigationController as a subview of UIView

I'm trying to display a UILabel on top of a UINavigationController. The problem is that when I add the UILabel as a subview of UIWindow it will not automatically rotate since it is not a subview of UIViewController (UIViewController automatically handles updating subviews during rotations).
This is the hierarchy I was using:
UIWindow
UILabel
UINavigationController
So I was thinking I could use the following hierarchy:
UIWindow
UIViewController
UIView
UILabel
UINavigationController
This way the label could be displayed on top of the UINavigationController's bar while also automatically being rotated since it is a subview of UIViewController.
The problem is that when I try adding a UINavigationController as a subview of a view:
[myViewController.view addSubview:myNavigationController.view];
it will appear 20 pixels downwards. Which I'm guessing is because it thinks it needs to make room for the status bar. But, since the UINavigationController is being placed inside a UIView which does not overlay on top of the status bar, it is incorrectly adding an additional 20 pixels. In other words, the top of the UINavigationBar is at the screen's 40 pixel mark instead of at 20 pixels.
Is there any easy way to just shift the UINavigationController and all of its elements (e.g. navigation bar, tool bar, root view controller) up 20 pixels? Or to let it know that it shouldn't compensate for a status bar?
If not, I guess I would need to use my first hierarchy mentioned above and figure out how to rotate the label so it is consistent with the navigation bar's rotation. Where can I find more information on how to do this?
Note: by "displaying a label on top of the navigation bar", I mean it should overlay on top of the navigation bar... it can't simply be wrapped in a bar button item and placed as one of the items of the navigation bar.
Using this code seems to work:
nav.view.frame = CGRectMake(nav.view.frame.origin.x, nav.view.frame.origin.y - 20,
nav.view.frame.size.width, nav.view.frame.size.height);
I did this before adding the navigation controller as a subview. Using the [UIApplication sharedApplication].statusBarFrame instead of the hard coded 20 would probably be a good idea too.
I'm not sure if it's the best way to do it though.
If you want a frame representing the available content area, then you should just use: [[UIScreen mainScreen] applicationFrame]. Of course, this restricts your top-level view controller so that it can only be top level. So still kind of dodgy, but less so.
Why don't you use App Frame instead of adding some values to origins? I mean using:
CGRect appFrame = [[UIScreen mainScreen] applicationFrame];
as a reference frame, and do something like this:
nav.view.frame = CGRectMake(appFrame.origin.x, appFrame.origin.y, ...
This one worked for me.
I had this same problem actually but managed to fix it.
I noticed that my view controller's view had the correct frame, but the view controller's navigation bar did not (it had a frame origin of (0,20) ).
Insert this into the view's controller that is the superview of the navigation controller:
- (void) viewDidAppear:(BOOL)animated {
if (navigationController.navigationBar.frame.origin.y != 0) {
[[navigationController view] removeFromSuperview];
[[self view] addSubview:navigationController.view];
}
}
Swift 5:
add the following line in the viewDidLoad() of the root view controller of the UINavigationController.
self.edgesForExtendedLayout = [.top, .bottom]