Blank space coming between keyboard and UIVew in iOS - ios

I have a tab bar controller-based application and I am using IQKeyboardManager to handle form-like stuff.
Step 1: Tab bar controller with bottom a UITextView inside a UIView. Check Image 1.
Step2: When I click on UITextView, the keyboard appears but a blank space is appearing due to the tab bar. I have tried to remove IQKeyboardManager but it still occurs, so it is confirmed that it is not the issue of IQKeyboardManager. It is an issue due to the tab bar controller.
How to remove that spacing?

You are correct. The blank space is caused by the tab bar. Override the y position in the view by adding the additional space when you receive keyboard should appear and not in your viewDidLoad or any place else because it will then be hidden behind the tab bar. Then you need to set it back to normal by removing that added value when the user is finished using the keyboard. eg.
// Declaration
var tabBarHeight : CGFloat = 0.0
// viewDidLoad
tabBarHeight = tabBarController?.tabBar.frame.size.height
// When the user begins using the keyboard move the view containing the textfield
yourView.frame.origin.y = (tabBarController?.tabBar.frame.origin.y + tabBarHeight )
// When the user finishes using the keyboard
yourView.frame.origin.y = (tabBarController?.tabBar.frame.origin.y - tabBarHeight )
If you have constraints, you will need to adjust them. Good answer here:
https://stackoverflow.com/a/27870216/4008175
This answer will assist you in listening to when the keyboard has been activated and deactivated:
https://stackoverflow.com/a/27087733/4008175
Good luck!

Related

backBarButtonItem becomes visible on iOS 10 when titleView has constraints

Having a very weird behavior on iOS 10. Assume you have an empty app, created with a Master-Detail Application template. Place any UIView as a titleView in navigationBar for detail viewcontroller. Place any UIView to the right bar button items.
Then, write that code to configureView method:
if let item = self.splitViewController?.displayModeButtonItem {
self.navigationItem.leftBarButtonItem = item
self.navigationItem.leftItemsSupplementBackButton = true
}
Then configure splitviewcontroller preferredDisplayMode = .allVisible, so the displayModeButtonItem could appear.
On iOS 9 and lower this results in a standard behavior: the detail viewcontroller displays displayModeButtonItem expand button on a left side.
When user taps it, the icon transforms to an arrow. Tapping an arrow reverses button state.
On iOS 10 displayModeButtonItem displays as expand button, but if user taps it, it disappears.
Meanwhile, the button is still there and a user can tap it one more time. After that, displayModeButtonItem appears again with expand icon and backButtonItem icon as well. Just like it appears when we push another viewcontroller onto detail's navigationcontroller:
But in that case both of icons acts as displayModeButtonItem.
Is this an iOS bug, or a misconfig? What can I do to get normal button behavior?
Edit: I found out, that everything works as expected, if a titleView (of rightBarButtonItem's view) does not contain any constraints on it's child views. Filed a radar on this.
Edit 2: Some controls (like UIImageView) may implicitly add NSContentSizeLayoutConstraint, so, to prevent this behavior (and prevent the bug above), subclass it and override intrinsicContentSize method like this:
private class NoConstraintsUIImageView: UIImageView {
private override func intrinsicContentSize() -> CGSize {
// prevent implicit NSContentSizeLayoutConstraint adding in updateConstraints
return CGSize(width: UIViewNoIntrinsicMetric, height: UIViewNoIntrinsicMetric)
}
}

iOS 10 - View Controller / Navigation Bar Title hidden

I'm currently facing stranges behaviours with iOS 10.
Indeed, everything was working fine, but since I updated to xCode 8 and began testing my App on iOS 10, a lot of stuff went wrong.
For example, all my Navigation Bar's titles are not displayed anymore.
More precisely, when I'm using the menu to navigate threw my app, every time I switch to a different view, there are no title, BUT when I press the back button, I can briefly see it before the transition to the other view.
I don't understand this new behaviour, I didn't change anything in the code, and when I launch the App on iOS 9 or lesser, everything is working properly.
I tried to set the title in the ViewWillAppear / ViewDidLoad, in the prepareForSegue, but nothing is working.
if ([segue.identifier isEqualToString:kMy_Segue]) {
MyViewController* destinationVC = segue.destinationViewController;
[destinationVC setTitle:#"MyTitle"];
}
I feel like there are some changes with the pushed Navigation Controller, or the title item is not at the same index than the Navigation Bar itself because when I navigate threw subviews in the menu, the title only appears when I press back.
For example I have a category in my Menu called "World".
When I tap it I want the title of the subview to be "World", but nothing is displayed. Then, I have all the continents listed "Africa", "Europe", "Asia" etc...
When I tap on Africa, I want the next title to be "Africa" right?
And again, nothing is displayed BUT if I press the back button and go back to the list of continents, the title "World" appears.
If anyone has encountered this issue, I would really appreciate some help.
Follow this:
Solution-1
Goto to the viewController, then click on NavigationItem as shown below:
In the right pane, change "Title" as follows:
Solution-2
Add a UIView to your navigationBar as shown below:
Add an UILabel to your navigationItem as shown below:
Change the frame of the newly added UILabel as follows:
Change text of UILabel to "Sample Title" and change UIView backgroundColor to clearColor.
I have made a sample in Xcode8, please check my GitHub link below:
https://github.com/k-sathireddy/NavigationItemSample
Have you try to adding navigation item on to your navigation bar? You'r using Storyboard for this design.
I found a solution to my issue. It's really weird.
I have a fade animation to the navigation bar on the Home Page.
It's a scroll view so that when I scroll down I can still see the title and the navigation bar.
On iOS < 10, the fade animation only change the background color and transparency. But when I launch the app on iOS 10, the fade effect hide everything, the menu icon, the title, everything. I believe Apple changed the structure of the navigation bar items.
Moreover, when I tap on the menu icon to navigate threw my App when the fade animation is on going, I can see that the title and the navigation bar items are under "fade effect" and even for the next ViewControllers's title after my navigation.
So it's working, it's just that the menu icon, titles etc.. are hidden on the Navigation Bar.
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
UIColor * color = [Constants backgroundColor];
CGFloat offsetY = scrollView.contentOffset.y;
CGFloat threshold = 250;
if (offsetY > threshold) {
[self.navigationController.navigationBar lt_setBackgroundColor:[color colorWithAlphaComponent:1]];
} else {
CGFloat alpha = offsetY / threshold;
[self.navigationController.navigationBar lt_setBackgroundColor:[color colorWithAlphaComponent:alpha]];
}
}
I guess the issue is coming from the library LTNavigationBar that I used to change the appearance of the NavigationBar dynamically...

UISearchBar in a NavigationBar width

I would like to have an UISearchbar in my NavigationBar - as I've done here:
When the SearchBar gets the Focus, I'll remove the left Button with:
self.navigationItem.leftBarButtonItems = []
And try to make the UISearchBar getting the whole width of the Screen (with a Cancel Button)
searchBar.sizeToFit()
searchBar.showsCancelButton = true
But my UISearchBar is too wide, it looks like in this screen:
But why is that? I want to get the following result:
User clicks into the SeachBar, I'll FadeIn a UITableView for the Results - when the User presses the Cancel Button, the UITableView fades out and I'll add the "Kategorie" left Button again.
Is this a way how to solve that - or can I not use the sizeToFit() method here?
Seems like you placed your searched bar as a rightBarButtonItem and that spot has a right margin. Your searchBar is trying to expand to be the full width of the screen, hence it gets to be too wide.
I used a search controller and implemented didPresentSearchController and resized it there.
How about setting the width of the search bar equal to the screen minus the size of the 'Cancel' button, or try to add constraints between the search bar and leading space to the navigation controller.

iOS UITextField Outside of SuperView not Responding to Touches

I'm building an iOS 8 app that makes use of the new hidesBarsOnSwipe property on UINavgitationController to hide the nav bar while scrolling. At the same time that the nav bar hides, I'm also programmatically hiding the tab bar. On top of the tab bar, there is a text field which lets users comment on a post (much like Facebook). When the tab bar is hidden (by moving it downward and off the screen), the text field is moved down as well, so that it now sits at the bottom of the screen and so that there's no gap between the bottom of the screen and the text field.
So, things look great. But, turns out that the text field doesn't respond to touch events when it moves to the bottom of the screen. I did some digging and it appears that the reason is because the text field is outside of its superview (the view controller's view), and so touch events will not be sent to the text field.
So I think I've figured out why the issue is occurring, but I haven't yet figured out how to fix it. I've tried messing with hitTest:withEvent: and pointInside:withEvent: but didn't have any luck. Anyone have any solutions?
EDIT: Here is some code to make the question clearer (hopefully). When the nav controller's barHideOnSwipeGestureRecognizer is called, I am running the following code:
- (void)barHideSwipeGestureActivated:(UIPanGestureRecognizer*)gesture
{
[self animateTabBarUpOrDown:self.navigationController.navigationBar.frame.origin.y >= 0 completion:nil];
}
The method above is the following:
- (void)animateTabBarUpOrDown:(BOOL)up completion:(void (^)(void))completionBlock
{
if(!self.animatingTabBar && self.tabbarIsUp != up)
{
self.animatingTabBar = YES;
//to animate the tabbar up, reset the comments bottom constraint to 0 and set the tab bar frame to it's original place
//to animate the tabbar down, move its frame down by its height. set comments bottom constraint to the negative value of that height.
[UIView animateWithDuration:kTabBarAnimationDuration animations:^{
UITabBar *tabBar = self.tabBarController.tabBar;
if(up)
{
tabBar.frame = CGRectMake(tabBar.frame.origin.x, tabBar.frame.origin.y - tabBar.frame.size.height, tabBar.frame.size.width, tabBar.frame.size.height);
self.addCommentViewToBottomConstraint.constant = 0.0f;
}
else
{
tabBar.frame = CGRectMake(tabBar.frame.origin.x, tabBar.frame.origin.y + tabBar.frame.size.height, tabBar.frame.size.width, tabBar.frame.size.height);
self.addCommentViewToBottomConstraint.constant = -tabBar.frame.size.height;
}
} completion:^(BOOL finished) {
self.tabbarIsUp = up;
self.animatingTabBar = NO;
if(completionBlock)
{
completionBlock();
}
}];
}
}
Ok, finally found a solution for this one. I haphazardly messed around with changing the bounds of my view controller's view, but that was too hacky and ultimately didn't accomplish what I wanted it to.
What I ended up doing was changing my view controller's edgesForExtendedLayout property to be equal to UIRectEdgeAll which basically says that the view should take up the entire screen, and extend above top bars / below bottom bars.
I had to hack around a little bit with changing auto layout constraints on my text field so that it appeared in the right place at the right time, but overall, the solution was changing edgesForExtendedLayout to be UIRectEdgeAll - this makes the view take up the entire screen, so the text field is now still in the super view even when it animates downward, thus, allowing it to still receive touch events.

Black bar flashes at top of UITableView when pushing to view with "Hides Bottom Bar When Pushed" in IB

This is a weird error that may just be an issue in Xcode for all I know. I have a tab bar controller where the first view is a UITableView with (obviously) a number of cells. When you select a cell, I've set up a segue on the MainStoryboard to go to a detail view controller. I want the tab bar to be hidden when I go to the detail view, so I went into the storyboard, chose my detail view, and clicked "Hides Bottom Bar on Push" in the editor screen that starts with "Simulated Metrics."
Everything works just fine, except that when I tap on a cell, a black bar flashes at the top of the UITableView screen, dropping the tableview cells down (as if the cells are falling down below the tab bar at the bottom), just before the screen pushes over to the detail view. The effect isn't harmful at all, but it's very disconcerting, and I'd like to smooth that out.
The only fix I've found is to uncheck the "Hides Bottom Bar when Pushed" option on the storyboard. That indeed does get rid of that black bar flash, but of course the tab bar stays on the screen when I go to the detail view, which is what I don't want.
Any ideas?
Just for completeness' sake, I went ahead and ran
[self.navigationController setToolbarHidden:YES animated: YES];
on the detail view controller's viewWillAppear method (and even tried it with the storyboard option both on and off), but there was no difference. The toolbar did indeed hide just fine, but I still got that black line at the top. So weird.
I know it is too late !!! I ran into same issue. It seems like the Auto resizing mask for the view was incorrect to be exact the UIViewAutoresizingFlexibleTopMargin. I checked this on in the xib file. If you are trying to do it in code make sure this flag -UIViewAutoresizingFlexibleTopMargin - is not included in the autoresizing mask.
Hope this will help some one in the future
I know it is a bit late, but I have same problem and I can't solve it with any of the previous answers. (I suppose this is the reason non was accepted).
The problem is that view size of the SecondViewController is same as view size of a previous ViewController, so too small to fit in a ViewController with Toolbar hidden. Thats why black background of a UITabBarController is visible at the top when transition is happening, and on a viewDidAppear view will stretch on right size.
For me it help to subclass root UITabBarController and set background color to same background color as SecondViewController has.
class RootViewController: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = Style.backgroundColor
}
}
Then you can leave checkbox checked inside storyboard and it will look ok.
P.S.
If you have some views, that is position on the bottom part of the view, you need to set bottom constraints so they are smaller by 49 (because this is the height of the toolbar), and then on viewDidAppear set the right constraint.
For example:
I have view that need to be position 44 px from bottom edge. Before, I have constraint set to 44 and I have some strange behaviour of that view. It was placed to height and then jump on the right place.
I fix this with setting constraint to -5 (44-49), and then in viewDidAppear set the constraint back to 44. Now I have normal behaviour of that view.
Wow I just had the same issue now, very painful, and no info on the net about it.
Anyway, a simple workaround for me was to change the current view's Frame moving the y coordinates up and making the height bigger by the height of the tab bar. This fixed the problem if done straight after pushing the new view onto the navigation controller. Also, there was no need to fix the Frame afterwards (it must be updated when the view is shown again).
MonoTouch code:
UIViewController viewControllerToPush = new MyViewController();
viewControllerToPush.HidesBottomBarWhenPushed = true; // I had this in the MyViewController's constructor, doesn't make any difference
this.NavigationController.PushViewController(viewControllerToPush, true);
float offset = this.TabBarController.TabBar.Frame.Height;
this.View.Frame = new System.Drawing.RectangleF(0, -offset, this.View.Frame.Width, this.View.Frame.Height + offset);
Objective C code (untested, just a translation of the monotouch code):
UIViewController *viewControllerToPush = [MyViewController new];
viewControllerToPush.hidesBottomBarWhenPushed = YES; viewControllerToPush.hidesBottomBarWhenPushed = YES;
float offset = self.tabBarController.tabBar.frame.size.height; float offset = self.tabBarController.tabBar.frame.size.height;
self.view.frame = CGRectMake(0, -offset, self.view.frame.width, self.view.frame.height + offset); self.view.frame = CGRectMake(0, -offset, self.view.frame.size.width, self.view.frame.size.height + offset);
Do this in viewWillAppear of detailViewController, it should work fine
subclass your navigation controller, or just find the navigation bar
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
let backdropEffectView = navigationBar.subviews[0].subviews[0].subviews[0] //_UIBackdropEffectView
let visualEffectView: UIVisualEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .Light))
visualEffectView.frame = backdropEffectView.frame
backdropEffectView.superview?.insertSubview(visualEffectView, aboveSubview: backdropEffectView)
backdropEffectView.removeFromSuperview()
}

Resources