iOS 13 UITabBar RePosition to Top - ios

I have followed this answer to reposition my tabbar to top of the page. It was working perfect until iOS 13 release. In iOS 13 the tabbar is visible on bottom of the screen. Any other workaround should i have to use?
Does anyone faced the same problem?
Update:
Below piece of code i have used in my app:
- (void) viewWillLayoutSubviews {
[super viewWillLayoutSubviews];
[self.tabBar invalidateIntrinsicContentSize];
// Just a quick fix for making this to happen for iOS versions between 11.0 to 11.1
// Updating the frame in Main queue.
dispatch_async(dispatch_get_main_queue(), ^{
[self changeTabBarPosition];
});
// Set the translucent property to NO then back to YES to
// force the UITabBar to reblur, otherwise part of the
// new frame will be completely transparent if we rotate
// from a landscape orientation to a portrait orientation.
self.tabBar.translucent = NO;
self.tabBar.translucent = YES;
}
- (void)changeTabBarPosition {
CGFloat tabSize = 44.0;
UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
if (UIInterfaceOrientationIsLandscape(orientation)) {
tabSize = 32.0;
}
CGRect tabFrame = self.tabBar.frame;
tabFrame.size.height = tabSize;
tabFrame.origin.y = [UIApplication sharedApplication].statusBarFrame.size.height;
self.tabBar.frame = tabFrame;
}

I found the solution with the help of #Thanh Vu mentioned in his/her answer. Below piece of code fixed my issue.
- (void) viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
[self.tabBar invalidateIntrinsicContentSize];
CGRect tabFrame = self.tabBar.frame;
tabFrame.size.height = 44.0;
tabFrame.origin.y = 0;
self.tabBar.frame = tabFrame;
// Set the translucent property to NO then back to YES to
// force the UITabBar to reblur, otherwise part of the
// new frame will be completely transparent if we rotate
// from a landscape orientation to a portrait orientation.
self.tabBar.translucent = NO;
self.tabBar.translucent = YES;
}

I just test bellow code on iOS 13. It still work.
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
self.tabBarController.tabBar.frame = CGRectMake(0, 0, self.view.frame.size.width, self.tabBarController.tabBar.frame.size.height);
}

I get this solution after a lot struggle too, with Swift5 + IOS13.2Sdk. Follow this answer.
class MyUITabBarController:UITabBarController{
override func viewDidLayoutSubviews(){
super.viewDidLayoutSubviews()
var frame = self.tabBar.frame
frame.origin.y = 0
self.tabBar.frame = frame
}
}

Related

How to make UINavigationBar taller like in Mail.app

Apple Mail app in thread views has a dynamic, taller than usual navigation bar which collapses when you scroll. Is it possible to achieve same effect using only allowed API calls or is this available only internally for Apple?
Expanded:
Collapsed:
Please check here. The link has different ways to solve the problem.
However following code helped me.
for subview in (self.navigationController?.navigationBar.subviews)! {
if NSStringFromClass(subview.classForCoder).contains("BarBackground") {
var subViewFrame: CGRect = subview.frame
// subViewFrame.origin.y = -20;
subViewFrame.size.height = 100
subview.frame = subViewFrame
}
}
You can able to set it as follows
-(void)layoutSubviews{
[super layoutSubviews];
CGRect rectStatus = [[UIApplication sharedApplication] statusBarFrame];
if (rectStatus.size.height==44.f) {
}else{
if (#available(iOS 11.0, *)) {
for ( UIView*aView in self.subviews) {
if ([NSStringFromClass(aView.classForCoder) isEqualToString:#"_UINavigationBarContentView"]) {
aView.frame = CGRectMake( 0,20,aView.frame.size.width,44);
}
else if ([NSStringFromClass(aView.classForCoder) isEqualToString:#"_UIBarBackground"]) {
aView.frame = CGRectMake(0,0,aView.frame.size.width, 64);
}
}
}
}
}

Unable to make tabbar visible

I am having an app where I am hiding and showing tabbar on an event, below is the method I am using , when I try to hide it, it works fine . But when I am trying to make it visible it doesn't work.
-(void)setTabBarVisible:(BOOL)visible animated:(BOOL)animated completion:(void (^)(BOOL))completion {
// RootViewController* tabBarController = (RootViewController*)self.navigationController.parentViewController.parentViewController;
UITabBarController *tabBarController = self.tabBarController;
CGFloat duration = (animated)? 0.3 : 0.0;
CGRect frame = tabBarController.tabBar.frame;
CGFloat height = frame.size.height;
CGFloat offsetY = (visible)? -height : height;
CGRect playerFrame = player.view.frame;
CGRect toolBarFrame = self.toolbar.frame;
[UIView animateWithDuration:duration animations:^{
CGRect fr = CGRectOffset(frame, 0, offsetY);
tabBarController.tabBar.frame = fr;
if((!visible && ![self toolBarOnBottom]) || visible) {
self.toolbar.frame = CGRectOffset(toolBarFrame, 0, offsetY);
[self.toolbar layoutIfNeeded];
}
} completion:completion];
}
I when I debug code the second time I call this method to make it visible , the tabbar frame is zero , I think this is the problem. I am testing this on Xcode 9 with iOS 11 SDK. I am not sure if Safe area has anything to do with this.
Any help would be appreciated.
As I wanted to get a working solution , ended up using this , works perfect with autolayout and safe area
Hide UINavBar and UITabBar at the same time with animation

iAd frame returning wrong height on iPhone

I have an iAd which I am trying to position at the bottom of the screen though when I try to get the height of the ad so that I can put it at the bottom. This error only occurs when I enter the screen in a landscape orientation as the ad is taller in the portrait orientation and only on the iPhone simulator as on an ipad the ads are the same height.
The method I am using to put the add at the bottom is by setting the y value of the ad frame to the height of the view minus the height of the ad.
Here is the code that I am currently using:
- (void)viewWillAppear:(BOOL)animated
{
CGRect adFrame = banner.frame;
adFrame.origin.y = screenHeight - banner.frame.size.height;
adFrame.size.width = screenWidth;
banner.frame = adFrame;
[banner setAutoresizingMask:UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleWidth];
}
- (void)viewDidLoad
{
[super viewDidLoad];
banner.frame = CGRectZero;
}
Any help would be much appreciated.
I would take a look at Apple's sample code
for integrating iAD exactly how you describe, particularly in ContainerBanner/ContainerBanner/BannerViewController.m. What you are looking for is ADBannerView's - (CGSize)sizeThatFits:(CGSize)size.
CGRect adRect = CGRectZero;
CGRect contentFrame = self.view.bounds;
adRect.size = [banner sizeThatFits:contentFrame.size];
adRect.origin.y = CGRectGetHeight(contentFrame) - CGRectGetHeight(adRect);
banner.frame = adRect;

UIScrollView issue on tapping UITextView or UITextField on keyboard presentation

I have a UIScrollView, which contains UITextFields and UITextViews. I have registered for the UIKeyboardDidChangeFrameNotification. When I tap on a text field or text view, the did change frame notification action is triggered and I adjust the contentOffset of the scroll view as shown below
- (void)keyboardDidChangeFrame:(NSNotification *)notification
{
CGRect keyboardEndFrame;
[[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardEndFrame];
CGRect screenRect = [[UIScreen mainScreen] bounds];
CGRect intersection;
UIView *theFirstResponder = [[UIApplication sharedApplication].keyWindow findFirstResponder];
if ([theFirstResponder isKindOfClass:[UITextView class]]) {
if ([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeLeft) {
keyboardEndFrame = CGRectMake(keyboardEndFrame.origin.y, 416, keyboardEndFrame.size.height, keyboardEndFrame.size.width);
}
else if ([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeRight)
{
keyboardEndFrame = CGRectMake(keyboardEndFrame.origin.y, 0, keyboardEndFrame.size.height, keyboardEndFrame.size.width);
}
}
else
keyboardEndFrame = CGRectMake(keyboardEndFrame.origin.y, keyboardEndFrame.origin.x, keyboardEndFrame.size.height, keyboardEndFrame.size.width);
screenRect = CGRectMake(screenRect.origin.y, screenRect.origin.x, screenRect.size.height, screenRect.size.width);
if(CGRectEqualToRect(lastKBDRect, keyboardEndFrame)) {
return;
}
lastKBDRect = keyboardEndFrame;
if (CGRectIntersectsRect(keyboardEndFrame, screenRect)) {
// Keyboard is visible
//Convert Frame of the first responder, in context of the view that needs to be shifted
UIView *firstResponder = [[UIApplication sharedApplication].keyWindow findFirstResponder];
CGRect theRect = [firstResponder convertRect:firstResponder.frame toView:[UIApplication sharedApplication].keyWindow];
theRect = CGRectMake(theRect.origin.y, theRect.origin.x > 768 ? 750 : theRect.origin.x, theRect.size.height, theRect.size.width);
intersection = CGRectIntersection(keyboardEndFrame, theRect);
//If intersection is null, then no need to shift anything. Simply return.
if(CGRectIsNull(intersection)) {
return;
}
//Shift the view so that the first responder view is completely visible, keeping the constraint that the origin of the first responder view is also visible.
//Remember the current offset, so when we shift the view back, we shift it to the proper position.
if (!wasContentViewShifted) {
lastContentOffset = contentScrollView.contentOffset;
lastContentSize = contentScrollView.contentSize;
wasContentViewShifted = YES;
}
CGFloat offset = theRect.origin.y + theRect.size.height - keyboardEndFrame.origin.y;
if((theRect.origin.y - offset) < 40) {
offset += 42;
}
[UIView animateWithDuration:0.3f animations:^{
contentScrollView.contentOffset = CGPointMake(0, contentScrollView.contentOffset.y + offset);
contentScrollView.contentSize = CGSizeMake(0, lastContentSize.height + (600 - theRect.size.height));
}];
} else {
// Keyboard is hidden. Move the view back only if it was shifted.
if(wasContentViewShifted) {
wasContentViewShifted = NO;
[UIView animateWithDuration:0.3f animations:^{
contentScrollView.contentOffset = lastContentOffset;
contentScrollView.contentSize = lastContentSize;
}];
}
}
}
The application supports only landscape orientation.
The problems I'm facing here are
Tapping on textView presents the keyboard and textview is scrolled to the top if it is hidden by keyboard. Now, changing the orientation (landscape left to landscape Right) makes the textView scroll further to top and hence invisible.
The scrolling of TextView sometimes works for landscape left orientation but not for landscape right orientation and vice versa. This is because of the keyboardEndFrame values I'm using. Shouldn't I use the keyboardEndFrame origin values ? If not, what would be the alternative ?
Sometimes the it works for the textField but not for the textView.
Instead of having such complex solution you can try using this.
One simpler solution can also be found here.
Also it is not advisable to hard code the frames as you are doing. Refer to the apple documentation for more details.

Background picture is "blinking" when the screen orientation is changed

I would like to change the background picture of my view controller, when the orientation is changed. I call my setupGUIForOrientation function in shouldAutorotateToInterfaceOrientation, like this:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
[self setupGUIForOrientation:interfaceOrientation];
return YES;
}
The setupGUIForOrientation function:
-(void)setupGUIForOrientation:(UIInterfaceOrientation)orientation
{
if(!background) background = [[UIImageView alloc] init];
UIImage* image = [[StorageProvider storage].imageProvider getImageForSurfaceElement:#"background"];
int width = 0;
int height = 0;
CGRect bounds = [[UIScreen mainScreen] bounds];
if(UIInterfaceOrientationIsPortrait(orientation)) {
width = MIN(bounds.size.width, bounds.size.height);
height = MAX(bounds.size.width, bounds.size.height);
} else {
width = MAX(bounds.size.width, bounds.size.height);
height = MIN(bounds.size.width, bounds.size.height);
}
background.frame = CGRectMake(0, 0, width, height);
[self.view addSubview: background];
[self.view sendSubviewToBack: background];
[background setImage:image];
}
Everything is good (the image and the frame changes) except one thing: when the rotation happens, I can see the view controller's background color for one second, which is really ugly. Can I prevent it somehow? And, can I code this function on a better way? Thanks for any help!
I'm guessing, but you may be updating your view too early. Rather than call your method in shouldAutorotateToInterfaceOrientation, have you tried doing it in didRotateFromInterfaceOrientation?
I.e. making this change:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
[self setupGUIForOrientation:self.interfaceOrientation];
}

Resources