How to retrieve available height considering other UIElement's height? - objective-c

How can i get the available height?
I tried:
NSLog(#"%f", [self bounds].size.height);
NSLog(#"%f", [self frame].size.height);
NSLog(#"%f", [[UIScreen mainScreen] bounds].size.height);
I get always the screen's height.
But the actual height is smaller. With Informationbar on the top + Nav-Bar, the height is smaller.
EDIT:
I need to retrieve the height programmatically. Thats if there is a TabBar and my View is not always in a NavBar-Controller. Maybe there is no NavBar.

Navigation bar has a predefined height of 44 which you can never change. And by information bar, i think u mean the status bar which has a fixed height of 20. Total height of iPhone screen is 480. U do the calculations... :)
However, if you want the height of such a screen then in the nib always have status bar and navigation bar simulated and then have all the UI elements for that. After that, when you'll do
self.view.frame.size.height
you'll get the height of your view

self.view.frame.size.height;
OR
float theHeight = // one of the methods you posted
theHeight -= 44; // for nav bar
theHeight -= 20; // for status bar

Related

IOS center bottom position view

I do the following to a loading animation, to place it at the bottom center of the screen.
CGPoint bottomCenter = CGPointMake((self.imageView.bounds.size.width / 2), (self.imageView.bounds.size.height * 0.8));
self.activityView.center = bottomCenter;
(imageView is the full screen splash image)
If the orientation is portrait, it is positioned perfectly, however turning on its side, in landscape or upside down portrait and the animation ends up miles away :S
Does anyone know the correct way to position this loading animation, its for the splash screen.
use UIDeviceOrientationIsLandscape(deviceOrientation) and UIDeviceOrientationIsPortrait(deviceOrientation) instead of deviceOrientation==X
First, look at tkanzakic's answer.
Second, don't use screen bounds, orientate the view by its parent view. If you put your view to the bottom of your parent view and you set the autoresizing mask correctly, everything will be done automatically - no need to check device orientation.
Try this code
CGRect screenBounds = [[UIScreen mainScreen] bounds];
CGPoint bottomCenter;
if (deviceOrientation == 1) {
bottomCenter = CGPointMake((screenBounds.size.width / 2), (screenBounds.size.height * 0.8));
}
else if (deviceOrientation == 4) {
bottomCenter = CGPointMake((screenBounds.size.width / 2), (screenBounds.size.height * 0.8));
}
In landscape mode you are taking wrong width and height
In landscape mode width and height also change.

NSRect Size to Fill Screen

How do i get the current size of the screen no matter the resolution change in xcode so that i can adjust my NSRect size to be maximized or take up the screen according to the resolution ? What do I need to add? Would it be something to the NSWindow?
NSRect panelRect = [[self window] frame];
panelRect.size.height = _HEIGHT;
panelRect.size.width = _WIDTH;
panelRect.origin.x = 0;
panelRect.origin.y = 0;
[[self window] setFrame:panelRect display:NO];
Thanks!
You can use CGDisplayBounds, which returns a CGRect containing the screen's bounds (origin and size) in global coordinates.
You can use CGDisplayRegisterReconfigurationCallback to be notified when a display configuration changes, which includes when its resolution is changed.
Quartz Display Services Reference
Have you tried using [[NSScreen mainScreen] frame]? If you want to exclude the menubar, you can subtract the menubar height from the NSRect's height. (It's around 20 pixels)
Edit: If you want your window to be resized from the start, you can put the method above in your controller's awakeFromNib and use NSWindow's setFrame:display: to resize it.

Synchronised scrolling between two instances of NSScrollView

I have two instances of NSScrollView both presenting a view on the same content. The second scroll view however has a scaled down version of the document view presented in the first scroll view. Both width and height can be individually scaled and the original width - height constraints can be lost, but this is of no importance.
I have the synchronised scrolling working, even taking into account that the second scroll view needs to align its scrolling behaviour based on the scaling. There's one little snag I've been pulling my hairs out over:
As both views happily scroll along the smaller view needs to slowly catch up with the larger view, so that they both "arrive" at the end of their document at the same time. Right now this is not happening and the result is that the smaller view is at "end-of-document" before the larger view.
The code for synchronised scrolling is based on the example found in Apple's documentation titled "Synchronizing Scroll Views". I have adapted the synchronizedViewContentBoundsDidChange: to the following code:
- (void) synchronizedViewContentBoundsDidChange: (NSNotification *) notification {
// get the changed content view from the notification
NSClipView *changedContentView = [notification object];
// get the origin of the NSClipView of the scroll view that
// we're watching
NSPoint changedBoundsOrigin = [changedContentView documentVisibleRect].origin;;
// get our current origin
NSPoint curOffset = [[self contentView] bounds].origin;
NSPoint newOffset = curOffset;
// scrolling is synchronized in the horizontal plane
// so only modify the x component of the offset
// "scale" variable will correct for difference in size between views
NSSize ownSize = [[self documentView] frame].size;
NSSize otherSize = [[[self synchronizedScrollView] documentView] frame].size;
float scale = otherSize.width / ownSize.width;
newOffset.x = floor(changedBoundsOrigin.x / scale);
// if our synced position is different from our current
// position, reposition our content view
if (!NSEqualPoints(curOffset, changedBoundsOrigin)) {
// note that a scroll view watching this one will
// get notified here
[[self contentView] scrollToPoint:newOffset];
// we have to tell the NSScrollView to update its
// scrollers
[self reflectScrolledClipView:[self contentView]];
}
}
How would I need to change that code so that the required effect (both scroll bars arriving at an end of document) is achieved?
EDIT: Some clarification as it was confusing when I read it back myself: The smaller view needs to slow down when scrolling the first view reaches the end. This would probably mean re-evaluating that scaling factor... but how?
EDIT 2: I changed the method based on Alex's suggestion:
NSScroller *myScroll = [self horizontalScroller];
NSScroller *otherScroll = [[self synchronizedScrollView] horizontalScroller];
//[otherScroll setFloatValue: [myScroll floatValue]];
NSLog(#"My scroller value: %f", [myScroll floatValue]);
NSLog(#"Other scroller value: %f", [otherScroll floatValue]);
// Get the changed content view from the notification.
NSClipView *changedContentView = [notification object];
// Get the origin of the NSClipView of the scroll view that we're watching.
NSPoint changedBoundsOrigin = [changedContentView documentVisibleRect].origin;;
// Get our current origin.
NSPoint curOffset = [[self contentView] bounds].origin;
NSPoint newOffset = curOffset;
// Scrolling is synchronized in the horizontal plane so only modify the x component of the offset.
NSSize ownSize = [[self documentView] frame].size;
newOffset.x = floor(ownSize.width * [otherScroll floatValue]);
// If our synced position is different from our current position, reposition our content view.
if (!NSEqualPoints(curOffset, changedBoundsOrigin)) {
// Note that a scroll view watching this one will get notified here.
[[self contentView] scrollToPoint: newOffset];
// We have to tell the NSScrollView to update its scrollers.
[self reflectScrolledClipView:[self contentView]];
}
Using this method the smaller view is "overtaken" by the larger view when both scrollers reach a value of 0.7, which is not good. The larger view then scrolls past its end of document.
I think you might be approaching this in the wrong way. I think you should be getting a percentage of how far down each scroll be is scrolled in relation to itself and apply that to the other view. One example of how this could be done is this way using NSScroller's -floatValue:
NSScroller *myScroll = [self verticalScroller];
NSScroller *otherScroll = [otherScrollView verticalScroller];
[myScroll setFloatValue:otherScroll.floatValue];
I finally figured it out. The answer from Alex was a good hint but not the full solution as just setting the float value of a scroller doesn't do anything. That value needs translation to specific coordinates to which the scroll view needs to scroll its contents.
However, due to differences in size of the scrolled document view, you cannot just simply use this value, as the scaled down view will be overtaken by the "normal" view at some point. This will cause the normal view to scroll past its end of document.
The second part of the solution was to make the normal sized view wait with scrolling until the scaled down view has scrolled its own width.
The code:
// Scrolling is synchronized in the horizontal plane so only modify the x component of the offset.
NSSize ownSize = [[self documentView] frame].size;
newOffset.x = MAX(floor(ownSize.width * [otherScroll floatValue] - [self frame].size.width),0);
The waiting is achieved by subtracting the width of the scroll view from the width times the value of the scroller. When the scaled down version is still traversing its first scroll view width of pixels, this calculation will result in a negative offset. Using MAX will prevent strange effects and the original view will quietly wait until the value turns positive and then start its own scrolling. This solution also works when the user resizes the app window.

Center a MacGLView in a Window

I have an cocos2D app that runs in 4/3 ratio and I want to enter fullscreen mode resizing the view to maintain the aspect ratio without showing black bars at screen sides. So, when the app enters fullscreen, I do this:
NSRect aFrame=[[NSScreen mainScreen] frame];
[glView_ setFrameSize:NSMakeSize(aFrame.size.width,aFrame.size.height*1.2)];
This way I got fullscreen wide but (as I wanted) the ratio is untouched. My problem now is that the glview is not centered on screen. It extends from left bottom point so I got my game unevenly clipped (all clipping is done at top). I've trying to use [glview setFrameOrigin] and similar to select the visible portion of the view without success.
I just want to displace my view a certain number of pixels down so it shows the center area of whole view. Is it possible?.
Thanks in advice.
You are changing the dimensions of glView_, but not its origin.
NSRect aFrame=[[NSScreen mainScreen] frame];
CGFloat x = 0.0f;
CGFloat y = aFrame.size.height;
CGFloat width = aFrame.size.width;
CGFloat height = aFrame.size.height * 1.2f;
glView_.frame = NSRectFromCGRect((CGRectMake(x, y/2 - height / 2, width, height));

Scrollable UINavigationBar similar to Mobile Safari

My application uses a UINavigationController and the final view (detail view) lets you view an external website within the application using a UIWebView.
I'd like to free up some additional screen real estate when the user is viewing a webpage and wanted to emulate how Safari on iPhone works where their URL bar at the top scrolls up and off the screen when you're viewing content in the UIWebView that's below the fold.
Anyone have ideas on how to achieve this? If I set the navigationBarHidden property and roll my own custom bar at the top and set it and a UIWebView within a UIScrollView then there are scrolling issues in the UIWebView as it doesn't play nicely with other scrollable views.
Based on #Brian suggestion I made this code:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGFloat height = navigationBar.frame.size.height;
CGFloat y = scrollView.bounds.origin.y;
if (y <= 0) {
CGRect frame = navigationBar.frame;
frame.origin.y = 0;
navigationBar.frame = frame;
} else if (tableView.contentSize.height > tableView.frame.size.height) {
CGFloat diff = height - y;
CGRect frame = navigationBar.frame;
frame.origin.y = -y;
navigationBar.frame = frame;
CGFloat origin = 0;
CGFloat h = height; // height of the tableHeaderView
if (diff > 0) {
origin = diff;
h = y;
}
frame = tableView.frame;
frame.origin.y = origin;
frame.size.height = tableView.superview.frame.size.height - origin;
tableView.frame = frame;
CGRect f = CGRectMake(0, 0, tableView.frame.size.width, h);
UILabel* label = [[UILabel alloc] initWithFrame:f];
tableView.tableHeaderView = label;
[label release];
}
}
My code has a UITableView but should work with any scrollable component. If you have other components than the navigationBar and the UIScrollView subclass, you should change the way the height of the scrollable component is calculated. Something like this:
frame.size.height = tableView.superview.frame.size.height - origin - otherComponentsHeight;
I needed to add a dumb tableHeaderView to have the desired behaviour. The problem was that when scrollViewDidScroll: is called the content has an offset, but the apparience in Mobile Safari is that the content is not scrolled until the navigationBar fully disappears. I tried first changing the contentOffset.y to 0, but obviously it didn't work since all the code relies on the scrolling mechanism. So I just added a tableHeaderView whose height is exactly the scrolled offset, so the header is never really seen, and the content appears to not scroll until the navigationBar fully disappears.
If you don't add the dumb tableHeaderView, then the scrollable component appears to scroll behind the navigationBar.
With the tableHeaderView, the scrollable component is actually scrolling (as seen in the scrollbar), but since there is a tableHeaderView whose height is exactly the same than the scrolled offset, the scrollable content appears to not be scrolling until the navigationBar fully disappears:
Have a delegate for the scrolling events in the UIWebView and when you initially start scrolling the UIWebView, have the UIWebView increase in height and have it's Y position decrease at the same time while simultaneously shifting the nav bar up in the Y direction. Once the nav bar has been completely shifted out of view, stop increasing the size of the UIWebView and just allow normal scrolling to occur.
This will give the illusion of the nav bar being part of the UIWebView as it scrolls off the screen.
Also, you'll need to do the reverse when you are scrolling in the opposite direction and are reaching the top of the content of the UIWebView.
Can't give you a straight answer, but have a look at iWebKit. Maybe that provides a solution. The demo, at least, contains a "full screen" item.