bounds vs frame of a UIAlertView - objective-c

I have UIAlertView and I log it's frame and bounds using:
[self.alertView show];
NSLog(#"frame: %#", NSStringFromCGRect(self.alertView.frame));
NSLog(#"bounds: %#", NSStringFromCGRect(self.alertView.bounds));
I notice that the width and height of the frame and bounds is different. How is this possible?

From UIView's frame, bounds, center, origin, when to use what?
frame - this is the property you most often use for normal iPhone applications. most controls will be laid out relative to the "containing" control so the frame.origin will directly correspond to where the control needs to display, and frame.size will determine how big to make the control.
bounds - this property is not a positioning property, but defines the drawable area of the UIView "relative" to the frame. By default this property is usually (0, 0, width, height).
That being said, it's not surprising nor uncommon for the bounds size to be different from the frame size. Since in this case the bounds rect is smaller than the frame it simply means that only a part of the view is being drawn.
Also consider that UIAlertView view hierarchy it's much more complex than it appears and it also went through a big change with iOS 7.
To further remark this, here's a statement from the documentation
The UIAlertView class is intended to be used as-is and does not support subclassing. The view hierarchy for this class is private and must not be modified.
Which is a nice way to say: here be dragons!

Related

Identifying correct window frame size for filling background color

I am developing in Cocoa, and I am currently having problems with filling the background of a NSWindowController.
I understand that subclassing is the way forward if you want to customise your cocoa app. So I created a custom NSView named whiteView and added this view as a subview to my windowController's contentView; however, there are some issues with completely filling the background of the window. Can anyone explain how I can have the color cover the complete surface area of the window's frame pls. Thank you
These are the results that I have so far.
1) This is the window when I leave it as it is, notice the white color only having covered half of the window.
2)Here is the same window again when I adjust the window far to the right and bottom. The white screen seems to stretch enough so that it covers the elements.
This is how I create the custom view
- (void)drawRect:(NSRect)dirtyRect
{
[super drawRect:dirtyRect];
[[NSColor whiteColor] set];
NSRectFill([self bounds]);
}
And this how I achieve plaster the view onto my window.
WhiteView *whiteBackgroundView = [[WhiteView alloc] initWithFrame:self.window.frame];
[self.window.contentView addSubview:whiteBackgroundView positioned:NSWindowBelow relativeTo:self.window.contentView];
What do I need to do to correctly allow for my window's background to be fully covered in white?
First, the simple solution is to use -[NSWindow setBackgroundColor:] to just set the window's background color. No need for a view.
If you're still interested in how to fix the view-based approach, probably what's wrong is that you haven't set the autoresizing mask of the view to make it follow the changes in the window size. For example, you could do [whiteBackgroundView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable].
However, you could also set the whiteBackgroundView as the window's contentView rather than as a subview of it. The window's content view is always kept at the size necessary to fill the window's content rect. All of the other views of your window would be subviews of the white background view. In my opinion, this is better than making it a sibling that just happens to be at the back. Using relative ordering among siblings views to achieve a particular rendering order is a hack.
Finally, there's no reason to invoke super's implementation in your -drawRect: if the superclass is NSView itself. NSView doesn't do any drawing in its -drawRect:. Also, your subclass takes over full responsibility for the entire drawn contents of its bounds, so you'd overdraw whatever super had drawn, anyway. (Also, you need only fill dirtyRect rather than [self bounds].)
While you're at it, since your class fills its bounds, you should override -isOpaque to return YES for optimization.
Update: regarding the frame of the view: if it's not going to be the window's content view, then you want to set its frame to be its prospective superview's bounds. So, you should have used self.window.contentView.bounds if you wanted whiteBackgroundView to fill the content view.
More generally, if you want the content rect of a window, you would do [window contentRectForFrameRect:window.frame]. But if a view is going to be a window's content view, there's no need to set its frame to anything in particular. It will be resized automatically.
Update 2:
To transfer the view hierarchy from the original content view to the new content view (when you're making the white background view the content view):
NSArray* subviews = [self.window.contentView.subviews copy];
[subviews makeObjectsPerformSelector:#selector(removeFromSuperview)];
[whiteBackgroundView setSubviews:subviews];
[subviews release];
(Written for manual retain-release. If using ARC, just drop the -release invocation.)
Regarding the frame to use, as mentioned in the first update: keep in mind that the view's frame should be expressed in the coordinate system of its superview. So, as I said, self.window.contentView.bounds would work if you're putting the new view into the content view. The window's frame and content rect are in screen coordinates. They would be completely incorrect for positioning a view.

In Cocoa View Hierarchy what determines the subView position?

I am new to cocoa /objective-C coming from Java/C# and C/C++ . Cocoa has been giving me lots of headaches. I have read an apple's article on View hierarchy in cocoa. But still confusions.
I need to know when I add a subView to a view programatically not via interface builder. Where exactly will the view be placed relative to other subviews assuming there are other subviews in the same parent view.
In java there are layout managers, in C# there is also vertical/horizontal panel etc, so we know if I add an item/control it will be going to the right of the existing item or to the bottom of it.
So if I do as shown in the following line what exactly determines where the new subview will be placed ??
[[window contentView] addSubview:newView];
Thanks,
The frame of the view defines the rect that it occupies in its superview's coordinates, so its position will be frame.origin. That can be set either before or after you add the subview.
This is spelled out fairly clearly in the View Programming Guide.
It depends on whether you are using Autolayout or not.
If you are not, then when you create a view you call -[NSView initWithFrame:(NSRect)frame] and that frame will will define where the view appears in the superview's coordinates.
_view = [[NSTextField alloc] initWithFrame:NSMakeRect (50, 50, 100, 50)];
will make an NSTextField size 100x50 and it will be placed 50,50 pixels inside the superview.
If you are using Autolayout, then the position of a view depend entirely on what layout constraints apply to it. With Autolayout any frame that you set will be ignored. While autolayout has a steep learning curve, once you set your constraints, it (in theory) means you can ignore the layout.
The frame rectangle gives the view's size and position in the superview. The frame is at position 0,0 (x,y) with a size of 0,0 (w,h) by default. The position in the subview collection is entirely ignored except in rare cases like NSSplitView.
Cocoa doesn't automatically align any views. There is no initial layout mechanism like in .net or java.
You have to position all your views manually by setting their frames in points.
By default, the origin of a fresh initialized view is at (0,0).
AFAIK, the documentation and header file don't specify exactly the origin (x,y) the added subview will be placed. What I do after add a subview is to calculate a new origin (and if applicable) size before repositioning the subview using CGRectMake().

CGRectContainsPoint checking a view within a subview?

I am trying to check for a collision of an UIView that is in the main view, with a UILabel that is a subview of another view in the main view.
When I use CGRectContainsPoint, it does not return true. When I check the UILabel's frame, it returns values relative to the subview it's in, not it's absolute position. I figured this might be the problem.
If so, how do I specify that I want UILabel's absolute values for the frame?
You can convert coordinates between different coordinate systems using the NSView methods:
- convertRect:(NSRect) fromView:(NSView)
- convertRect:(NSRect) toView:(NSView)
If the second argument is nil, the coordinates are converted from/to window base coordinates. Similar methods exist for NSPoint and NSSize variables. One solution would be to convert all rectangles and points to window base coordinates and check for collision in those coordinates.

drawRect's aRect argument in relation to UIView's bounds

I'm working on creating my first custom UIView and learning about the semantics of the drawRect method.
I have encountered advice (advice that makes sense to me) to only draw within the scope of the CGRect that is passed in as an argument, rather than always drawing everything within the UIView's bounds:
- (void)drawRect:(CGRect)aRect {
// draw, draw, draw...
}
What I'm trying to find out now is whether there are any constraints about what relationship there is between bounds and the aRect that gets passed in. In particular, I'm wondering if aRect is guaranteed to be entirely inside bounds, or whether it may extends outside of bounds.
If some code outside of my UIView passes, for example, a very large CGRect into setNeedsDisplayInRect:(NSRect)invalidRect, will the underlying code just blindly pass the same CGRect into my drawRect method, or does it do some sort of intersection and always pass in a sensible rectangle?
I haven't found an answer to this in any documentation. Is this something I shouldn't even worry about? Or should I always intersect bounds and aRect on my own?
From the View Programming Guide:
Before calling your view’s drawRect: method, UIKit configures the basic drawing environment for your view. Specifically, it creates a graphics context and adjusts the coordinate system and clipping region to match the coordinate system and visible bounds of your view.
You won't be asked to draw outside your view. Even if you were, the clip rect should be set such that the drawing would have no effect.

Anything like layout manager in Java for iOS?

Guys, I am a newbee for iOS.
I need to create dynamic layout since the GUI will be generated according to the data.
I checked the UIView references, it seems the standard way to add subview is like:
CGRect rect = CGRectMake(0, 0, width, height);
UILabel *label = [[UILabel alloc] initWithFrame: rect];
[someView addSubView: label];
But, maybe I can't be sure that the width and the height. In Java, container use layout manager to automatically deal with the width and height based on some rules. In iOS, can I use something like layout manager in Java?
Thanks.
Any clue will be OK.
You can do this in iOS, although it is not one-to-one with Java layouts. The get the idea of what is possible, use the Size Inspector in Interface Builder. Anything that is done there, such as allowing an item to grow horizontally or stay the same distance from the top, can be done programmatically. If further customization is needed, you can override event hooks in your view or controller, such as UIView's -layoutSubviews method.
iOS 9 provides UIStackView class which in essence is a layout manager:
The UIStackView class provides a streamlined interface for laying out
a collection of views in either a column or a row. Stack views let you
leverage the power of Auto Layout, creating user interfaces that can
dynamically adapt to the device’s orientation, screen size, and any
changes in the available space. The stack view manages the layout of
all the views in its arrangedSubviews property. These views are
arranged along the stack view’s axis, based on their order in the
arrangedSubviews array. The exact layout varies depending on the stack
view’s axis, distribution, alignment, spacing, and other properties.
Note that it's not applicable if you're supporting iOS 8 which is still pretty actual at the moment.