InputAccessoryView covers the bottom bar - ios

Any idea how to get an inputAccessoryView to anchor to the tab bar rather than the bottom of the screen?
I have created a UIViewController and overridden the following methods:
-(BOOL)canBecomeFirstResponder {
return YES;
}
-(UIView *)inputAccessoryView {
CGRect frame = CGRectMake(0, 0, self.view.frame.size.width, 44);
self.keyboardInputAccessoryView =[[BRKeyboardInputBarView alloc] initWithFrame:frame leftButtonTitle:#"Left" andRightButtonTitle:#"Send"];
[self.keyboardInputAccessoryView setDelegate:self];
[self.keyboardInputAccessoryView setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.keyboardInputAccessoryView removeFromSuperview];
return self.keyboardInputAccessoryView;
}
View controller with inputAccessoryView covering the tab bar
By the looks of it the view controller adds the view to the window rather than the current view controllers view, which would explain its positioning. However if I remove the line:
[self.keyboardInputAccessoryView removeFromSuperview];
I get a crash when I tap in the textview of my accessory view:
The view hierarchy is not prepared for the constraint:<NSLayoutConstraint:0x7fa0c2ca5f80 BRKeyboardInputBarView:0x7fa0c2d6fad0.bottom == UIInputSetContainerView:0x7fa0c295a2c0.bottom>
So I guess what I am asking is what is the correct way to add a keyboard accessory view so that it plays nicely with auto layout and avoids the crash, but also anchors itself to the view and not the window?

What you are seeing is the right behaviour.
The results you are seeing is because of the fact that UIViewController is a UIResponder subclass. By overriding the inputAccessoryView and returning an instance of a view, UIViewController will take care of placing that view at the bottom of the screen and animating it appropriately when keyboard appears or disappears.
If you want to add this bar on top of your keyboard, then you need to set the property inputAccessoryView of a textField/textView to your custom view.

Related

Popping UIViewController causes previous UIViewControllers View to change position

I have a UINavigationController with a UIViewController set as it's rootController, it contains a background on its UIView using an image set just under the navBar. I then push onto the navigation controller a new UIViewController and when the back button is pushed, the previous controller looks different. Using the visual debugger I can see that the self.view has moved entirely down below the navBar where previously it was at the top. I have no idea and been racking my brains as to why this might be happening
-(void)pushIPhoneMessagingContactsController:(MessageContactsViewController *)contactsController{
self.selectorView.hidden = YES;
[self.navigationController pushViewController:contactsController animated:YES];
}
On the RootViewController (iPhoneMessagingNotificationsController)
-(void)viewWillAppear:(BOOL)animated{
self.selectorView.hidden = NO;
[[[self navigationItem] leftBarButtonItem] setTintColor:[UIColor blackColor]];
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDefault];
if ([_displayType intValue] == MESSAGES_SHOWING) {
[self.notificationsViewController.view removeFromSuperview];
[self.contentView addSubview:_messagesViewController.view];
} else {
[self.messagesViewController.view removeFromSuperview];
[self.contentView addSubview:_notificationsViewController.view];
}
}
It seems the offending line was in the viewWillAppear method of the pushed UIViewController
self.navigationController.navigationBar.translucent = YES;
Somewhere else this navigationBar gets set as translucent:
[self.navigationController.navigationBar setBackgroundImage:[UIImage new]
forBarMetrics:UIBarMetricsDefault];
self.navigationController.navigationBar.shadowImage = [UIImage new];
self.navigationController.navigationBar.translucent = YES;
and to make it solid colour again:
self.navigationController.navigationBar.shadowImage = nil;
self.navigationController.navigationBar.translucent = NO;
but this code seems to mess with the layout so perhaps there is another way to change the opacity of the navBar and statusBar without affecting the layout?
What you're currently trying to do is hide or show a selectorView which really only should appear for one specific view controller.
Here's an encapsulated way to solve this that makes your selectorView a part of the root view controller, removing the connection from other view controllers. They no longer have to know about it or hide it.
Add your selectorView to your rootViewController's navigation bar titleView. (You can do this in code, or drop it in Storyboard and add an IBOutlet for it.)
self.navigationItem.titleView = selectorView;
Now when you push another view controller, its title will replace your rootViewController's selectorView title (view). Your other view controllers don't need to know anything about that view.
This is a good design approach in general. Anytime you have a control that should only appear on one view controller's navigation bar, you want to make it a part of that view controller's navigationItem (titleView, or left/right bar button items.) iOS will display the control when it presents that view controller, and hide the control when that view controller is no longer the top view controller in the navigation controller stack.
As for the 64-pixel height issue, it's likely related to some complexity in the rootViewController hierarchy that shouldn't be there.
In iOS 7/8, a view's content, by default, appears under a translucent navigation bar. Apple freely managed this for you, by insetting the first view of the view hierarchy.
From your code, it appears that you're trying to "hide" or "show" the (un)selected viewController's view.
Each view controller should have a view it controls. A view controller shouldn't be trying to control other view controller's views, or adding other view controller's views to its own view hierarchy.
Here's Apple's recommended way to approach this. Use a containerView in your rootViewController. The whole purpose of a container view is to encapsulate a view controller within a view. As your selectorView changes which view to show, you have your container view transition from one view controller to the other. (If you're not familiar with how to do that, check out this answer.)
Pin the containerView to the rootViewController's view, so Auto Layout can size it for you.
Your view hierarchy now looks like view -> containerView, instead of view -> hidden view of unselected view controller, shown view of selected view controller. Apple can adjust the first view's inset, and nothing gets incorrectly offset (by the height of the navigation control).
Update:
This question talks about scrollViewInsets and how they can be set on a view-controller-by-view-controller basis. If you do have a view controller, and you don't want its content to appear under a bar, uncheck that box.
But the best way to handle this is to "standardize" your UI, so it isn't varying from view to view. Either make the bar always be translucent, or not always be translucent. This makes transitions less "jarring" for the users.

view considers navigation bar only after rotation

I have a simple UIScrollView
UIScrollView *mainScrollView = [[UIScrollView alloc] initWithFrame:CGRectZero];
[self.view addSubview:mainScrollView];
[mainScrollView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(self.view);
}];
When the view is loaded and shown, part of UIScrollView appears under the navigation bar. But after rotation the view is suddenly considers navigation bar and pins the view to its bottom.
How can I make a view consider navigation bar from the beginning?
To start UIScrollView at bottom of UINavigationBar then i would suggest you to set Adjust Scroll View Insets property and setting Extend Edges property as well. do the needful changes of below property as per your requirement.
Ok, I solved this issue.
Problem has been solved by moving creation of scrollView to viewDidLoad method. Somehow, if scrollView is created outside the "load" methods, we can face such kind of problems.

how to show an overlapping view iOS

I have a view with some UI components and a button on it, upon touch of a button I want to show a half view with some textfields on it overlapping the initial view, the initial view should be visible partly , the overlapping view will cover only half screen from bottom. Is this possible ?
I don't have any code as I am unable to figure out what it needs to be done, as we show any view it covers the entire screen.
Thanks
there are several ways you can do this, here are two:
1) add a popover controller that gets displayed on your button press:
here's some apple documentation on popovers: https://developer.apple.com/Library/ios/documentation/WindowsViews/Conceptual/ViewControllerCatalog/Chapters/Popovers.html
2) add the new view as a subview to your UIViewController
PROGRAMICALLY:
in the viewDidLoad function you can do the following to initialize the halfScreenView
GLfloat topOffset = self.view.frame.size.height/2;
UIView halfScreenView = [[UIView alloc] initWithFrame: CGRectMake(0, topOffset , [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height - topOffset)
[self.view addSubview:halfScreenView];
-more logic might be needed if you support Landscape orientation, you can always re-assign the location of the view with halfScreenView.frame.origin and halfScreenView.frame.size
-initially you can have this view be hidden
halfScreenView.hidden = YES;
-when you click the button it will show the overlaying view:
halfScreenView.hidden = NO;
USING STORYBOARD:
you can also set up your overlaying view in the storyboard if you have one
-drag a UIView into your UIViewController and set it up where you want it to be located
-initialize the view to be hidden by checking the hidden box in the attribute inspector
-add the view as a property to your view
-manage when to show this view with self.halfScreenView.hidden
-this technique allows you to customize what is inside the new view within the storyboard which is nice
FOR BOTH:
-be careful with layers, you don't want your view to show up behind the one you already present. In the storyboard the last thing inserted goes on top. With in the code you can always access/change the views z position with halfScreenView.layer.zPosition (higher z values are on top)
First create a new class subclassing UIViewController called SecondView (or whatever you want), then design the UI the way you want (in its .xib file)
Then go to your main view controller's file and make an IBAction for that button.
In that method, write:
SecondView* second = [[SecondView alloc] initWithFrame:CGRectMake(0, [[UIScreen mainScreen] bounds].size.height/2, height, width);
[self.view addSubview:second.view];
This will add it to the bottom half of the screen. Put your own parameters for its height and width. When you want to dismiss the view, you can do this inside your SecondView class
[self.view removeFromSuperview];
You can deal with the textFields from within the SecondView class and have them communicate with your other view by doing the following in SecondView.h
#property IBOutlet UITextField* textField;
Hope this helps!
Yes, assuming you are using Interface Builder, go ahead and build the overlapping view and hook up all of the IBOutlets and IBActions. Say this view is called myView. Set myView.hidden = YES and myView.enabled = NO. This hides and disables myView so that it isn't even there from the user's perspective. In the appropriate button's IBAction, change the hidden and enabled properties to YES. That will make the view visible and active again.

iOS 7 UIScrollView doesn't scroll when presented as modal view controller, works fine otherwise

I have a storyboard in which I have a view controller, (InfoViewController) in which I have an UIScrollView with some labels, uitextviews, etc. this is all created in IB, no code has been written at all. The only thing that is left for me to do is to set the content size, which I do as following:
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
CGRect screenRect = [[UIScreen mainScreen] bounds];
[self.scrollView setContentSize:CGSizeMake(screenRect.size.width, 600)];
[self.scrollView setBackgroundColor:[UIColor greenColor]];
}
Whenever I make this view the entry point of my app, it works perfectly. I can see my view, the content size is set, the background color is being set to green.
Now it comes, I created another view controller, and this view controller is now my entry point of the app. I added a button in there, and on this button I did a "modal segue" to the earlier mentioned Info View Controller.
When I now run my app, I press this button, my Info View Controller shows up. The green background color is being set, but it's impossible to scroll. So the code is being executed (otherwise the background color couldn't been green, in the storyboard it's just plain white) but somehow whenever I use this "modal segue", the scroll functionality gets lost.
How can I fix this?
Try to insert a UIView into the scroll view...
Set the UIView with top, bottom, leading and trailing space to super view to 0.
Then insert everything into the UIView rather than into the ScrollView
Then modify the constraint height of the inner UIView instead of the contentsize of the scroll view, it works with iOS7

UIViewController view not size correctly when running iOS7 simulator

I have a custom UIViewController which create a view containing an action bar at the top (view with 4 buttons), a tableview and then another view below the tableview. Layout is done all in code and is not using auto layout.
Everything works perfectly on various device with iOS 7.0 and 7.0.2, but in the simulator, the root view of the controller get anchored at the top right corner of the screen (0,0) instead of below the navigation bar.
I'm going to force the relay out in the viewDidAppear: method, but this seem like a hack...
Thanks for any insights
Edit: added an image. You can see the UIView highlighted. As ManicMonkOnMac mentioned, the UIView is under the toolbar (but this only happens in the simulator, on the device, the view lines up fine)
In the loadView method on the controller, i set the frame when creating the view:
- (void)loadView
{
// Our parent view controller will resize us appropriately. The size set
// here is a convenience for initial view layout.
self.view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 320)];
self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
}
But this frame is later changed. Not by my code, though, but by UIkit code)
Edit2: addded loadView method body
EDIT: After going through session 201 of WWDC 2013, I think I have the solution.
in iOS 7 there is a property that you can set on your view controllers to specify whether you want the views to be overlapped by navigation bar.
viewController.edgesForExtendedLayout = UIRectEdgeNone;//UIRectEdgeAll specifies that nav bars should overlap the view.
Unlike iOS 6, navigation bars are placed over the views in iOS 7.
Use the frame size that excludes the navigation bar.
code:
CGRect frame = CGRectMake(self.view.frame.origin.x,self.view.frame.origin.y+self.navigationController.navigationBar.frame.size.height,self.view.frame.size.width,self.view.frame.size.height);
CustomView *view = [[CustomView alloc] initWithFrame:frame];
[self.view addSubview: view];

Resources