ok I know many people asked this question,
but mine is different from their situations.
many asked to hide the bar and they find the way,
my app, wanna launch without bar, and shows bar when loaded,
what I did is set Status bar is initially hidden to YES,
and in
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
[application setStatusBarHidden:NO withAnimation:UIStatusBarAnimationFade];
works good on iOS6, view bounds 320*460
on iOS7, bounds of my view controller.view becomes 320*480, which under the status bar,
people say to change the origin.y of window and I tried, it leaves a 20px gap, but of course the status bar is clipped out,
I tried
self.edgesForExtendedLayout = UIRectEdgeNone;
self.automaticallyAdjustsScrollViewInsets = YES;
not working,
and many other ways, not working too.
anyone helps, pls dont downvote me, many people like me want the answer.
EDITING:
self.edgesForExtendedLayout = UIRectEdgeNone; only works when you use a navigation bar by system,self.view became 416px, reduces 64, but if self.navigationController.navigationBarHidden = YES; you sill got a 480 px view....
so bad design .....
Related
I am attempting to add a custom view to an NSMenuItem in the OS X 10.10 Yosemite menu bar.
The custom view is simply an NSView background with an NSTextField “label”.
The problem is that the background NSView is given Yosemite-style vibrancy/transparency when added to the menu. The NSTextfield label is not.
Through the use of NSRectFillUsingOperation I've gotten this to look good for some background colors in Yosemite. But others continue to not match. When it is working, after manually "highlighting" the view, the original colors change and no longer match. I can dig up some example code for this if needed.
Then, when it is looking somewhat good in Yosemite, it looks terrible in 10.9 Mavericks.
I've also tried setting the wantsLayer property to YES to turn the view into a CALayer-backed view. This creates other issues such as text not anti-aliasing correctly against a clear background.
My Question:
How do I display a label on top of a NSMenuItem custom view? The label's background must exactly match the view's background. Solution must work in Yosemite and Mavericks.
Example code below:
self.statusItem = [[NSStatusBar systemStatusBar]
statusItemWithLength:NSVariableStatusItemLength];
[self.statusItem setTitle:#"TEST"];
[self.statusItem setHighlightMode:YES];
[self.statusItem setEnabled:YES];
[self.statusItem setTarget:self];
NSMenu *menu = [[NSMenu alloc] init];
[menu addItemWithTitle:#"Disabled menu item" action:nil keyEquivalent:#""];
[menu addItemWithTitle:#"Enabled menu item" action:#selector(enabled) keyEquivalent:#""];
NSTextField *label = [[NSTextField alloc] initWithFrame:NSMakeRect(30, 20, 50, 20)];
label.stringValue = #"label";
label.editable = NO;
label.bordered = NO;
label.backgroundColor = [NSColor blueColor];
//label.backgroundColor = [NSColor clearColor];
PKMenuItemView *view = [[PKMenuItemView alloc] initWithFrame:NSMakeRect(0, 0, 200, 50)];
[view addSubview:label];
NSMenuItem *viewMenuItem = [[NSMenuItem alloc] init];
[viewMenuItem setView:view];
[menu addItem:viewMenuItem];
self.statusItem.menu = menu;
I've subclassed the NSView to override drawRect: and draw a colored background:
- (void)drawRect:(NSRect)dirtyRect {
[super drawRect:dirtyRect];
[[NSColor blueColor] setFill];
NSRectFill(dirtyRect);
//NSRectFillUsingOperation(dirtyRect, NSCompositeSourceOver);
}
It is surely kinda hack, but it worked for me.
Try adding an NSImageView with empty image to your custom view. Image view must be occupy the whole view.
I think I have less "hackish" solution. It's indeed caused by the new NSVisualEffectView and Vibrancy stuff in Yosemite. I learned that there are quite complex rules how views are drawn when they're subviews of NSVisualEffectView. It was discussed on WWDC 2014 in session 220 - Adopting Advanced Features of the New UI of OS X Yosemite. I recommend you to watch this session video to get comprehensive explanation.
Shortly, it seems that your problem may be caused by colors you use. There are two new system colors - [NSColor labelColor] and [NSColor secondaryLabelColor]. These two are automatically adjusted when drawn inside NSVisualEffectView. Also, your custom view should support Vibrancy effect. This is done by overriding - (BOOL)allowsVibrancy method and returning YES.
Please check the session video mentioned above or download session slides in PDF to get precise information. This stuff is discussed from slide 124 in PDF and near the middle of the video.
Unfortunately there are currently several problems in Yosemite. As Matthes already mentioned, you can use labelColor() and secondaryLabelColor(). Using those colors do not cause the label to draw the strange background you are seeing.
However, labelColor() only works fine for VibrantDark because there the label color is white when a NSMenuItem is both highlighted and when not highlighted. With VibrantLight the labelColor is black and is therefore very difficult to read on on top of the blue highlight.
For the highlight color of the custom view of your NSMenuItem one might think that you should use selectedMenuItemColor() given its name. The problem with this is that the color doesn't actually match the menu highlight color that you see in NSMenuItems without a custom view. The color is completely wrong for both VibrantLight and VibrantDark.
Tl;dr: So how can you create a custom NSMenuItem that uses the exact same text color and highlight color? You can't. You should use labelColor() and selectedMenuItemColor() but the former only works correctly for VibrantDark, and the latter doesn't match at all.
I really hope I am wrong because I am trying to achieve the same thing :(
Edit: Here is an example project if people want to have a look.
Response from a Apple Developer Technical Support ticket I opened in 2015:
Re: DTS Auto-Ack - Vibrant background and highlighting of Custom View NSMenuItems
This is a difficult problem to tackle, especially in light of the fact that menu selection drawing was not intended for menu items with custom views, and menu selection drawing (colors, etc.) may change in the future. This is why we ask you to file bug reports so that menu selection will be honored with custom views, if asked for, so that future changes to OS X won’t require developers to continually maintain their code to match future color appearances.
The “Application Menu and Pop-up List Programming Topics” says this:
Views in Menu Items -
“A menu item with a view does not draw its title, state, font, or other standard drawing attributes, and assigns drawing responsibility entirely to the view. Keyboard equivalents and type-select continue to use the key equivalent and title as normal.”
Since all drawing is up to the developer, custom views in menu items aren’t necessarily supposed to draw “selected”.
The APIs to obtain the right selection color is obviously not doing what it’s supposed to, hence the request to file a bug report. I wish we could offer more concrete solutions to the problem but a workaround offered today may not hold up tomorrow and we don’t want to set a bad precedent on workarounds that are risky. Apple apps have access to lower level private APIs that achieve their results. We cannot offer you these solutions as they are private.
If selectedMenuItemColor() does not match the menu highlight color with Vibrant light and dark, that’s a bug to be filed and to be fixed.
Lastly, Apple recommends to use NSMenuItem’s APIs as much as possible to achieve what you want in menus. The screenshots you included can likely be done without applying custom views.
I've just discovered that +[NSColor keyboardFocusIndicatorColor] is the right color (on El Capitan at least), whereas the expected selectedMenuItemColor is by far too dark.
Per AppKit engineers at WWDC, this doesn't really work with NSMenuItem. I added that answer to this question as well.
They suggested to instead use an NSPopover to create a faux-NSMenu attached to an NSStatusItem menu bar helper.
Using code similar to the below results in vibrant background selection:
override func viewDidLoad() {
super.viewDidLoad()
let visualEffectView = NSVisualEffectView()
visualEffectView.material = .selection
// .menu or .popover for the non-selected background.
visualEffectView.state = .active
visualEffectView.blendingMode = .behindWindow
visualEffectView.isEmphasized = true
let label = NSTextField(labelWithString: "Hello, world!")
label.cell?.backgroundStyle = .emphasized
visualEffectView.addSubview(label)
visualEffectView.frame = view.bounds
label.setFrameOrigin(.zero)
view.addSubview(visualEffectView)
}
At the WWDC 2019 AppKit Lab I worked through this issue with engineers from the AppKit team.
They were surprised that it did not work by default, and encouraged me to file (more) radars:
FB6143574 - Expose private API for NSMenuItem _viewHandlesEvents
They were aware of a private API _viewHandlesEvents on NSMenuItem.
// VibrantMenuBar-Bridging-Header.h
#import <AppKit/AppKit.h>
#interface NSMenuItem ()
#property (setter=_setViewHandlesEvents:) BOOL _viewHandlesEvents;
#end
Set viewHandlesEvents to false and the background of the custom view in the NSMenuItem will be selected and appear (somewhat) as expected.
There are still issues with how labels and other subviews react to the selection. Text View text is not properly changing color.
let menuItem = NSMenuItem(title: "", action: nil, keyEquivalent: "")
menuItem.view = label
menuItem._viewHandlesEvents = false
There are some other references to _viewHandlesEvents on the internet:
How to flash a custom NSMenuItem view after selection?
I tried several solutions from SO for this problem but none of them worked for me. I created a new iOS7 project with one simple view. I tried setting
View controller-based status bar appearance to NO
and in AppDelegate:
[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent animated:NO];
However this removes the status bar completely.
Without the View controller-based status bar appearance option, Regardless what I set for Status bar style in the plist file, the status bar text is still black. I need it to be white for the entire application. Is this possible?
I am on latest xcode version.
did you try it without "Animated:No" ?
Go to Info tab of the project target, Add Row:
UIViewControllerBasedStatusBarAppearance, set value NO
Then in appdelegate.m
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
[application setStatusBarStyle:UIStatusBarStyleLightContent];
}
This should set it application wide.
The Accepted answer seemed to work sometimes. I found out that the UIViewController can change the status bar style also. To get around this and always work, cause I didn't need the UIViewControllers controlling the status bar, I had to set UIViewControllerBasedStatusBarAppearance to NO in my Info.plist
Use needsStatusBarAppearanceUpdate to update status bar in viewDidLoad: method of view controller
[self setNeedsStatusBarAppearanceUpdate];
Now add below method into view controller:
- (UIStatusBarStyle) preferredStatusBarStyle {
return UIStatusBarStyleLightContent;
}
I would go with Logan's answer. As of iOS 9, UIApplication's setStatusBarStyle: method is deprecated anyway, so you'll want to start moving away from using that. The preferred method, now is to implement preferredStatusBarStyle within your ViewController like Logan has described.
My PhoneGap application was messed up on iOS 7, like apparently most are at first - the status bar was clear & the text was on top of (overlapping) my app's HTML-based navigation bar. I fixed that by:
In [app name] info.plist:
View controller-based status bar : NO
Status bar style : UIStatusBarStyleLightContent
In MainViewController.m underneath - (void)viewWillAppear:(BOOL)animated is:
self.view.frame = [[UIScreen mainScreen] applicationFrame];
[super viewWillAppear:animated];
NSArray *vComp = [[UIDevice currentDevice].systemVersion
componentsSeparatedByString:#"."];
if ([[vComp objectAtIndex:0] intValue] >= 7) { // iOS 7 or above
CGRect oldBounds = [self.view bounds];
/* Changing the -20 to 0 takes away the black bar
at the top, making the status bar text overlap
my content again... positive 20 of course makes
my content cut off by 20px at the top, so obviously
this is the cause of the problem */
CGRect newBounds = CGRectOffset(oldBounds, 0, -20);
[self.view setBounds:newBounds];
}
I won't bother taking an image of the MainViewController.xib file's settings pane because I'm pretty sure they're made irrelevant by what I've set in info.plist? Let me know if I'm wrong about that.
My app supports rotation as well, in case that matters. And I'm using Cordova 2.1.0.
QUESTION
My HTML code is being cut off by 20px at the bottom because of what I added when trying to get iOS 7's status bar to display properly. If I'm at the bottom of the page in the app & I drag my finger to scroll down further, I can actually see the bottom of my page, but when I lift my finger it's still cut off by 20px (let me know if that makes no sense). What's wrong here? And how do I fix it? In iOS 6 and below, this is NOT an issue - everything is perfect.
Thanks!
https://stackoverflow.com/a/19188984/706751
This is the best solution for people using PhoneGap who experience the iOS 7 Status Bar issue. If other solutions clip your content or don't do well with rotation, this is probably going to work for you!
Didn't have this issue at all until I began adapting my app for iOS 6. Whenever I return from a modal segue (with dismissViewControllerAnimated:completion:), my main view is shifted up by about the status bar's height worth of offset (and is subsequently behind the status bar).
The only workaround I've found is to add:
self.navigationController.view.frame = CGRectMake(0, 20, 320, 460);
self.view.frame = CGRectMake(0, 0, 320, 416);
to my dismissViewControllerAnimated:completion method (those values are for an iPhone < 5 and are just for explanation). But this doesn't really solve the problem, because when I go to present the next modal view controller, the presented view is then shifted up by about the status bar's height worth of offset.
No idea how this issue arose. My suspicion is that, somewhere in the segue, one of the navigation controllers loses track of the status bar's existence (linked to the new status bar, in some way?).
EDIT:
a screenshot of the main view, post-modal dismissal. [Note: 20px whitespace on the bottom]
Resolved the issue. My custom navigationController's supportedInterfaceOrientations was returning UIInterfaceOrientationPortrait, rather than UIInterfaceOrientationMaskPortrait.
Your answer didn't work for me either but I found this solution by Mike Foster that did:
http://fostah.com/ios/2012/09/27/ios6-orientation-handling.html
His steps are:
add the applications supportedInterfaceOrientation and have it return UIInterfaceOrientationMaskAll (or in my case I used AllButUpsideDown)
In your rootViewController implement shouldAutorotate and have it return NO
DO NOT implement supportedInterfaceOrientations in your rootViewController (this seems to be the step that was causing problems with the status bar for me)
In the viewController that should be landscape implement shouldAutorotate to return NO and supportedInterfaceOrientations to return UIInterfaceOrientationMaskLandscape
Hopefully that helps a few other people.
This answer didn't work for me, even though I have the same structure with a custom navigationController as the rootViewController. In my app, I want it in portrait for all VCs except for my modals, which will be UIInterfaceOrientationMaskAll.
What did work was a variation on your workaround, except it will account for iPhone 4 and iPhone 5 screen sizes and the height of the navBar:
[yourParentVC dismissViewControllerAnimated:NO completion:^{
[yourParentVC.view setFrame:CGRectMake(0, 0, [UIScreen mainScreen].applicationFrame.size.width, [UIScreen mainScreen].applicationFrame.size.height-44)];
//your other completion code
}];
+1 for asking this question...not happy how much work it's been accounting for all the deprecations in iOS 6, so every little bit helps.
I am adding a dummy ScrollView to my app to detect a user click on the status bar, to performa an event in my program.. I am creating it in the ViewDidLoad:
//Dummy Scroll is for the tap on status bar to work
UIScrollView *dummyScrollView = [[UIScrollView alloc] init];
dummyScrollView.delegate = self;
[[self view ] addSubview:dummyScrollView];
[[self view] sendSubviewToBack:dummyScrollView];
I then implement :
- (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView
{
NSLog(#"scrollViewShouldScrollToTop");
.
.
}
Under all previous versions of IOS this has worked beautifully and flawlessly, yet under iOS 6 the scrollViewShouldScrollToTop never gets called. Is this a bug?? The API says this should still be available as part of the delegate in iOS6, yet under iOS6 on both device and simulator it never executes... Anyone have any idea what is going on?
Still no other TableView or ScrollView, but there is a MAPVIEW?? But the MapView doesn't have a shouldScrollToTop that I can find to set to NO.. so I am still beyond confused why this stopped working under iOS 6...
Is there any chance that the UIScrollView you're creating isn't somehow the only UIScrollView in your view hierarchy? It looks like in iOS6, if you have more than a single UIScrollView in your view hierarchy, only one should have scrollsToTop = YES. This is the one that'll have its scrollViewShouldScrollToTop method called.
My problem was similar in that I had a very basic UITableView that would no longer autoscroll to the top when the status bar was tapped. I finally remembered that one of the cells in my tableView uses a UIWebView, and that the cell's webView.scrollView was (correctly, now in iOS6) hijacking the call to scrollViewShouldScrollToTop that, before iOS6, was being made on my tableView.
After setting the tableViewCell's "scrollsToTop = NO", the status bar autoscroll once again worked as it did before. Here's more-or-less how the code looks:
myCustomCellWithAWebView.webView.scrollView.scrollsToTop = NO;
Hope this helps!
On iOS 6, only tap the part above scrollview of status bar can fire scrollsToTop event.
And, that scrollView can't be hidden or 0 alpha.
But it can be covered. or clear background color.
So on iOS 6, you need
dummyScrollView.frame = self.view.bounds;
dummyScrollView.backgroundColor = [UIColor clearColor];