I created a floating view for my application which always displays on screen.
Now I want to make a half of it go outside my screen when it is interactive for 3-4 seconds. I think I should use a NSTimer to hide out this view, but it is not the problem.
The problem is how should I set origin.x of this view to go outside of the screen? I've tried to set the frame in my initWithSuperView like this:
CGRect screenRect = [[UIScreen mainScreen] bounds];
CGFloat screenX = screenRect.origin.x;
[self setFrame:CGRectMake(-screenX - size.width, 0, size.width, size.height)];
However, it doesn't work. How should I do it to get my desired result? See image below for more information:
you can use uiview animation similar to this:
dispatch_async(mainQueue, ^{
__weak __typeof(self) weakSelf = self;
[UIView animateWithDuration:3.f animations:^{
// change uiview frame here
weakSelf.frame = hiddenFrame;
} completion:^(BOOL finished) {
// setup completion
[weakSelf.view layoutIfNeeded];
}];
});
also you can setup NSLayoutConstraint to the x constraint of uiview and update it with negative value when you need.
Related
I have this code below who move my UIView to left:
- (void)viewDidLoad {
[super viewDidLoad];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:4];
int xOriginal = 91;
CGRect rect = imagem.frame;
int x = rect.origin.x;
int y = rect.origin.y;
int w = rect.size.width;
int h = rect.size.height;
if(x == xOriginal){
imagem.frame = CGRectMake(x+100, y, w, h);
}else{
imagem.frame = CGRectMake(x-100, y, w, h);
}
[UIView commitAnimations];
}
My coordinate of my view is x = 91 (Center of the superView), When I start my app my UIView start left and go to center, instead of center and go to right, Why this is happening?
How to make my UIView start in center (x=91) and go to right (91+100), instead of left to center?
[UIImageView animateWithDuration:0.5 delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
imagem.frame=CGRectMake(imagem.frame.origin.x+100, imagem.frame.origin.y, imagem.frame.size.width, imagem.frame.size.height);
} completion:^(BOOL finished) {
//code for completion
NSLog(#"Animation complete");
}];
Autolayout and frame animations are not good friends. Try to animate constraints instead of directly the frame.
You can create outlets of your constraints, and set the constant property of the constraint in your code to move your views.
You also call -[view layoutIfNeeded] to refresh your constraints while in an animation block.
Else you can remove all of your view constraints and animate its frame fearlessly.
Initially image.frame = CGRectMake(91,100,20,20);
So imageview starting point is 0
[UIView animateWithDuration:5.0
animations:^{
//Animation code goes here
image.frame = CGRectMake(191,100,20,20); //Now imageview moves from 0 to 100
} completion:^(BOOL finished) {
//Code to run once the animation is completed goes here
}];
As the other poster says, you can't animate a view's frame in XIBs/storyboards that use AutoLayout.
Instead you have to animate a constraint that's attached to the view.
What you do is to create a constraint (or multiple constraints) and connect it to an IBOutlet. Then, in your animation code, you calculate the changes to the constraint(s) and change the constant for the appropriate constraints.
For example, if you wanted to shift the vertical position of a view, set up a constraint that sets the vertical position of your view, and link it to an IBOutlet called viewConstraint. Then you'd use code like this:
[myView animateWithDuration: .25
animations: ^
{
viewConstraint.constant -= shiftAmount;
[self.view layoutIfNeeded];
}
];
I have embedded all my views in a UIScrollView from xib. The scrollview contents cover all screen below status bar. Now when the textfield is tapped, I am able to move the scrollview little up. But I want it to be completely scrollable till the bottom most view is also visible above the keyboard. Also when the scrollview is scrolled till top , it should come to normal original positions. Hence, Overall I want a completely scrollable functionality like mentioned above for my scrollview.
I am done with following tricks but with no luck:
Trick 1: Change the height of the scrollview so that the content is more than scrollview height and hence the view is scrollable:
-(void)keyboardWillAppear:(NSNotification *)sender
{
CGFloat y_offset=0;
if([UIScreen mainScreen].bounds.size.height == 480){
y_offset = 80;
} else {
y_offset = 70;
}
NSDictionary* userInfo = [sender userInfo];
CGRect keyboardEndFrame;
[[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardEndFrame];
keyboardHeight = keyboardEndFrame.size.height;
[UIView animateWithDuration:0.5f animations:^{
[self.view setFrame:CGRectMake(0, - y_offset, self.view.frame.size.width, self.view.frame.size.height)];
}];
[self.loginScrollView setFrame:CGRectMake(self.loginScrollView.frame.origin.x, self.loginScrollView.frame.origin.y, self.loginScrollView.frame.size.width, [UIScreen mainScreen].bounds.size.height - keyboardHeight)];
}
-(void)keyboardWillDisappear:(NSNotification *)sender
{
[UIView animateWithDuration:0.5f animations:^{
[self.view setFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
}];
[self.loginScrollView setFrame:CGRectMake(self.loginScrollView.frame.origin.x, self.loginScrollView.frame.origin.y, self.loginScrollView.frame.size.width, [UIScreen mainScreen].bounds.size.height)];
}
Trick 2: As per other suggestions, I changed the contentInset of the UIScrollView.
In keyboardWillAppear method I added following code:
CGSize kbSize = [[userInfo objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height+100, 0.0);
self.loginScrollView.contentInset = contentInsets;
self.loginScrollView.scrollIndicatorInsets = contentInsets;
and in keyboardWillDisappear method I set the contentInset back to zero values.
Hence, let me know if there needs to be any other way to sort this out or any other possible changes I need to make in scrollview frame. Moreover , if I turn on the bouncesVertically functionality it is able to bounce even when complete subviews are visible onscreen which I don't want. So basically I want it to freeze when keyboard is not there and scrollable till viewable area when it is up. Hence, give me any other suggestions? Thanks in advance.
From a conceptual point of view when "scrollView Size == scrollView ContentSize", it does not scroll. To make it scrollable we need to increase the contentSize. In your problem you need to adjust the contentSize of scrollView along with frame. This can be done in your first approach.
As for the second approach, changing the edge insets will create a sort of padding for the content drawable area. This can make the bottom content visible, but it won't affect the contentSize, hence view will not be scrollable.
-(void)textFieldDidBeginEditing:(UITextField *)textField
{
[self animateTextField:textField up:YES];
}
-(void)textFieldDidEndEditing:(UITextField *)textField
{
[self animateTextField:textField up:NO];
}
-(void)animateTextField:(UITextField*)textField up:(BOOL)up
{
const int movementDistance = -60; // change this size if you need
const float movementDuration = 0.3f; // change this size if you need
int movement = (up ? movementDistance : -movementDistance);
[UIView beginAnimations: #"animateTextField" context: nil];
[UIView setAnimationBeginsFromCurrentState: YES];
[UIView setAnimationDuration: movementDuration];
self.view.frame = CGRectOffset(self.view.frame, 0, movement);
[UIView commitAnimations];
}
it is useful for me
I can really recommend this library:
https://github.com/michaeltyson/TPKeyboardAvoiding
It's very very easy to use, and works for ScrollView, TableView and CollectionView!
I am trying to reproduce an effect like the iOS 7 app switcher where I can scroll between smaller, transformed views. My current obstacle is getting the contentOffset
In order to do this, I have added a scrollView to my view, and sized it to the bounds of the view. I then create a container view that holds on to all the 'cards' -- it is this container view to which I apply the transform.
Anyway, the issue I am having is with adjusting where a particular card appears after it has the transform applied -- right now, I am unable to adjust the contentOffset during the transform in a manner that is smooth.
Anyway, code would help! Here it is:
NSInteger idx = selectedCardIndex;
if (TransformApplied)
{
[UIView animateWithDuration:0.5 animations:^{
[self.container setTransform:CGAffineTransformIdentity];
[self.container setFrame:CGRectOffset(self.container.frame, (1-ScaleFactor)/2 * NumCards * ScreenWidth, 0)];
[self.scrollView setContentSize:self.container.frame.size];
[self.scrollView setContentOffset:CGPointMake(ScreenWidth * idx, 0) animated:NO];
[self.scrollView setPagingEnabled:YES];
} completion:^(BOOL finished) {
TransformApplied = NO;
}];
}
else
{
[UIView animateWithDuration:0.5 animations:^{
[self.container setTransform:CGAffineTransformMakeScale(ScaleFactor, ScaleFactor)];
[self.container setFrame:CGRectOffset(self.container.frame, (-1)*((1-ScaleFactor)/2) * NumCards * ScreenWidth, 0)];
[self.scrollView setContentSize:CGSizeMake(ScreenWidth * ScaleFactor * NumCards, ScreenHeight * ScaleFactor)];
[self.scrollView setContentOffset:CGPointMake(ScaleFactor * ScreenWidth * idx, 0) animated:NO];
[self.scrollView setPagingEnabled:NO];
} completion:^(BOOL finished) {
TransformApplied = YES;
}];
}
More
I am noticing that everything is smooth when applying the identity transform, but not when applying the smaller transform, I get a weird 'jump' in the frame before the animation.
If i comment out the content offset adjustment in the scale transform (the bottom block) then everything runs smoothly, but the contentOffset is wrong after the scale transform.
Lastly, calling setContentOffset:animated: results in a wonky animation so that is a no-go.
Any help greatly appreciated!!!!
UPDATE
I've looked in to anchor point/ position properties on CALayer, and I've got the animation effects working perfectly with this:
NSInteger idx = selectedCardIndex;
if (TransformApplied)
{
[UIView dd_AnimateWithDuration:0.5 animations:^{
[self.container setTransform:CGAffineTransformIdentity];
[self.scrollView setContentOffset:CGPointMake(ScreenWidth * idx, 0) animated:NO];
[self.scrollView setPagingEnabled:YES];
} completion:^(BOOL finished) {
TransformApplied = NO;
}];
}
else
{
CGPoint anchor = CGPointMake((idx * ScreenWidth + ScreenWidth/2)/CGRectGetWidth(self.container.frame), 0.5f);
[self.container.layer setAnchorPoint:anchor];
CGPoint position = CGPointMake((anchor.x) * self.container.frame.size.width, self.container.layer.position.y);
[self.container.layer setPosition:position];
[UIView dd_AnimateWithDuration:0.5 animations:^{
[self.container setTransform:CGAffineTransformMakeScale(ScaleFactor, ScaleFactor)];
[self.scrollView setPagingEnabled:NO];
} completion:^(BOOL finished) {
TransformApplied = YES;
}];
}
However, now i've got to figure out a way to get rid of all the extra space in the scrollview without allowing the position of the container to change....
I have had a similar issue a long time ago about the position of a view. After a long research, I ended up with the UIView documentation. It says about transform and frame properties of a UIView with a warning:
Warning:
If the transform property is not the identity transform, the value of this property is undefined and therefore should be ignored.
Changing the frame rectangle automatically redisplays the receiver without invoking the drawRect: method. If you want the drawRect: method invoked when the frame rectangle changes, set the contentMode property to UIViewContentModeRedraw.
Changes to this property can be animated. However, if the transform property contains a non-identity transform, the value of the frame property is undefined and should not be modified. In that case, you can reposition the view using the center property and adjust the size using the bounds property instead.
So, the basic idea is that, you shouldn't rely on or change frame when your view's transform contains a non-identity transform.
And the more important idea, always give a chance to the official documentation before looking elsewhere.
I hope this helps.
I have an element in a UIView with a constraint that says it should always be 10 pixels from the bottom of the view. I am then attempting to animate this view's height so that it appears to slide down the screen. According to the constraint, the element should always be 10 pixels from the bottom of the view. This holds true when I add the view like so...
printView *vc = [self.storyboard instantiateViewControllerWithIdentifier:#"printView"];
[self addChildViewController:vc];
vc.view.frame = CGRectMake(0, 60, vc.view.frame.size.width, HEIGHT);
vc.view.layer.masksToBounds = FALSE;
[vc.view.layer setShadowOffset:CGSizeMake(0.0, 5.0)];
[vc.view.layer setShadowOpacity:0.8];
vc.view.layer.shadowColor = [[UIColor blackColor] CGColor];
vc.view.layer.shadowRadius = 8;
vc.view.clipsToBounds = TRUE;
[self.view insertSubview:vc.view aboveSubview:docWebView];
I can change HEIGHT to whatever I want and the element is always 10 pixels from the bottom of the view. The problem comes when I try to animate the height
printView *vc = [self.storyboard instantiateViewControllerWithIdentifier:#"printView"];
[self addChildViewController:vc];
vc.view.frame = CGRectMake(0, 60, vc.view.frame.size.width, 0);
vc.view.layer.masksToBounds = FALSE;
[vc.view.layer setShadowOffset:CGSizeMake(0.0, 5.0)];
[vc.view.layer setShadowOpacity:0.8];
vc.view.layer.shadowColor = [[UIColor blackColor] CGColor];
vc.view.layer.shadowRadius = 8;
vc.view.clipsToBounds = TRUE;
[self.view insertSubview:vc.view aboveSubview:docWebView];
[UIView animateWithDuration:5.0 animations:^{
vc.view.frame = CGRectMake(0, 60, vc.view.frame.size.width, 200);
[self.view setNeedsDisplay];
}];
The constraint is no longer honored and instead of the view sliding in with the element always 10 pixels from the bottom, it looks like the element is being uncovered because the element does not move with the view. I hope I am explaining this well enough. To put it another way, I'm going for the effect of a map being pulled down, but instead it looks like the map is already there and a piece of paper that is covering it is being pulled away. Thanks for your help.
When using constraints, you shouldn't be setting frames, you should be adjusting the constraints. When you initially set up your constraints, you should make an IBOutlet to the height constraint, and then animate its constant parameter in the animation block. If you had a height constraint called heightCon, you could do this:
[UIView animateWithDuration:5.0 animations:^{
self.heightCon.constant = 200
[self.view layoutIfNeeded];
}];
I'm not sure about your structure, that self.view might have to be vc.view instead.
After Edit:
This is the way to animate a height constraint, but I'm not sure that's what you want to do to accomplish the look you're after. I'm not really sure what to make of your last paragraph. If you're going for an effect of a map being pulled down, it seems like the bottom constraint needs to be either animated or eliminated.
I have a UIView at the bottom left of its superview, i.e.its frame is like
[myView setFrame:CGRectMake(0,superView.bounds.size.height-myViewHeight,myViewWidth,myViewHeight)];
I want to animate its size such that its bottom left point remains fixed at its position. I am not sure how to play with anchor point property of layers.
Currently I am increasing its size using the following lines of code.
[UIView animateWithDuration:0.2 animations:^{
[bottomLbl setFrame:CGRectMake(0, bottomView.bounds.size.height-250, 300, 250)];
This works fine but when I try to bring back to its original size, its bottom point gets lifted at the start of animation and settles down at the end of animation.
First define the point for the bottom left corner...
CGPoint bottomLeft = CGPointMake(0, 480); // this can be anything.
Then you need to define the sizes (big and small).
CGSize bigSize = CGSizeMake(280, 280);
CGSize smallSize = CGSizeMake(50, 50); // again, these can be anything.
Then animate them...
// create the rect for the frame
CGRect bigFrame = CGRectMake(bottomLeft.x, bottomLeft.y - bigSize.height, bigSize.width, bigSize.height);
CGRect smallFrame = CGRectMake(bottomLeft.x, bottomLeft.y - smallSize.height, smallSize.width, smallSize.height);
[UIView animateWithDuration:0.2
animations:^{
// set the rect onto the view
bottomLbl.frame = bigFrame;
// or
bottomLbl.frame = smallFrame;
}];
As long as you set the frame and the calculated end frames are correct and it's all done in one animation then the bottom left corner won't move.
If this doesn't help can you please post a video of what is happening (and all your animation code).
EDIT
[UIView animateWithDuration:0.2
delay:0.0
options:UIViewAnimationOptionBeginFromCurrentState
animations:^{
// set the rect onto the view
bottomLbl.frame = bigFrame;
// or
bottomLbl.frame = smallFrame;
}
completion:nil];