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
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 an scrollview in my app.
If I click on a Button on one Page, a Subview is added. I want to remove this subview when the user scrolls the view. This function is called:
-(void) DisableViews {
[Annimation removeFromSuperview];
NSLog(#"scroll");
}
I get the NSLog many times, but the view also is Subview when i come back to the page.
I think this will happen, because the view with the subview is not the present view at this time, so i can't remove the subview.
Is there any possibility to remove a subview from any view on the subview?
edit:
ViewController.h
#interface ViewController : UIViewController {
//...
UIView *Annimation;
}
#property (nonatomic,retain) UIView *Annimation;
Implementation:
ViewController.m
#import "ViewController.h"
#import "AppDelegate.h"
#implementation ViewController
#synthesize Annimation;
//...
- (void) Bild1ButtonKlickt{
Annimation = [[UIView alloc]initWithFrame:CGRectMake(0.0, 0.0, 320.0, 480.0)];
Annimation.backgroundColor = [UIColor blackColor];
[self.view addSubview:Annimation];
}
Most likely "Annimation" (which I assume is an ivar) is nil at this point, and so nothing is happening when you try to remove it.
(As a note, don't access your ivars directly this way. Your property should be called animationView (to make it clear it's a view and not an NSAnimation, and you should access it via self.animationView. Also, methods should always have a leading lowercase. ObjC is very sensitive to method and property naming. Proper naming matters for the runtime; it's not just stylistic.)
As requested as answer: Is that the only subview in that scrollview? Anyway, one of the answers from how to remove subviews from scrollview? should work.
Now which answer from the above page did fix it?
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].
So it is very easy to hide the tabbar when you push a view controller onto the navigation controller stack:
uiViewController.hidesBottomBarWhenPushed = YES;
works just peachy.
Put let's say I want to push deeper into the stack and show it again?
Setting
laterUIViewController.hidesBottomBarWhenPushed = NO;
on some later view controller doesn't make it reappear. It's still hidden.
You could try subclassing UIViewController and overriding the
- (void)viewWillAppear:(BOOL)animated { self.hidesBottomBarWhenPushed = YES; }
- (void)viewWillDisappear:(BOOL)animated { self.hidesBottomBarWhenPushed = NO; }
And then using that subclass as the superclass of the view controller that you want to show the bottom bar.
This worked for me:
- (void)viewWillAppear:(BOOL)animated { self.tabBarController.tabBar.hidden = YES; }
- (void)viewWillDisappear:(BOOL)animated { self.tabBarController.tabBar.hidden = NO; }
Try this workaround: if you don't animate switching between view controllers it should work OK.
The idea is to make your tabbar controller's view size bigger so tabbar (which is at the bottom of the view) goes out of the screen and restore the view size when hiding the view.
In your view controller that should hide a tab bar define the following methods:
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
CGRect r = self.tabBarController.view.frame;
r.size.height +=self.tabBarController.tabbar.frame.size.height;
self.tabBarController.view.frame = r;
}
-(void)viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
self.tabBarController.view.frame = CGRectMake(0, 0, 320, 480); //for iPhone portrait
}
You need to make sure that in your app delegate tabbar controler and window outlets are defined and properly linked with XIB
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet UITabBarController *tabBarController;
Try un hidding it, so you tell it to hide, it hides, but then you tell it to not hide it (i dont know if it re shows it if you set this to no) but it looks like it isnt, either that or u are telling it to not hide when the view controller you want the bar in has been pushed already and it does not un hide the bar until the next view controller has been pushed, so you should try to set it as unhidden youself.
How can I change the color of navigation bar from its default blue color?
Thanks.
The UINavigationBar class has a UIColor *tintColor property that you can change in code.
Alternately this property is also exposed in the InterfaceBuilder UI design tool.
Assuming you have added the navigation bar programmatically and not in Interface Builder, just put this in your viewDidLoad method.
self.navigationController.navigationBar.tintColor = [UIColor grayColor];
TintColor property doesn't affect default subview of navigation bar as bottom border and shadow. Sometimes it's useful to override layout of navigation bar at all.
Despite navigationBar is read-only property for UINavigationController you can avoid
this restriction by "setValue:forKey:". This method was approved on 5 applications successfully submitted to AppStore.
You can subclass UINavigationBar and change drawRect: method as you want.
For example,
#implementation CustomNavigationBar
- (void) drawRect:(CGRect)rect
{
[super drawRect:rect];
UIImage *backgroundImage = ImageFromColor(WANTED_COLOR);
[backgroundImage drawInRect:rect];
}
After you can subclass UINavigationController and change initWithRootViewController:
- (id) initWithRootViewController:(UIViewController *)rootViewController
{
self = [super initWithRootViewController:rootViewController];
if (self)
{
CustomNavigationBar *navBar = [CustomNavigationBar new];
[self setValue:navBar forKey:#"navigationBar"];
}
return self;
}
Also you can vary this approach by making Category for UINavigationController and implementing method swizzling for initWithRootViewController:
P.S. Yesterday my new app appeared at AppStore without any problem with this approach.