I've written a screen saver that displays a web page. It works exactly as I want it to on my main display, but in the preview and secondary displays, the web view is hanging off the top of the screen.
Example (from preview):
screen saver bug http://img.skitch.com/20081212-nk5cqrgfds1funr1a3p72aw25q.preview.jpgUploaded with plasq's Skitch!
My code is pretty straightforward. From within initWithFrame:isPreview: I have the following code:
webview = [[WebView alloc] initWithFrame:frame
frameName:#"main"
groupName:#"main"];
[self addSubview:webview];
Does anyone have any idea what's happening?
If anyone wants to play with the project, the code is on github.
I looked at your code and you're using the superview's (WebSaverView) frame rectangle as the WebView's frame. You should instead use it's bounding rectangle ([self bounds]). The bounding rectangle represents the area "inside" the superview. As you've seen, the two may not always have the same origin, which is causing this issue. You should not be adjusting the frame you're passed in initWithFrame:, since the origin probably has a very good reason for not being 0,0.
I think the frame you're giving the WebView is in the wrong coordinates. Remember that a view's frame is expressed in terms of the superview's coordinate system (bounds).
You should be making the view as big as the superview's -bounds, if I get correctly what you want to do: usually a rect from (0,0) to (width,height).
Related
I'm new to Obj-C/Cocoa programming and facing to a problem about NSImageView.
My goal is to create an app which allow the user to put an image on it with drag&drop.
The problem is the following : when we're dropping an image larger than the window, it resizes the window to the image size, I don't want that !
I put my NSImageView into a NSScrollView so only a certain part of the image MUST be showed and the user will move sliders to view the entire one (or simply resize the window), that's what I want..
Here is my XIB hierarchy (concerned part) :
View
NSScrollView
View
NSImageView
In the code of my NSImageView, I have (about that problem) :
[self setImageScaling:NSScaleProportionally];
[self setImage:newImage];
NOTE: The sliders seem to move the view and not the image
NOTE2: I can't resize the window to a lower size than the image
I have a horrible aversion to nib files and prefer to do things programmatically whenever possible so I'm not much help with that... but here's a little listing from a little NSScrollview test app I recently coded up that does something similar. The only non-self-contained thing mentioned in this code chunk is the window name, which refers to an NSWindow * for a window that was already created. And self here just refers to a controller object.
NSImage * myImage = [NSImage imageNamed:#"myfilename.png"];
NSRect imageRect = NSMakeRect(0.0,0.0,myImage.size.width,myImage.size.height);
self.myImageView = [[NSImageView alloc] initWithFrame:imageRect];
self.myImageView.bounds = imageRect;
self.myImageView.image = myImage;
self.myScrollView = [[NSScrollView alloc] initWithFrame:[window.contentView frame]];
self.myScrollView.hasVerticalScroller = YES;
self.myScrollView.hasHorizontalScroller = YES;
self.myScrollView.documentView = self.myImageView;
self.myScrollView.borderType = NSNoBorder;
self.myScrollView.scrollerStyle = NSScrollerStyleOverlay;
window.contentView = self.myScrollView;
I know that's perhaps not the solution you were looking for but maybe it helps you debug? In particular, I didn't do anything funny with my NSImageView besides give it a frame, a bounds rectangle, and an NSImage *, so I don't think you need to worry about the scaling parameter per se -- in fact, if you want the image to be full-sized and to scroll around it, you want your NSImageView's frame to be the same size as the image so that it doesn't HAVE to scale at all. Maybe that's your problem -- the frame is too small? It is OK for the NSImageView frame to be bigger than the window -- that's what lets you scroll around it.
To me it sounds like your views don't have the proper sizes. Because of bouncing and because your views don't clip their subviews, you can still scroll a bit, but it returns to its original position.
Check if the NSImageView is big enough to display your full image. (Check frame or bounds for width and height)
If it is not big enough do this (inside the method, where you set the new image):
self.myImageView.frame = NSMakeRect(0.0,0.0, self.myImageView.image.size.width, self.myImageView.image.size.height);
Adjust the size of your scroll views view accordingly.
self.myScrollView.view.frame = self.myImageView.frame;
Now your scrollable area should be big enough to cover the full image.
If this works for you, give Matt some credit as well, by up-voting his answer, since his answer does essentially the same thing - only code based, instead of initialising everything using a nib file - and the code I used is very similar to what he had already posted.
I suggest to put the "image view" inside of the custom view (edges to its superview).
The image view's constraints to the equal edges, except the bottom constraint, which to the "Less Than or Equal" relation to its superview.
I am developing a iOS-6 app. I have a UIViewController with a view that needs fixed orientation (portrait mode). But when the phone is rotated, one control on that view needs to be moved and rotated (so that it will always be in the upper left corner, and its text will be readable).
I am achieving this by shifting the control(a UIView) using the frame-property of my control (it is a custom view, more on that later), and then using CGAffineTRansformMakeRotate() afterwards, since I know that it's not advisable to use the frame after rotating a view. Everything is fine so far, but here's the thing: That custom view has three UIButtons of type UIButtonTypeCustom as its subviews. Because I rotated the View, but cannot rotate the buttons inside the view (they are not squares), I need to rotate the titleLabels of the Buttons for the text to be readable in the new deviceOrientation.
But it won't work very well. The text will be rotated, as I intended, but it will be clipped by the titleLabel, because the titleLabel has the wrong frame. I checked this by applying borders to the label. So I need to change the titleLabels frame, right? But how can I do that? I tried setting it using [titleLabel setFrame: frameThatFits];, but to no avail. (frameThatFits is a CGRect I created). Also, calling [button.titleLabel sizeToFit]; has no effect that I could see.
I am using [button setTitle:title forControlState: UIControlStateNormal];to set the title.
TL;DR: I'm trying to change the frame/bounds of a UIButtons titleLabel after rotating it using an affine transformation. Any help?
Thanks.
PS: I can supply code when needed, but I wouldn't know what to show you. Tell me what you need, I'll post it.
OK, first of all, thanks to everyone who tried to help. Im posting an alternative solution for my problem, and although it doesnt really address the problem of changing the titleLabels dimensions, it will result in the proper display of my ViewController.
It turns out using the frame is a bad idea. I initially used the frame to reposition the view and i figured that this couldnt be a problem because i only ever applied transformations afterwards, but i was wrong. Because OBVIOUSLY i tried to change the titleLabels frame. AFTER the rotation. And that didnt work.
So the way to go here is using the center-property and the bouds of the view consistently throughout the code. It will result in properly rotated Buttons, that do not need any fidgeting afterwards.
My takeaway here is that i will never ever again use the frame-property outside of a NSLog-statement. But why [button sizeToFit];wouldnt yield any results is still beyond me. If i ever figure it out, i might post it if i remember.
EDIT:
#ZevEisenberg nailed it with this comment:
“Warning: If the transform property is not the identity transform, the value of this property is undefined and therefore should be ignored.” So you are right to use the center and bounds here, but if you do not have a transform, the frame is perfectly safe to use.
NEXT EDIT:
Heres how i ended up repositioning the Buttons:
-(CGPoint)centerForView:(UIView *)view{
//calculate a suitableposition for the view
//depending on the current orientation and the device type (iphone 4S/5, etc)
return point;
}
Then, as a reaction to the deviceOrientation change notification, i apply CGAffineTransformIdentity to all the views, reposition them using my centerForView shown above, and apply the correct rotation transformation to the View. I do this for all the subviews every time the divice rotates, like so:
-(void)setRightRotationTransformations{
[self resetAllTransformations];
self.someSubview.transform = CGAffineTransformRotate(self.someSubview.transform, -M_PI_2);
}
In my case works such hack:
set Line Break mode to Word Wrap
Add extra line to title (even for one line title)
When making a photo viewer app found that our UIImageView controller is drawing its image outside its frame when the content mode is different neither ScaleToFill nor Aspect Fit.
Trying to understand why; I isolated the problem making a new project which only has a UIImageView with the following frame (50,50,100,100). The image size contained in it is (4592,3056).
After running the app, with the content mode set to ScaleToFill and AspectFit it all worked as expected:
But after setting the contentMode of the UIImageView to TopLeft, the image is drawn outside its frame, the odd thing is that the log from the frame after all has been drawn is still the original {50,50,100,100}.
I've try to understand the issue by moving the Autoresize, the clips and the content mode of the UIViewController but the result is the same.
set clipToBounds = YES on the view.
its NO by default because that makes drawing way cheaper
I have a problem understanding how the parameter passed to the drawInRect method is defined when a rotation transformation is performed on a UIView.
To give an example I have a UIView which I rotated with an angle of 307 degree.
In the drawInRect method I log the following:
self.frame: {{103.932, 273.254}, {64.3007, 84.3374}}
rect (the variable passed as parameter:{{0, 0.102913}, {18, 89}}
The problem is that according to the documentation I should not draw outside of rect, but considering what I should draw, there is no way my images will fit there.
Can anyone explain to me how I am supposed to use drawInRect in the case my UIView is rotated ?
To give more detail about my problem, here is what I do:
I have a scrollview with a contentView inside (subclassed). I add my UIViews in the content view.
The views in question are composed of a handler image (bottom left) and the main image (top right). Users are supposed to grab the view by pressing the handler but that's not the point.
The drawInRect method of the UIView contains the following:
[_image drawInRect:CGRectMake(handlerSize.width, 0, _image.size.width, _image.size.height)];
CGSize size = CGSizeMake(kHandPickerWidth/self.scrollViewScale, kHandPickerHeight/self.scrollViewScale);
[_handPickerImage drawInRect:(0, _image.size.height, size.width, size.height)];
The UIViews objects are added at viewWillAppear in the content view doing the following:
first instanciate,
then addSubview:
then I set the scrollViewScale parameter,
then I set the frame parameter (according to the top right image displayed (which may vary)
then I rotate the UIView.
Starting from line three, the code is executed from the
- (void)scrollViewDidZoom:(UIScrollView *)scrollView
to make sure every variable is set properly when displayed is needed.
The line defining the size variable is to adjust the marker's size no mater the zoomScale value of the scroll view.
You basically just draw as you would normally, and the painting will be rotated by iOS for you. You can get this transformation information if you would want to.
You need to get a reference to the currect graphics context:
CGContextRef ctx = UIGraphicsGetCurrentContext();
Then query the transformation matrix directly:
CGAffineTransform tf = CGContextGetCTM(ctx);
NSLog(#"current ctm: %#",NSStringFromCGAffineTransform(tf));
or better, get the transfrom from your drawing function to the device:
CGAffineTransform tf = CGContextGetUserSpaceToDeviceSpaceTransform(ctx);
NSLog(#"user->device transform: %#",NSStringFromCGAffineTransform(tf));
And in drawRect: you should not rely too much on the passed CGRect, because it serves mostly as a hint to what piece of the view needs updating. (e.g. because you called -setNeedsDisplayInRect: on it). To get the actual bounds where your view lives in, use self.bounds.
Drawing outside of the CGRect is no real problem, but will only hurt performance a little.
edit
ps. to clarify: self.frame is the frame of your view in the parent view coordinate system. It changes if you move, rotate or otherwise transform the view. self.bounds is the frame of your view in its own coordinate system, and (therefore) remains constant under changes of position or transformations.
So I found a solution to my problem:
I was setting the frame parameter multiple times with some CGAffineTransformation defined which is not supposed to be done.
Now each time I need to reset the frame I reset the affine transform, change the frame and set the back the affine transform.
Everything works as supposed to this way.
I am putting an image into an IKImageView, and immediately sizing it to fit. Whenever I do this, the image originally appears at 1-1 size (huge) and then resizes down, which would be fine if the animation was smooth. However, the animation looks ... fluttery? There are big blocks, like 2 inches square, of the image that appear and shrink independently of each other. The effect is a little annoying, and almost to the level where it might give an epileptic a seizure... (I'm exaggerating a little).
Is this a bug in IKImageView? Is it a bug in the animation? Will it go away if I turn off the animation (How do I do that? setAnimates: NO doesn't seem to do anything, nor does overloading animates to return NO in my subclass...
EDIT: addedcode:
NSImage* image = [doc currentImage];
[imageView setImage: image];
[imageView zoomImageToFit: self];
This is in the app controller, so self is the application (or plugin, depending on which version I'm looking at)
If you tell the IKImageView to autoresize, then it won't animate the new image to the new size and the artefacts will not be a problem. The image will be sized to fit in the image view immediately.
imageView.autoresizes = YES;