Get dimensions of UIView Class for CGRects? - ios

I am currently working on an app that draws a series of rectangles (CGRect) on a view and sizes them based on the size of the UIView. This code is contain in a class file that inherits UIView (rectangle.h/rectangle.m). I cannot for some reason use self.view.bounds.height or self.view.bounds.width to get the values I need. I am using the overridden method "drawrect" that is built into the class. How can I get the view size? or if thats not possible, how can I implement this?

Use
self.view.bounds.size.width
self.view.bounds.size.height
or
if self class is itself a UIView
self.bounds.size.width
self.bounds.size.height

You can get the view size using the following :
CGSize viewSize = self.view.frame.size;
NSLog(#"View Size : %#",NSStringFromCGSize(self.view.frame.size));

Related

Display UIView on scaled CGRect iOS

I am using the AVMetaData API to extract the bounds of an AVMetadataFaceObject. When printed to the console, this CGRect has the following values: bounds={0.2,0.3 0.4x0.5}. I'm having a fair amount of trouble mapping this to a UIView that displays over the face. I can hard-code in some conversion values for my specific screen to get it to crudely be in the right spot, but I would like a solution that displays a UIView over the face shown in my previewView on any screen size.
Does anyone know how to map these to the frame of an on-screen UIView based upon the size of a previewView?
You should be able to take the size of the capture area, let's call that "captureSize" and then do this:
CGRect viewRect;
viewRect.origin.x = bounds.origin.x * captureSize.width;
viewRect.origin.y = bounds.origin.y * captureSize.height;
viewRect.size.width = bounds.size.width * captureSize.width;
viewRect.size.height = bounds.size.height * captureSize.height;
Now, this all depends how your previewView is setup and whether or not it has any content scaling, etc, but should give you a sense of the conversion.

self.view.frame.width returns 0 in Custom Keyboard View Controller

When I try to get the frame width with the following code, it simply returns 0:
var deviceWidth = self.view.frame.width
I am assuming that this has something to do with the restrictions of the UIInputViewController class, which is the superclass of all custom keyboards
I found out that you can use the following code instead:
UIScreen.mainScreen().bounds.width
Or simply:
view.bounds.width
this is right solution
-(void)viewDidLayoutSubviews{
CGRect keyboardRect = self.inputView.bounds;
}
I don't know why, but it returns 0 until u set any view as subview. So I solwed this problem in such way: in viewDidLoad method I'm innitialazing all neccessary thing i need for drawing and one extra view:
//initialize all you need for drawing
var extraView = UIView()
self.view.addSubview(extraView)
//now you can get real size
Now you can start drawing in viewDidAppearmethod, where you can get real size now. This is my solution of this problem.

How to do a custom layout of a UIView so it works with both iPhone 5 screen dimensions as well as regular screen dimensions

Here is the desired outcome. The blue area is the UIView of interest. The UIView is not a UIImageView.
I've tried all sorts of arrangements with auto-resizing masks to no avail
This can only be done programmatically. One option is what #user2223761 suggests with subclassing. If you don't want to subclass UIView, then you need to set the frames on orientation changes and set yourView.center to be the center of the center.
- (void) willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration {
if (UIInterfaceOrientationIsLandscape(interfaceOrientation)) {
// Make sure that the frame is centered in the screen
NSInteger paddingLeftSide = (self.view.bounds.size.width - 480) / 2;
self.view.frame = CGRectMake(paddingLeftSide, 0, 480, 320);
} else {
self.view.frame = CGRectMake(0, 0, 320, 320);
}
}
Dealing with different screen sizes can be tricky. In your case it is not :)
since you want to center the view in the screen what ever size it is, all you need to do is set the center of the view to be the center of the screen.
CGRect screenBounds = [[UIScreen mainScreen] bounds];
view.center = CGPointMake(screenBounds.size.width/2,screenBounds.size.height/2);
This code assumes the view's superView's bounds is the same size as the screenBounds..
First: Subclass UIView (create a MYUIView).
Second: override the method
- (void)layoutSubviews {
[super layoutSubviews];
// .. put your code...
}
and perform the frame update manually inside that method by reading the screen size.
auto-resize mask must be set to UIViewAutoresizingNone.

Using UIPopoverBackgroundView class

Apple is missing documentation on how to use UIPopoverBackgroundView class introduced in iOS5. Anyone have an example?
I have tried to subclass it, but my XCode 4.2 on Lion is missing UIPopoverBackgroundView.h
Edit: Unsurprisingly, it should have been imported as #import <UIKit/UIPopoverBackgroundView.h>
To add to the other, link-only answers, here is how this is done.
Create a new subclass of UIPopoverBackgroundView
Declare the following in your interface:
+(UIEdgeInsets)contentViewInsets;
+(CGFloat)arrowHeight;
+(CGFloat)arrowBase;
#property(nonatomic,readwrite) CGFloat arrowOffset;
#property(nonatomic,readwrite) UIPopoverArrowDirection arrowDirection;
The class methods are straightforward: contentViewInsets returns the width of your borders all the way round (not including the arrow), arrowHeight is the height of your arrow, arrowBase is the base of your arrow.
Implement the two property setters, making sure to call [self setNeedsLayout].
In your initialisation method, create two image views, one holding your arrow (which should be the size of the arrow dimensions in your class methods) and one holding your background image (which must be a resizable image) and add these as subviews. It doesn't matter where you put the subviews at this point, as you don't have an arrow direction or offset. You should make sure the arrow image view is above the background image view so it blends in properly.
Implement layoutSubviews. In here, according to the arrowDirection and arrowOffset properties, you have to adjust the frames of your background view and arrow view.
The frame of your background view should be self.bounds, inset by arrowHeight on whatever edge the arrow is on
The frame of the arrow view should be aligned so that the centre is arrowOffset away from the centre of self (correct according to the axis). You have to change the image orientation if the arrow direction is not up, but my popover would only be up so I didn't do that.
Here is the layoutSubviews method for my Up-only subclass:
-(void)layoutSubviews
{
if (self.arrowDirection == UIPopoverArrowDirectionUp)
{
CGFloat height = [[self class] arrowHeight];
CGFloat base = [[self class] arrowBase];
self.background.frame = CGRectMake(0, height, self.frame.size.width, self.frame.size.height - height);
self.arrow.frame = CGRectMake(self.frame.size.width * 0.5 + self.arrowOffset - base * 0.5, 1.0, base, height);
[self bringSubviewToFront:self.arrow];
}
}
Another link only answer, but customising UIPopoverBackgroundView is more work than you might realise given the limited documentation available and this github project has a complete working example which saved me a lot of time: https://github.com/GiK/GIKPopoverBackgroundView
It's fairly straightforward to drop into your own project. The most fiddly part is adapting the cap insets for whatever custom images you're using. I'd recommend doing your customisations in-situ in the project and as it's easy to verify all the popover orientation/direction use cases display correctly in the simulator before migrating it into your own project.

Custom Drawing with Xib file present

I have a view that I want to add some custom drawing to.
I know how to do this with a View that isn't connected to a Nib/Xib file
you write the drawing code in the -drawRect: method.
But if I init the view using
[[MyView alloc] initWithNibName:#"MyView" bundle:[NSBundle mainBundle]];
-drawRect: of course doesn't get called. I tried doing the below code in -viewDidLoad
CGRect rect = [[self view] bounds];
CGContextRef ref = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(ref, 2.0);
CGContextSetRGBStrokeColor(ref, 1.0, 1.0, 1.0, 1.0);
CGContextSetRGBFillColor(ref, 0, 0, 0, 0);
CGContextAddRect(ref, CGRectMake(1, 1, rect.size.width - 10, rect.size.height - 10));
CGContextStrokePath(ref);
CGContextDrawPath(ref, kCGPathFillStroke);
But nothing get drawn. Any ideas?
I think the issue is that you're treating a view and its view controller as interchangeable. For example, there's no -[UIView initWithNibName:bundle:] method — that's a UIViewController method.
Furthermore, a view isn't really like a "canvas" for drawing. A view will be asked to draw itself; in general, it won't be drawn into from "outside."
So:
Rename your subclass of UIViewController from MyView to MyViewController.
Create a new UIView subclass named MyView.
Add a -drawRect: method to your new MyView class that does the drawing you want.
Finally, set the Custom Class of your view controller's view in Interface Builder to MyView using the Identity Inspector.
For example, you should be able to use this for your -[MyView drawRect:] implementation:
- (void)drawRect:(CGRect)rect {
CGRect bounds = [[self view] bounds];
CGContextRef ref = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(ref, 2.0);
CGContextSetRGBStrokeColor(ref, 1.0, 1.0, 1.0, 1.0);
CGContextSetRGBFillColor(ref, 0, 0, 0, 0);
CGContextAddRect(ref, CGRectMake(1, 1, bounds.size.width - 10, bounds.size.height - 10));
CGContextStrokePath(ref);
CGContextDrawPath(ref, kCGPathFillStroke);
}
The drawing will be clipped to the update rectangle passed in.
Here are three possible solutions, depending on your constraints.
Set the class of the NSView object in the Xib file to be one of your custom classes. You mention that you know how to do custom drawing with a "hard-coded" NSView subclass, and this would work the same way. When the Xib file is loaded, the NSView is loaded into memory as an object of your custom class instead of the default. Changing the class type of the view in the Xib is simple with Interface Builder.
If the NSView object in the Xib file is already some kind of custom view that you do not want to override, you can add a subview to that view in Interface Builder, and simply make the subview into a custom class of your design (as in #1)
You can programmatically add a subview to the NSView object in the Xib file at runtime. In your sample code above, you could create an instance of your own custom NSView subclass, and then add it to the existing view using the addSubView: method.
How about doing all the drawing in a simple subview and add it to the XIB view (in viewDidLoad)?

Resources