Resize views when menubar autohides/appear in fullscreen mode - objective-c

I'm working on an OSX app that supports a fullscreen mode.
The window is generated from a nib file but everything else is handled programmatically.
When I goes in fullscreen mode, my views resize properly but when the menu bar appear/disappear, setFrame don't get called for either the contentView or my own views. I'd to be notified
Is there a delegate to implement to catch those notifications? Or do I have to subclass NSWindow and find out how Safari handles its menu bar by reversing it?

It would be helpful to see some code, how exactly "your views resize properly".
But next info might help:
When a window goes fullscreen it occupies entire screen after the end of the fullscreen animation. The main menu bar shows over the window ("above" in sense of z-ordering). So when main menu bar shows/hides frame of your window and content view don't change.
Also note, that -[NSScreen visibleFrame] returns unoccupied frame. And it will not return whole screen frame until the end of the fullscreen animation.

After some researches, I could at least get ride of the dirty gray bar at the top of the screen by subclassing the window's content view and add the following code to the setFrame method, before call super:
//isFullscreen
if(([self.window styleMask] & NSFullScreenWindowMask) == NSFullScreenWindowMask)
{
frameRect.size.height = self.window.frame.size.height;
frameRect.size.width = self.window.frame.size.width;
}
The window get resized to the screen size before setFrame get called, so we can use its size to update frameRect to window's size.

Related

Hiding Nav Bar moves view "up"

The usual story -- I'm making an iOS 5/6 app run under iOS 7 and the navigation bar behavior change is causing a problem.
The app already worked like the iOS 7 default with a full-screen view and a translucent nav bar "over" of the view. The problem is that hiding/un-hiding the nav bar causes different behavior in iOS 7. On iOS 5/6 hiding/un-hiding the nav bar does not change the view. On iOS 7, hiding the bar visually moves the view up leaving a blank bar at the bottom of the screen and un-hiding the bar moves the view back down to occupy the full screen (with the nav bar on top, of course).
I need to continue to support iOS 5 so I don't use auto layout, but I do use the full screen.
I have a view in which I'm viewing a zoomable image -- so the view controller has a fullscreen view containing a scrollView which contains an imageView.
The status bar is always hidden.
I get to the view controller via a navigation controller so there is a (black, translucent) navigation bar which lies over the top of my fullscreen view/scrollView/imageView.
After a brief delay some overlaying labels fade and the navigation bar is hidden
A single tap restores the overlay labels and un-hides the navigation bar.
This works on iOS 5/6 -- the navigation bar slides off the top of the screen uncovering the top of the view/image.
On iOS 7, when the navigation bar slides off the top of the screen the entire view visually moves up a corresponding amount (i.e. 44 points) leaving a black bar at the bottom of the screen. I can see this by setting a background color on the top-level view and resizing the scrollview enough to see the background; the top of the view does indeed move offscreen and the background color is not drawn over the bottom (44 points) of the screen.
BUT, self.view.frame doesn't change and remains at {0, 0} 320 x height.
When I single-tap to restore the overlay info and navigation bar the view moves back down to occupy the full screen and the translucent nav bar is over the top of the view/image.
Nothing I've tried changes the behavior:
Changing the IB view controller layout controls (Under top bars, Under bottom bars, Adjust scroll view insets). Building for 5.1, 6.1, and 7.0 all produce the same result when run under 7.0.
self.edgesForExtendedLayout = UIRectEdgeNone
does nothing. Using the layout delta values doesn't do anything. In IB the view looks the same when "viewed as" iOS 7 and iOS 6 and earlier. I print out a lot of debug info but nothing about the view (or scroll view) seems to change when the view moves "off screen".
The code that shows the overlay info (run when the view is first shown and on single-taps) is:
- (void) showOverlayInfo {
self.navigationController.navigationBar.barStyle = UIBarStyleBlack;
[[[self navigationController] navigationBar] setTranslucent:YES];
[[self navigationController] setNavigationBarHidden:NO animated:NO];
overlayInfoHidden = NO;
overlayInfoFading = NO;
self.infoButton.hidden = NO;
self.infoButton.alpha = 1;
self.descriptionLabel.hidden = NO;
self.descriptionLabel.alpha = 1;
}
The code that hides the overlay info is:
- (void) hideOverlayInfo {
overlayInfoHidden = YES;
overlayInfoFading = NO;
self.infoButton.hidden = YES;
self.descriptionLabel.hidden = YES;
[[self navigationController] setNavigationBarHidden:YES animated:YES];
}
So can anybody tell me what (presumably simple) thing I'm missing?
I finally found my problem.
The key fact is that the image-viewer view controller was in a UIPageViewController,
so what I was looking at and experimenting with was really "inside" another view controller.
Although I had disabled the view controller setting Adjust Scroll View Insets for the image viewer VC, I hadn't done it for the containing VC that created the UIPageViewController and the UIPageViewController presents the pages in some subclass of a UIScrollView. When I changed them for the parent VC, the problem vanished.
So I think the moral of the story is to:
Think about the problem more globally when local doesn't work because maybe you're missing some important context.
If you don't want to use the iOS 7 behavior, change the settings for every single view controller you have!

How to position progress spinner inside the title bar of a Mac application

I am trying to place a progress spinner at the right side of the the title bar of the window of my Mac OS X application, but I can't do that with the Interface Builder, as it doesn't let me drag the view inside it.
So, I tried to put it in the title bar programmatically, with the following code inside the applicationDidFinishLaunching method in AppDelegate.m:
loadingSpinner = [[NSProgressIndicator alloc] init];
[loadingSpinner setFrame:NSMakeRect(485, 0, 17, 17)];
[loadingSpinner setStyle:NSProgressIndicatorSpinningStyle];
NSView *titleBarView = [[_window standardWindowButton:NSWindowCloseButton] superview];
[titleBarView addSubview:loadingSpinner];
However, this is putting my progress spinner view at the bottom of the window instead of the title bar. It appears NSMakeRect() is positioning it relative to the bottom of the window, not the top.
If I change the second parameter of NSMakeRect (y position) to something like 370, it puts the loading spinner in the place I want it to be, but obviously when I resize the window vertically, it brings the progress spinner together to the bottom.
I've never seen something like this before. How can I fix that?
P.S.: Also, I don't know if there's a "more right" way to get the title bar view. As you can see, I'm using the superview of the close button view to get it, which seems a bit "dirty".
Randall Brown has some code to put a button in an NSWindow's title bar on his blog. You were on the right track. The superview of the close button is the entire window including the title bar. Its a little less hacky to get it with [[_window contentView] superview].

Rotating UITabBarController Icon

I have an UITabBar in my application. One of the tab bar icons looks like a loading symbol. When the user presses the loading button I want the icon to spin/rotate until the loading is done. Should I use UIImageView to animate or something else? How should I make this happen?
Jacos, unfortunately you cannot do that with the UITabBarController and manipulate the tabBarController's tabBar properties. My best bet would be that you use a UIToolBar and assign a black color and make it appear like a tabBar and have buttons added in them as a subView so that they look like tabBarItems.
Its much more customizable, and you can even provide a scrolling experience and add more buttons to it.
I know this question is 4 years old but I had the same problem and managed to fix it by reading the tutorial in here:
https://medium.com/#werry_paxman/bring-your-uitabbar-to-life-animating-uitabbaritem-images-with-swift-and-coregraphics-d3be75eb8d4d#.bjfpbdnut
The main point is to get the view for desired UITabBarItem and the get the UIImageView from it in viewDidLoad:
UIView *plusView = self.tabBar.subviews[1];
self.plusImageView = plusView.subviews.firstObject;
self.plusImageView.contentMode = UIViewContentModeCenter;
Then in didSelectItem method you can do this:
[UIView animateWithDuration:0.4 animations:^{
[self.plusImageView setTransform:CGAffineTransformMakeRotation(M_PI/4)];
}];
My code only rotate the image view for 45 degrees but you can change as you wish.
I guess you could change the UITabBarItem's icon on a timer, but that seems pretty kludgey. You would have to pre-render each frame of your "loading" icon rather than rotate an ImageView.
Another hackey solution would be to add your ImageView to the UIWindow and move it on top of the TabBarController's TabBar (adding it to the TabBar itself is asking for trouble).
You shouldn't try to animate the actual UIImageView within the UITabBarController. I would take this approach:
Set the image for the relevant tab to nil or a blank image.
Create a UIActivityIndicatorView and add it over the tab bar. Position it over the correct tab.
[self.tabBarController.tabBar addSubview:activityIndicatorView];
When your loading task has completed, restore the normal image to the tab and remove the activityIndicator from the tab bar.

Showing an image on my window's drag area... how can I make a click on the image still drag the window?

I'm using an NSImageView to display an image on an NSWindow. The image will be on top of the area where the user can normally drag the window.
The window is styled in such a way that it's not easily apparent that you can drag the window... I thus need this little image to indicate that you can in fact drag the window.
Unfortunately, I can't figure out how to make a click on the image drag the window! It needs this. Dragging anywhere else in the window's title area works fine.
How can I make clicking and holding the image drag the entire window?
Bonus points if you can tell me how to give the mouse a "drag icon" cursor while hovered on this image.
I think the easiest way is to subclass NSImageView and return YES to mouseDownCanMoveWindow (which it inherits from NSView).
-(BOOL)mouseDownCanMoveWindow {
return YES;
}
You can set a new cursor when the mouse enters the image view by overriding resetCursorRects like this in the NSImageView subclass (I don't know what you mean by "drag icon" cursor, so this example uses the pointing hand cursor:
- (void)resetCursorRects {
[self addCursorRect:self.bounds cursor:[NSCursor pointingHandCursor]];
}
NSImageViews have their own mouse handling. To change the way that view behaves, you will have to subclass, either NSView or NSImageView.

statusbar and superview frame size

I've a typical View based application (mainwindow.xib + viewControler.xib) in which I have HIDDEN the status in the AppDelegate file like this...
[[UIApplication sharedApplication] setStatusBarHidden:YES];
then I create various subviews on the mainview (mainly UIWebViews) that are full screen positioned at 0,0. Then I created a button that enables you to toggle the view of the statusbar. My problem begins when I show the statusbar and the change the orientation of the screen, the views don't have the full dimension of window and are starting just after the statusbar (at y:20 instead of y:0) and their height is reduced by 20pixel and if I removed the status I can see the blank space.
So the question is this...how can the code ignore the presence of the statusbar and always position new or re-oriented views into 0,0, instead of 0,20 (if the statusbar is shown). I think that the problem is not lying on my main view but in my MainWindow.xib, but I cannot find any solution.
UPDATE1: I am also checking for a solution in the autoresizingmask property of the subviews.
Thanx in advance...
I finally found the solution and I can fall to sleep in peace.
The solution lies in the property wantsFullScreenLayout and you must set it to YES.
So visit your appDelegate that adds your mainview (superview) and add this line:
viewController.wantsFullScreenLayout = YES;
before this line
[window addSubview:viewController.view];
on didFinishLaunchingWithOptions of your AppDelegate.m file.
That way your superview ALWAYS uses fullscreen resolution and doesn't resize if the statusbar is present!