View bounds and coordinates in Cocoa Mac OS X - objective-c

I have a simple custom view in my Mac OS X application that is essentially empty. Here is the code:
#implementation MyDrawingView
- (id)initWithFrame:(NSRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code here.
}
return self;
}
- (void)drawRect:(NSRect)dirtyRect
{
NSLog(#"bounds:x:%f y:%f w:%f h:%f", self.bounds.origin.x, self.bounds.origin.y, self.bounds.size.width, self.bounds.size.height);
}
#end
Here is the output of NSLog:
bounds:x:0.000000 y:0.000000 w:713.000000 h:509.000000
I read about user space here: Coordinate Systems and Transforms
Does this mean that my view is going to show 713/72 inches wide on screen? It doesn't show up that wide in reality. I have a background color set on my view so I can see it just as wide as it really is.

the view is 713 points wide. 713*screenscale = pixel size which you can then use with dpi to get the inches shown ;)

Related

drawRect in UIView subclass doesn't update image

I have a UIView subclass that I would like to use to draw images with different blend modes.
code:
#implementation CompositeImageView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
-(void)setBlendMode:(CGBlendMode) composite
{
blender = composite;
}
-(void)setImage:(UIImage*) img
{
image = img;
}
- (void)drawRect:(CGRect)rect
{
NSLog(#"it draws");
CGContextRef c = UIGraphicsGetCurrentContext();
CGContextSetBlendMode(c, blender);
CGContextDrawImage(c, rect, image.CGImage);
}
#end
the code that I use to set it up it is:
[testImage setImage:[UIImage imageNamed:#"Prayer_Background_Paid"]];
[testImage setBlendMode:kCGBlendModeColor];
[testImage setNeedsDisplay];
I am using the interface builder to place a large rectangular UIView, and then set its class to CompositeImageView. However, it still draws as a large white square. Even if I comment out everything inside drawRect, it still draws the white square. However, it IS calling drawRect, because "it draws" is being logged.
Are you sure kCGBlendModeColor is what you want? From the Apple doc:
Uses the luminance values of the background with the hue and
saturation values of the source image.
It seems that if it was a white background, the blended image would also appear white.

How to make iPhone app smaller on iPad?

I have converted ILColorPicker to work on XCode4 and Storyboard. My problem is that it fills the entire UIView on the iPad... where do I start looking for a way to make it smaller?
I was thinking of using a subview, but not sure how to "wire" it into the subview. Any other ideas?
UPDATE: here is the code where I believe I can modify the frame, except I don't know how...
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
[self setup];
}
return self;
}
Adjusting the frame size is programmed with CGRectMake like this:
- (id)initWithFrame:(CGRect)frame {
if ((self = [super initWithFrame:CGRectMake(x, y, width, height)])) {
// Initialization code
}
return self;
}
In the above the variable x and y corrispond to the top-left corner. And width and height are the width and height of the frame.

Scaling UITextView using contentScaleFactor property

I am trying to create a higher resolution image of a UIView, specifically UITextView.
This question and answer is exactly what I am trying to figure out:
Retain the resolution of the label after scaling in iphone
But, when I do the same, my text is still blurry:
self.view.transform = CGAffineTransformMakeScale(2.f, 2.f);
[myText setContentScaleFactor:2.f]; // myText is a subview of self.view object
I have also tried the same in the Apple sample project "UICatalog" to UILabel and it is also blurry.
I can't understand why it would work for Warrior from the other question and not for me. I would have asked there — but I can't seem to leave a comment or a question there.
Setting the contentScaleFactor and contentsScale is in fact the key, as #dbotha pointed out, however you have to walk the view and layer hierarchies separately in order to reach every internal CATiledLayer that actually does the text rendering. Adding the screen scale might also make sense.
So the correct implementation would be something like this:
- (void)updateForZoomScale:(CGFloat)zoomScale {
CGFloat screenAndZoomScale = zoomScale * [UIScreen mainScreen].scale;
// Walk the layer and view hierarchies separately. We need to reach all tiled layers.
[self applyScale:(zoomScale * [UIScreen mainScreen].scale) toView:self.textView];
[self applyScale:(zoomScale * [UIScreen mainScreen].scale) toLayer:self.textView.layer];
}
- (void)applyScale:(CGFloat)scale toView:(UIView *)view {
view.contentScaleFactor = scale;
for (UIView *subview in view.subviews) {
[self applyScale:scale toView:subview];
}
}
- (void)applyScale:(CGFloat)scale toLayer:(CALayer *)layer {
layer.contentsScale = scale;
for (CALayer *sublayer in layer.sublayers) {
[self applyScale:scale toLayer:sublayer];
}
}
UITextView has textInputView property, which "both draws the text and provides a coordinate system" (https://developer.apple.com/reference/uikit/uitextinput/1614564-textinputview)
So i'm using the following code to scale UITextView - without any font changes, without using any "CALayer" property and keeping high quality:
float screenScaleFactor = [[UIScreen mainScreen] scale];
float scale = 5.0;
textView.transform = CGAffineTransformMakeScale(scale, scale);
textView.textInputView.contentScaleFactor = screenScaleFactor * scale;
Comment the last line if you need low quality (but better performance) scaling.
Transform uses view.center as scaling center point, so adding a 'translate transform' is needed to scale around view corner.
Be sure to apply the contentScaleFactor to all subviews of the UITextView. I've just tested the following with a UITextView and found it to work:
- (void)applyScale:(CGFloat)scale toView:(UIView *)view {
view.contentScaleFactor = scale;
view.layer.contentsScale = scale;
for (UIView *subview in view.subviews) {
[self applyScale:scale toView:subview];
}
}

MKMapView rendering problem on iPad

My problem occurs only on iPad. There is always unrendered portion of MKMapView(right side on the picture below). As soon as I touch this window the mapview repaints itself just fine. But it never renders correctly right away. This problem occures in iOS 4.2 as well as in iOS 3.2 in Simulator and the Device. The code that constructs MKMapView is right below:
- (void)viewDidLoad {
[super viewDidLoad];
mapview = [[[MKMapView alloc] initWithFrame:CGRectMake(0,0,self.view.frame.size.width,230)] autorelease]; // because of apples bug
mapview.autoresizingMask = UIViewAutoresizingFlexibleWidth;
MKCoordinateSpan globe = MKCoordinateSpanMake(100, 100);
CLLocationCoordinate2D worldCenter; worldCenter.latitude = 42.032974; worldCenter.longitude =21.359375;
MKCoordinateRegion worldmap = MKCoordinateRegionMake(worldCenter, globe);
mapview.region = worldmap;
mapview.zoomEnabled = NO;
mapview.showsUserLocation = YES;
mapview.delegate = self;
NSRange theRange;
theRange.location = 1;
theRange.length = [annotations count]-1;
[mapview addAnnotations:[annotations subarrayWithRange:theRange]];
[self.view addSubview:mapview];
}
The problem manifests itself only in Landscape orientation.
UPDATE
This is how it spans after I touched the view.
Nonetheless it's Apple's bug. In iPad-landscape mode your longtitude span may not be enough to cover 360degree of the globe. it should autoscale with zoom, but it doesn't. it autozooms properly only if your centerMap is exactly at 0 degree longitude. Weird.
Workaround:
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
CLLocationCoordinate2D worldCenter; worldCenter.latitude = 42.032974;
worldCenter.longitude = UIDeviceOrientationIsLandscape(toInterfaceOrientation)? 0.0 : 21.359375;
mapview.centerCoordinate = worldCenter;
}
I did a quick test with your code and get the same result (which I expected). I still think it is not an issue with the map itself but with the way you are setting your center coordinates plus map span. You're trying to center the map too far to the left with max span and the only way for the map to fill the entire screen and maintain the center point would be for it to stretch itself, which is not desirable. If you set lat and long to 0 you get the same view without the missing part.

Adding Padding To The 'left' of a Text Field

I have a text field with a background but to make it look right the text field needs to have some padding on the left side of it a bit like the NSSearchField does. How would I give the text field some padding on the left?
smorgan's answer points us in the right direction, but it took me quite a while to figure out how to restore the customized textfield's ability to display a background color -- you must call setBorder:YES on the custom cell.
This is too late to help Joshua, but here's the how you implement the customized cell:
#import <Foundation/Foundation.h>
// subclass NSTextFieldCell
#interface InstructionsTextFieldCell : NSTextFieldCell {
}
#end
#import "InstructionsTextFieldCell.h"
#implementation InstructionsTextFieldCell
- (id)init
{
self = [super init];
if (self) {
// Initialization code here. (None needed.)
}
return self;
}
- (void)dealloc
{
[super dealloc];
}
- (NSRect)drawingRectForBounds:(NSRect)rect {
// This gives pretty generous margins, suitable for a large font size.
// If you're using the default font size, it would probably be better to cut the inset values in half.
// You could also propertize a CGFloat from which to derive the inset values, and set it per the font size used at any given time.
NSRect rectInset = NSMakeRect(rect.origin.x + 10.0f, rect.origin.y + 10.0f, rect.size.width - 20.0f, rect.size.height - 20.0f);
return [super drawingRectForBounds:rectInset];
}
// Required methods
- (id)initWithCoder:(NSCoder *)decoder {
return [super initWithCoder:decoder];
}
- (id)initImageCell:(NSImage *)image {
return [super initImageCell:image];
}
- (id)initTextCell:(NSString *)string {
return [super initTextCell:string];
}
#end
(If, like Joshua, you only want an inset at the left, leave the origin.y and height as is, and add the same amount to the width -- not double -- as you do to the origin.x.)
Assign the customized cell like this, in the awakeFromNib method of the window/view controller that owns the textfield:
// Assign the textfield a customized cell, inset so that text doesn't run all the way to the edge.
InstructionsTextFieldCell *newCell = [[InstructionsTextFieldCell alloc] init];
[newCell setBordered:YES]; // so background color shows up
[newCell setBezeled:YES];
[self.tfSyncInstructions setCell:newCell];
[newCell release];
Use a custom NSTextFieldCell that overrides drawingRectForBounds:. Have it inset the rectangle by however much you want, then pass than new rectangle to [super drawingRectForBounds:] to get the normal padding, and return the result of that call.