I spent a couple of hours trying to position a UIView and eventually figured out that I needed to modify the views frame. So I added a 'setPosition' method to the UIViewController subclass like this
- (void) setPosition:(CGPoint)position
{
CGRect newFrame = self.view.frame;
newFrame.origin.x = position.x;
newFrame.origin.y = position.y;
self.view.frame = newFrame;
}
However, that seems so simple that I don't understand why UIViews don't have this method already, which makes me think this might not be the right way to do it. So that's my question...
Is this method OK or am I doing something I shouldn't be doing... for some reason?
Copying, Modifying and setting the frame again like you have done here is how this is generally done. This can also be done by creating a rect and setting it directly:
UIView.frame = CGRectMake(50,50,50,50);//x,y,w,h
Doing this in an animation block will animate these changes.
Alternitively you can set a views Center point with :
UIView.center = CGPointMake(50,50);
Other way:
CGPoint position = CGPointMake(100,30);
[self setFrame:(CGRect){.origin = position,.size = self.frame.size}];
This i save size parameters and change origin only.
Related
What I Want to Do:
In Messages.app on OS 10.10, when you scroll the left-most pane (the list of conversations) upwards, a nice horizontal line fades in over about 0.5 seconds. When you scroll back down, the line fades back out.
What I Have:
I am trying to achieve this effect in my own app and I've gotten very close. I subclassed NSScrollView and have done the following:
- (void) awakeFromNib
{
_topBorderLayer = [[CALayer alloc] init];
CGColorRef bgColor = CGColorCreateGenericGray(0.8, 1.0f);
_topBorderLayer.backgroundColor = bgColor;
CGColorRelease(bgColor);
_topBorderLayer.frame = CGRectMake(0.0f, 0.0f, self.bounds.size.width, 1.0f);
_topBorderLayer.autoresizingMask = kCALayerWidthSizable;
_topBorderLayer.zPosition = 1000000000;
_fadeInAnimation = [[CABasicAnimation animationWithKeyPath:#"opacity"] retain];
_fadeInAnimation.duration = 0.6f;
_fadeInAnimation.fromValue = #0;
_fadeInAnimation.toValue = #1;
_fadeInAnimation.removedOnCompletion = YES;
_fadeInAnimation.fillMode = kCAFillModeBoth;
[self.layer insertSublayer:_topBorderLayer atIndex:0];
}
- (void) layoutSublayersOfLayer:(CALayer *)layer
{
NSPoint origin = [self.contentView documentVisibleRect].origin;
// 10 is a fudge factor for blank space above first row's actual content
if (origin.y > 10)
{
if (!_topBorderIsShowing)
{
_topBorderIsShowing = YES;
[_topBorderLayer addAnimation:_fadeInAnimation forKey:nil];
_topBorderLayer.opacity = 1.0f;
}
}
else
{
if (!_topBorderIsShowing)
{
_topBorderIsShowing = NO;
// Fade out animation here; omitted for brevity
}
}
}
The Problem
The "border" sublayer that I add is not drawing over top of all other content in the ScrollView, so that we end up with this:
The frames around the image, textfield and checkbox in this row of my outlineView are "overdrawing" my border layer.
What Causes This
I THINK this is because the scrollView is contained inside an NSVisualEffectView that has Vibrancy enabled. The reason I think this is that if I change the color of my "border" sublayer to 100% black, this issue disappears. Likewise, if I turn on "Reduce Transparency" in OS X's System Preferences > Accessibility, the issue disappears.
I think the Vibrancy compositing is taking my grey border sublayer and the layers that represent each of those components in the outlineView row and mucking up the colors.
So... how do I stop that for a single layer? I've tried all sorts of things to overcome this. I feel like I'm 99% of the way to a solid implementation, but can't fix this last issue. Can anyone help?
NB:
I am aware that it's dangerous to muck directly with layers in a layer-backed environment. Apple's docs make it clear that we can't change certain properties of a view's layer if we're using layer-backing. However: adding and removing sublayers (as I am) is not a prohibited action.
Update:
This answer, while it works, causes problems if you're using AutoLayout. You'll start to get warnings that the scrollView still needs update after calling Layout because something dirtied the layout in the middle of updating. I have not been able to find a workaround for that, yet.
Original solution:
Easiest way to fix the problem is just to inset the contentView by the height of the border sublayer with this:
- (void) tile
{
id contentView = [self contentView];
[super tile];
[contentView setFrame:NSInsetRect([contentView frame], 0.0, 1.0)];
}
Should have thought of it hours ago. Works great. I'll leave the question for anyone who might be looking to implement these nice fading-borders.
I put UIImageView in my Scene from Object library, and give it an image and defined OUTLET in .h file. Now I want to check its coordinates, or center point, or frame X,Y,Width,Height.
I am using
This
CGRect newFrameSize = CGRectMake(recycleBin.frame.origin.x, recycleBin.frame.origin.y,
recycleBin.frame.size.width, recycleBin.frame.size.height);
or
CGRect newFrameSize = recycleBin.frame;
by using this
NSLog(#"%#", NSStringFromCGRect(newFrameSize));
gives same result that is
2013-01-16 21:42:25.101 xyzapp[6474:c07] {{0, 0}, {0, 0}}
I want its actual position and size when viewcontroller loaded, so when user click on image view it will fadeout by zoom-in towards users and will disappear, and when user tap on reset button, it fadein and zoom-in back to original form (reverse to the previous animation).
Also give me hint, how to perform this animation on UIImageView or any button or label. Thx
Unfortunately, you can't check an item's actual frame as set in IB in -viewDidLoad. The earliest you can check it (that I've found) is by overriding -viewDidAppear:. But, since -viewDidAppear: could be called multiple times throughout the life of the view, you need to make sure you're not saving the frame it's in the modified state.
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
if(savedFrame == CGRectZero) {
savedFrame = self.recycleBin.frame;
NSLog(#"Frame: %#", NSStringFromCGRect(savedFrame));
}
}
Where savedFrame is a member variable (or you could make it a property).
From the description of the animation you're wanting, it sounds like adjusting the frame isn't the way to go about it. It sounds like you're wanting to get the effect of the view stretching and fading out (and the reverse when being reset)? If so, some code like this might be more so what you're looking for...
Fade out:
float animationDuration = 2.0f; // Duration of animation in seconds
float zoomScale = 3.0f; // How much to zoom in duration the animation
[UIView animateWithDuration:animationDuration animations:^{
CGAffineTransform transform = CGAffineTransformMakeScale(zoomScale, zoomScale);
self.recycleBin.transform = transform;
self.recycleBin.alpha = 0; // Make fully transparent
}];
And then, to reset the view:
float animationDuration = 2.0f; // Duration of animation in seconds
[UIView animateWithDuration:animationDuration animations:^{
CGAffineTransform transform = CGAffineTransformMakeScale(1.0f, 1.0f);
self.recycleBin.transform = transform;
self.recycleBin.alpha = 1.0; // Make fully opaque
}];
You can play around with the numbers to see if you get the effects you desire. Most animations in iOS are actually extremely simple to do. This code would work for any UIView subclass.
It sounds as if your IBOutlet is not attached to your class.
Open up your view controller header file (if that is where you property declaration is) and look beside the declaration:
Notice how on the first IBOutlet, the circle (to the left of the line number) is filled in. This means that it is connected to your scene. However, the second one is not (the circle is not filled in).
I'm trying to implement a UIDatePickeron Storyboard. As you would expect, the date picker can't be on screen when the view first loads so I have to write the custom code to move it off screen on load. Here's the code...
- (void)hideDatePicker
{
CGRect newRect = self.datePicker.frame;
CGPoint newOrigin = CGPointMake( 0, [[UIScreen mainScreen] bounds].size.height);
newRect.origin = newOrigin;
self.datePicker.frame = newRect;
}
I am currently calling this method in viewDidLoad.
When I run the app, the date picker is still on the bottom of the screen, disgustingly taking up half the screen...
You may want to implement it inside an UIActionSheet, a not-so-difficult and elegant solution. Check out this question that will provide you a brief explanation and the necessary code. Add UIPickerView & a Button in Action sheet - How?
In -viewDidLoad: you can't be sure that all IBOutlets are instantiated and all geometry set, so you better call your method in -view[Will/Did]Appear: if you're using any geometry transformations.
And it's easier to hide with hidden property
yourView.hidden = YES;
I have no idea why this code isn't working, but hopefully the fix is simple, I hope someone can help.
I have 2 functions, enterFullScreen and exitFullScreen.
In the enterFullScreen method, I set an NSView's frame to the Window's frame, which has a full-screen effect, this is what I want. Within this method I store the old frames so that in the exitFullScreen method I can set them back, but this isn't working. It has no effect whatsoever. The code is as follows:
NSView oldView, oldViewContainer;
- (void) enterFullScreen:(NSView*)newView
{
// Store original views
oldView = newView;
oldViewContainer = _newViewContainer;
// Set new views to fit window
[_newViewContainer setFrame:[_window.contentView frame]];
[newView setFrame:[_window.contentView frame]];
}
- (void) exitFullScreen:(NSView*)newView
{
// Restore old views
[_newViewContainer setFrame:[oldViewContainer frame]];
[newView setFrame:[oldView frame]];
}
The enter fullscreen method works exactly as expected, but for some reason I can't set the 2 Views back to their original size/location.
I don't know if it's because I can't just store the whole view, or if the origin is causing problems?
I've tried every combination, if somebody could help I'd be really grateful.
Thanks in advance.
You don't want to set oldView to newView, that makes them the same view, so when you resize newView to full screen, oldView's frame also is set to full screen. You want to save the old frame, not the view, so:
oldFrame = newView.frame; (to store the original frame)
then when you resize smaller,
[newView setFrame:oldFrame];
I am trying to change the size of an image when a button is pushed to make it get longer or shorter. I would prefer it if it could be animated into changing its size, but without animation would also help, if anyone can give me any information if this is possible, and how then it would be appreciated
Thanks for your help in advance
Assuming you are using a UIImageView then you simply change the size (this may cause bad effects depending on how much you stretch etc).
NOTE: newFrame is whatever your new frame will be
- (void)buttonTapped:(id)sender
{
CGRect newFrame = ...;
self.myImageView.frame = newFrame;
}
To animate it stick this inside an animation block
- (void)buttonTapped:(id)sender
{
CGRect newFrame = ...;
[UIView animateWithDuration:0.25f
animations:^{
self.myImageView.frame = newFrame;
}];
}