I have a UITabbar having 5 tabs like this
Now I want to hide the UITabbar when taps on the Feed Tab. I want to show the full screen there. I am able to hide the tabbar but the UIView of Feed screen is not adjusting itself and I can see the white space at the place of UITabBar. I set the frame of view after hiding the UITabbar but it is also not working. How can I get the object of UITabbarController in the UIViewController classes which are added on the UITabbar so that I can call the delegate methods of UITabbarController. For instance, how can I have the object of UITabbarController in Feed Class.Please Help! If I am not clear please let me know.
Thanks-
Adding to Ariel answer, you need to set "hidesBottomBarWhenPushed" property to YES,when you are loading it from the nib.
As " initWithCoder"-Method is called if you are loading from the nib, you need to set that property there only.
Hope this will help you out.
Try to add self.hidesBottomBarWhenPushed = YES; inside of -(id)initWithCoder:(NSCoder *)aDecoder; of the Feed class implementation like so:
-(id)initWithCoder:(NSCoder *)aDecoder{
self = [super initWithCoder:aDecoder];
if(self){
self.hidesBottomBarWhenPushed = YES;
//more of your initialization code...
}
return self;
}
It should be in -(id)initWithCoder:(NSCoder *)aDecoder; and not -(id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil; as your view is loaded from the .xib file by the application.
Try to set self.navigationController.view.frame size when you hide the tabbar.
You can get the fullscreen size with [[UIScreen mainScreen] bounds].
Related
I am transiting my project to iOS7. I am facing a strange problem related to the translucent navigation bar.
I have a view controller and it has a tableview as subview (let's call it ControllerA) . I init a new uinavigationcontroller with the controllerA and present it modally using presentviewcontroller. The presented view controller's table view is blocked by the navigation bar. I set the automaticallyAdjustsScrollViewInsets to YES but the result did not change.
I knew I can set the edgesForExtendedLayout to UIRectEdgeNone, but it will make the navigation bar no more translucent.
After that, I tried to create a new view controller for testing. It contains almost the same elements. But the result is much different. The table view content does not get blocked.
Conclusion
Two View Controllers' automaticallyAdjustsScrollViewInsets set to YES
The project is not using storyboard
The first one is created at Xcode 4.6, The second one is newly created on Xcode 5
I have compared two classes xib and code, not much different
I have found the answer on apple developer forum.
There are two different case.
The first one, the view controller added is a UITableViewController.
And the issue should not be appeared since apple will auto padding it.
The second one, the view controller is NOT a UITableViewController.
And in the view hierarchy, it contains a UITableView. In this case, if the UITableview(or ScrollView) is the viewController's mainview or the first subview of the mainview, it will work. Otherwise, the view controller doesn't know which scroll view to padding and it will happen the issue.
In my case, the view controller is the second one. And there is a background image view as the first subview of the main view. So, it fails.
Here is the Apple developer forum link (need developer account to access):
https://devforums.apple.com/message/900138#900138
If you want the view to underlap the navigation bar, but also want it positioned so the top of the scrollview's content is positioned below the navigation bar by default, you can add a top inset manually once the view is laid out. This is essentially what the view layout system does when the top-level view is a scroll view.
-(void)viewDidLayoutSubviews {
if ([self respondsToSelector:#selector(topLayoutGuide)]) {
UIEdgeInsets currentInsets = self.scrollView.contentInset;
self.scrollView.contentInset = (UIEdgeInsets){
.top = self.topLayoutGuide.length,
.bottom = currentInsets.bottom,
.left = currentInsets.left,
.right = currentInsets.right
};
}
}
Based on Tony's answer I was able to get around this problem programatically with temporarily sending the table view to the back, let the adjustments be made and then send the background view back to the back. In my case there is no flickering to this approach.
In the View Controller:
- (void)viewWillLayoutSubviews {
[super viewWillLayoutSubviews];
[self.view sendSubviewToBack:self.tableView];
}
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
[self.view sendSubviewToBack:self.backgroundView];
}
Obviously if there are other subviews on self.view you may need to re-order those too.
There's probably too many answers on this already, but I had to take Christopher's solution and modify it slightly to support view resizing and allowing the content inset to be changed in a subclass of the UIViewController.
#interface MyViewController ()
#property (weak, nonatomic) IBOutlet UIScrollView *scrollView;
#property (assign, nonatomic) UIEdgeInsets scrollViewInitialContentInset;
#end
#implementation MyViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self setScrollViewInitialContentInset:UIEdgeInsetsZero];
}
- (void)viewWillLayoutSubviews {
[super viewWillLayoutSubviews];
if (UIEdgeInsetsEqualToEdgeInsets([self scrollViewInitialContentInset], UIEdgeInsetsZero)) {
[self setScrollViewInitialContentInset:[self.scrollView contentInset]];
}
}
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
UIEdgeInsets scrollViewInset = [self scrollViewInitialContentInset];
if (UIEdgeInsetsEqualToEdgeInsets(scrollViewInset, UIEdgeInsetsZero) {
if ([self respondsToSelector:#selector(topLayoutGuide)]) {
scrollViewInset.top = [self.topLayoutGuide length];
}
if ([self respondsToSelector:#selector(bottomLayoutGuide)]) {
scrollViewInset.bottom = [self.bottomLayoutGuide length];
}
[self.scrollView setContentInset:scrollViewInset];
}
}
#end
To explain the point:
Any subclass of MyViewController can now modify the contentInset of scrollView in viewDidLoad and it will be respected. However, if the contentInset of scrollView is UIEdgeInsetsZero: it will be expanded to topLayoutGuide and bottomLayoutGuide.
#Christopher Pickslay solution in Swift 2:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
let topInset = topLayoutGuide.length
inTableView.contentInset.top = topInset
inTableView.contentOffset.y = -topInset
inTableView.scrollIndicatorInsets.top = topInset
}
Yeah - a bit annoying.
I have a nib with a single tableview within the main view, not using autolayout. There is a tabbar, navigationbar and a statusbar and the app needs to work back to 5.0. In Interface builder that neat 'see it in iOS7 and iOS6.1 side-by-side' thing works, showing the tables neatly fitting (once the iOS6/7 deltas were set properly).
However running on a device or simulator there was a large gap at the top of the table, which was as a result of a content inset (which pretty much matched by iOS6/7 vertical delta) that was set to zero in the nib.
Only solution I got was in viewWillAppear to put in [_tableView setContentInset:UIEdgeInsetsZero].
Another ugly hack with a pretty on-screen result.....
[self.navigationController setNavigationBarHidden:YES animated:YES];
in:
- (void)viewDidLoad
I have my interface completely laid out with Storyboards (including the UITabBarController and all corresponding views).
Now comes the time to customize the Tab Bar. Since I have icons that are already set to the correct colour, I can't use [[UITabBar appearance] setTintColor:] (it just keeps looking wrong).
Turns out I'm supposed to use setFinishedSelectedImage:withFinishedUnselectedImage: on the specific UITabBarItem's.
Is it possible to use this method from the AppDelegate (where the rest of my global customization occurs)? How does the AppDelegate know which UITabBar to target?
If instead, I'm supposed to customize each UITabBarItem from each UIViewController, how do I reference the UITabBar (or "root view controller"?) and then specific item from the UIViewController?
Any help would be greatly appreciated.
Thanks!
In viewDidLoad of your UIViewController instances, you can do
[self.tabBarItem setFinishedSelectedImage: withFinishedUnselectedImage:]
Try this
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self) {
[self.tabBarItem setFinishedSelectedImage:[UIImage imageNamed:#"t1s"] withFinishedUnselectedImage:[UIImage imageNamed:#"t1"]];
[self.tabBarItem setTitle:#"Title"];
}
return self;
}
Also, delete image in tabbar item from storyboard view
I'm using the ARC version of the InAppSettingsKit framework (https://github.com/tibr/InAppSettingsKit) to put the settings bundle into my application with Storyboard. I have managed to get the settings work but it shows the settings and I can't go back to the menus of my app.
Any Suggestion? Thanks.
Maybe this will help someone else
I used the main branch with storyboards and the -fno-objc-arc flag but it should be the same solution
I am not sure how you got the back button in your picture above because my button shows as done.
I created a subclass called
#interface SettingsViewController : IASKAppSettingsViewController <IASKSettingsDelegate>
I linked the storyboard to use this class instead of the IASKAppSettingsViewController I added the ShowDoneButton = YES
#implementation SettingsViewController
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self) {
self.delegate = self;
self.showDoneButton = YES;
}
return self;
}
My setup is storyboards with
a modal segue.
a settings button on my main view which links to a navigation controller and a grouped table view
I'm trying to reduce the brightness of my app at night, and while I have pretty good control over my UIView, the UITabBar and UINavigationController are giving me trouble.
How can I dim UITabBar and UINavigationController them without hiding them?
For the UITabBar you could do:
tabBar.alpha = 0.5
A UINavigationController is not a view, it is a controller, thus it doesn't make sense when you say you want to dim it. If you meant that you want to dim the UINavigationBar, you could do:
navigationController.navigationBar.alpha = 0.5;
Or if you want to dim everything in the navigationController:
navigationController.view.alpha = 0.5;
I would create a subclass of UIView that provides a solid black view. Next, you're going to have to pass touch events through the view so you will need to override -pointInside:withEvent:, return NO and pass the message up to the superview. Insert this view as a subview of the view you're trying to dim. Use the alpha property to control the dimming effect.
Edit I'm bored. Here's something I just threw together.
IADimmingView.h
#import <UIKit/UIKit.h>
#interface IADimmingView : UIView
- (id)initWithContainingView:(UIView *)view;
- (void)dim;
#end
IADimmingView.m
#import "IADimmingView.h"
#interface IADimmingView ()
#property (strong, nonatomic) UIView *containingView;
#end
#pragma mark -
#implementation IADimmingView
#synthesize containingView;
- (id)initWithContainingView:(UIView *)view
{
NSParameterAssert(view);
self = [super initWithFrame:view.frame];
if (!self)
return nil;
containingView = view;
self.backgroundColor = [UIColor blackColor];
return self;
}
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
[self.containingView pointInside:point withEvent:event];
return NO;
}
- (void)dim
{
[self.containingView addSubview:self];
}
#end
In your view controller, it is used like this...
IADimmingView *dimmingView = [[IADimmingView alloc] initWithContainingView:self.tabBarController.tabBar];
dimmingView.alpha = 0.75;
[dimmingView dim];
You may make them custom. This was asked many times here, for example: Custom colors in UITabBar
Just do the same with navigation bar.
This is how the navigationBar is declared in the documentation:
The navigation bar managed by the navigation controller. (read-only)
It is permissible to customize the appearance of the navigation bar using the methods and properties of the UINavigationBar class but you must never change its frame, bounds, or alpha values or modify its view hierarchy directly. To show or hide the navigation bar, you should always do so through the navigation controller by changing its navigationBarHidden property or calling the setNavigationBarHidden:animated: method.
This is the answer that I used to fix this: Visible buttons with transparent navigation bar
I have got my own custom UIViewController, which contains a UIScrollView with an UIImageView as it's subview. I would like to make the image to auto rotate when device orientation changes, but it doesn't seem to be working...
In the header file, I've got;
#interface MyViewController : UIViewController <UIScrollViewDelegate> {
IBOutlet UIScrollView *containerView;
UIImageView *imageView;
}
These components are initialised in the loadView function as below;
containerView = [[UIScrollView alloc] initWithFrame:frame];
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:#"http://..."]];
UIImage *image = [[UIImage alloc] initWithData:data];
imageView = [[UIImageView alloc] initWithImage:image];
[image release];
[containerView addSubview:imageView];
And I have added the following method, assuming that's all I need to make the view auto-rotate...
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
MyViewController loads fine with the image I've specified to grab from the URL, and the shouldAutorotate... function is being called, with the correct UIInterfaceOrientation, when I flip the device too.
However, didRotateFromInterfaceOrientation method do not get called, and the image doesn't seem to rotate itself...
Could someone please point out what I need to add, or what I have done wrong here?
Thanks in advance!
This may not be the right answer for you, because you don't specify the context that the UIViewController's in, but I just found an important gotcha in the Apple documentation that explains the similar problem I'm having.
Tab bar controllers support a portrait
orientation by default and do not
rotate to a landscape orientation
unless all of the root view
controllers support such an
orientation. When a device orientation
change occurs, the tab bar controller
queries its array of view controllers.
If any one of them does not support
the orientation, the tab bar
controller does not change its
orientation.
I've noticed that there are issues when rotating a UIView that's not the first or only view as a direct child of the main window.
So if your UIView is part of a Navigation Controller or a Tab View Controller, you'll also need to override shouldAutoRotateToInterfaceOrientation on the Navigation Controller or Tab View Controller.
Also: using [UIApplication setStatusBarOrientation] helps to work around things if/when you need to do it manually.
To make this kind of thing work in my application, I had to override
- (void) didRotateFromInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
[self layoutSubviews];
}
and also layoutSubviews
- (void)layoutSubviews
{
NSLog(#"layoutSubviews called");
...recalc rects etc based on the new self.view.bounds...
}
I'm not sure that this is absolutely required, but it worked for me.
Sometimes, if you add a subview to a view, it's your responsibility to make sure that the methods are passed to the subview; a couple of days ago I wrote a short post about this. For example, if you have a UIViewController and add a UINavigationController as subview, you must add this code to the UIViewController if you want viewWillAppear:animated: to be called when UINavigationController.view appears:
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[projectNavigationController viewWillAppear:animated];
}
It might be the case that the willRotateToInterfaceOrientation and didRotateFromInterfaceOrientation method also need to be called by the superview; I am not really sure about this, but give it a try.
This is discussed in Apple Technical Q&A QA1688.
Sometimes if you stack multiple views on top of each other for some reason, the anotherController might not receive rotation event.
[myWindow addSubview:primaryViewController.view];
[myWindow addSubview:anotherController.view];
A lazy way (not a good design) to fix this is only add one subview on window, but initialize multiple controller on the app delegate. Then when you need to switch window, remove the current view and add the view you want
[self.view removeFromSuperview];
AppDelegate *dg = (AppDelegate *)[[UIApplication sharedApplication] delegate];
[[dg window] addSubview:[[dg viewController] view]];
I just came across this having a similar problem. I have a series of view controllers/complex views, that all rotate perfectly and couldn't figure out why the new one I just added on wasn't rotating. After a LOT of trial and error, the reason was that I wasn't calling the init method (it's the standard init method) when allocating the view controller;
e.g. I was doing
m_timerViewController = [TimerViewController alloc];
instead of
m_timerViewController = [[TimerViewController alloc] init];
To expand on jonoogle's post. I had a similar error. My view has a nib and my custom init:
- (id)initWithCategory:(Category *)category inManagedObjectContext:context{
didn't include the call to init the nib.
self = [super initWithNibName:nil bundle:nil];
Adding that line made my view rotate like it is supposed to.
I copied this from this link
And it works for me.... Reason why i have added this here is to make it easy for others to find. It took me many hours to find this fix:
Make a new set of class files of the UIViewController type, go into the .h file of this class and change this line
#implementation MyTabBarController: UIViewController {}
#end
to something like this
#implementation MyTabBarController: UITabBarController{
}
Now go into the nib file and click on the UITabBarController object and go to it's identity tab, and make it Class MyTabBarController.
now in MyTabBarController.m make sure this is in it.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)io {
return YES;
}
You can probably get rid of everything else in there if you want.
just do this if you what to rotate from landscape to portrait!
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}