Ok, this might sound simple, but somehow I can't get this function to work .
- (void)setViewMovedUp:(BOOL)movedUp {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
CGRect rect = self.view.frame;
NSLog(#"%f",self.view.frame.size.height);
if (movedUp)
{
NSLog(#"test Moved Up");
rect.origin.y += 60;
rect.size.height -= 300;
}
self.view.frame = rect ;
NSLog(#"%f after:",self.view.frame.size.height);
[UIView commitAnimations];
}
All the NSLogs are printing results fine and "Test Moved Up" appears so I know there is nothing wrong upstream .
This function is part of the implementation file of my MainViewController ( which manages the root view of my Window app ) .
I assume I have to call : self.view.frame, right ?
No error or warning appears, but it just doesn`t move despite printing out the logs correctly ..
Edit, this is the hierarchy in IB :
Edit again : I'm actually wondering if I'm allowed to move that view up, are we allowed to move views up if they are at the top of the hierarchy ? Then what would be revealed behind ?
Try removing just the three animation messages.
If it moves (I think it won't, but ...)
Try passing in #"moveup" as the first argument to beginAnimations
Try using setAnimationCurve
If it doesn't move
Is the view inside another view that sets a layout for this view?
Are you calling this inside the main thread (not in a background thread)
EDIT: Update
You shouldn't need to do this, but try
[self.view setNeedsDisplay];
If that doesn't work, try it on the window. Changing the frame is supposed to do this automatically.
Related
I am trying to make a simple application where there are 3 buttons. When user clicks any of the button, they are animated(moved) to their new positions! All this works from this code:
[UIView animateWithDuration:1.2
delay:0.1
options: UIViewAnimationCurveEaseOut
animations:^
{
//Moving the Sum (UIButton which will move through this animation)
CGRect frame = Sum.frame;
frame.origin.y = -20;
frame.origin.x = (-120);
Sum.frame = frame;
.....
....
}
completion:^(BOOL finished)
{
NSLog(#"Completed");
//adding subview after the animation is complete! newView is an example!
[self.view addSubview:newView];}];
The Problem is that once i add a subview to the main view, All buttons come back to their old position! meaning they weren't moved permanently.. how can i solve this? Plz help guys!
What happens when you add a view? A layout is performed. You could have done two mistakes
You are using autolayout.
If you are using autolayout, changing frames directly is not advised and a relayout will update the views to their original position using current constraints.
You are setting the frame position in layoutSubviews, viewWillLayout or viewDidLayout.
Check where you are setting the original position. Can the method be called multiple times?
You have save the X,Y Position of the new frame & then set this frame by coding.
I am trying to force EGORefreshTableHeaderView to update from the code. When I pull down everything works perfect and the TableView (root) gets refreshed. But I have a modal view where the user can subscribe to certain entities. When he subscribes to one the reload method in the first (root) table view gets triggered. This method establishes a connection to a server, loads some specific data based on the subscription, stores it in a CoreData DB and updates the TableView (root).
The problem is that when the user is only connected to 3G or Edge network the download, which is processed in an own thread, can take several seconds. To indicate the user that something happens I would like to show the EGORefreshTableHeaderView.
I found out that I can set the indent of the refresh view and manually show the loading icon but I was wondering if there is not an easier solution by just triggering a delegate or a method on the EGORefreshTableHeaderView?
Did you try using egoRefreshScrollViewDataSourceStartManualLoading?
Assuming your EGORefreshTableHeaderView instance is named _refreshTableHeaderView, then a call like:
[_refreshTableHeaderView egoRefreshScrollViewDataSourceStartManualLoading:self.tableView];
works for me...
So, it's been too long since I used this, and I forgot I applied the change myself...
I modified EGORefreshTableHeaderDelegate (declared in EGORefreshTableHeaderView.h) to add this additional protocol:
- (void)egoRefreshScrollViewDataSourceStartManualLoading:(UIScrollView *)scrollView;
And the implementation (in EGORefreshTableHeaderView.m):
- (void)egoRefreshScrollViewDataSourceStartManualLoading:(UIScrollView *)scrollView {
[self setState:EGOOPullRefreshLoading];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.2];
scrollView.contentInset = UIEdgeInsetsMake(60.0f, 0.0f, 0.0f, 0.0f);
[UIView commitAnimations];
if ([_delegate respondsToSelector:#selector(egoRefreshTableHeaderDidTriggerRefresh:)]) {
[_delegate egoRefreshTableHeaderDidTriggerRefresh:self];
}
}
Let me know if you need more help there.
(And thank-you enormego for the great work!)
Thanks to Reuven and his code I have improved it a little bit that it can also be used in an UIScrollView that is larger as the screen. Additionally, I have changed the deprecated commitAnimations to block animations.
#pragma mark - Manually refresh view update
- (void)egoRefreshScrollViewDataSourceStartManualLoading:(UIScrollView *)scrollView {
[self.refreshHeaderView setState:EGOOPullRefreshLoading];
//animating pull down scroll view
[UIView animateWithDuration:0.2
animations:^{
scrollView.contentInset = UIEdgeInsetsMake(60.0f, 0.0f, 0.0f, 0.0f);
scrollView.contentOffset = CGPointMake(0, -60.0f);
}
];
//triggering refreshview regular refresh
if ([self.tableView.delegate respondsToSelector:#selector(egoRefreshTableHeaderDidTriggerRefresh:)]) {
[self egoRefreshTableHeaderDidTriggerRefresh:self.refreshHeaderView];
}
}
I am animating UIView when user touches on custom dropdown to show picker View from bottom side.UIView contains Pickerview...so when I change it's frame to move upwards.I get what I want, but pickerView doesn't recognize touch !(see screenshot below)
code is like this
CGRect pickerFrame=self.pickerSheet.frame;
CGRect viewFrame=self.view.frame;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:SHEET_ANIMATION_DURATION];
//change Frame of View containing UIPickerView
pickerFrame.origin.y=202+animatedDistance;
viewFrame.origin.y-=animatedDistance;//animated distance is value by which view needs to move upward.
[self.pickerSheet setFrame:pickerFrame];
[self.view setFrame:viewFrame];
[UIView commitAnimations];
screenshot
first of all, ++please**, stop using this animation declaration, and bedin use new, block animation:
[UIView animateWithDuration:SHEET_ANIMATION_DURATION
delay:0
options:nil
animations:^{
pickerFrame.origin.y=202+animatedDistance;
viewFrame.origin.y-=animatedDistance;
}
completion:^(BOO f){
//any actions after animation ended
}];
Second, I think your problem is somewhere else. May by, you implementing your touches or picker wrong.
Please start using the new , better animation block , but I think there is something missing in your code , you need to put the code below :
UIViewAnimationOptionAllowUserInteraction
Put this code in options in the new animation block , or find a way to put it in the old animation block
I just upgraded my iPhone 4 from iOS 4.2.1 to 4.3.2, and to XCode 4.0.2, and I am encountering some bizarre issues with uiview animations. When I first launch my app, code like this executes perfectly:
[UIView beginAnimations:#"fadeAlphaIn" context:nil];
[UIView setAnimationDuration:0.5f];
viewClue.alpha = 1.0f;
[UIView commitAnimations];
But then, after dismissing a presenting and then dismissing a modal view by the standard method:
[self presentModalViewController:more animated:YES];
and
[self dismissModalViewControllerAnimated:YES];
the first animation no longer works. Instead of fading in, for example, the viewClue view simply jumps from alpha = 0 to alpha = 1. Similarly, other animations altering other views' frame property just force the frame to jump from the initial to final value without animation. These animations worked fine before the modal view was presented and dismissed.
I understand that others have experienced animation issues with the upgrade to iOS 4.3.2, but the way the modal view disrupts animation seems very odd. Has anyone else experienced this problem? Any ideas as to a solution? I'm thinking of just adding the modal view as a subview and animation it as it hides and appears, but using the standard modal view method would be much preferred.
Thanks for your help,
James
EDIT: Some more code showing how the app's map is animated
-(void) viewMapfunc
{
AudioServicesPlaySystemSound(soundID);
if(mapvisible){
[UIView animateWithDuration:0.5
delay:0.1
options:UIViewAnimationOptionAllowUserInteraction
animations:^{
map.frame = CGRectMake(0, 350, 320, 27);
mapscroll.frame = CGRectMake(0, 27, 320, 0);
}
completion:nil];
mapvisible = NO;
viewMapLabel.text = #"View Map";
}else {
[UIView animateWithDuration:0.5
delay:0.1
options:UIViewAnimationOptionAllowUserInteraction
animations:^{
map.frame = CGRectMake(0, 50, 320, 300);
mapscroll.frame = CGRectMake(0, 27, 320, 300);
}
completion:nil];
mapvisible = YES;
viewMapLabel.text = #"Hide Map";
}
}
Try to check two things:
Do you commit all started animations? I got all kinds of strange effects after not committing one of them.
Do any animations take place in the same time? Especially with the same view.
Whether any animations take place right after changing properties. Something like:
-
view.alpha = 1;
[UIView beginAnimations:…];
view.alpha = 0;
[UIView commitAnimations:…];
In this example, view will not change it's alpha value from 1 to 0. It will change it instantly. To start an animation you have to extract animations block to another method and call it with performSelectorInMainThread:withObject:afterDelay:. Delay can be even 0.
I solved it by restarting my animation in my UIView subclass:
override func willMove(toWindow newWindow: UIWindow?) {
if newWindow != nil {
spinner.startSpinning() // Restart any animation here
}
}
In the end, I just removed all modal views and implemented them in other ways. For some reason, using modal views messed up animations. Makes no sense, but removing them fixed the problem. If anyone can enlighten me as to why this is going on, it might be nice for memory concerns...
I had the same issue. The root of my trouble was that my animation was being triggered by a notification, and I was adding an observer on each viewWillAppear, but forgot to remove in viewDidDisappear (remember that iOS 6 no longer calls viewDidUnload reliably).
Essentially, I was calling my animation function twice in quick succession, which was causing the visible irregularity. Hopefully this helps someone out down the line!
I've managed to solve this same issue in my own application.
I noticed while debugging that my UIImageViews which I was animating had different memory addresses before and after I pushed my modal view controller(s). At no other time did these UIImageViews switch their memory addresses.
I thought this might have been the root of the issue and it seems I was right.
My client's code had been allocating/initializing my View Controller's UIImageViews in
-viewDidAppear instead of in -viewDidLoad. Thus, every time I launched and dismissed a modal view controller my UIImageViews I was animating would get reinitialized.
Check for yourself if your map object's memory address is changing before and after you launch your modals, and if it is be sure to move your initialization logic to a more proper section of your code.
Hope this helps you!
Dexter
I was using UIView animateWithDuration: and I solved it by not using the completion block. This is code from a subclassed UIView. In the view controller's viewWillAppear: I set self.shouldAnimate to YES, and in the view controller's viewWillDisappear: I set self.shouldAnimate to NO.
-(void)continueRotate {
if (self.shouldAnimate) {
[self rotateRadarView:self.radarInner];
}
}
-(void)rotateRadarView:(UIView *)view {
[UIView animateWithDuration:0.6 delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(continueRotate)];
[view setTransform:CGAffineTransformRotate(view.transform, M_PI_2)];
}completion:nil];
}
I'm seeing what appears to be interaction between separate animations, and I'd really appreciate any suggestions to eliminate this effect.
Basically:
I've got an iPhone app which includes a button 'a' on the root view. Tapping 'a' pushes a view on a navigation view controller stack, with a flip animation. The pushed view has a button to pop the view back to the root.
The underlying code:
- (IBAction)pushOneView{
TheAppDelegate *delegate = [[UIApplication sharedApplication] delegate];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationTransition: UIViewAnimationTransitionFlipFromRight
forView:delegate.navigationController.view cache:NO];
[delegate.navigationController
pushViewController:oneViewController animated:NO];
[UIView commitAnimations];
}
This seems to work fine, and the animation is quite smooth.
The root view also includes a subview ('panelView'), and another button, 'b'.
panelView can display either of two other subviews--tapping 'b' swaps between those subviews, with a spin animation. The code:
-(IBAction)swapPanels{
UIViewController *coming;
UIViewController *going;
float rotation;
if (self.aPanel.view.superview == nil) {
coming = aPanel;
going = bPanel;
rotation = 3.14;
}
else {
coming = bPanel;
going = aPanel;
rotation = -3.14;
}
// First half of spin
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.25];
CGAffineTransform swirlTransform = CGAffineTransformMakeRotation(rotation);
panelView.transform = swirlTransform;
[panelView setAlpha:0.1];
[UIView commitAnimations];
// Finish spin
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.25];
CGAffineTransform secondTransform =
CGAffineTransformRotate(swirlTransform, rotation);
panelView.transform = secondTransform;
[panelView setAlpha:1];
[UIView commitAnimations];
// Swap the panels
[going.view removeFromSuperview];
[panelView insertSubview:coming.view atIndex:0];
}
This also seems to work fine. Each of the swappable panels contains a picker and some labels.
However, I notice that the 'a' transition becomes slow and jerky if the 'b' transition has been executed before it.
In other words, if I start the app, run 'a' back and forth several times, it runs smoothly. Then exercise 'b' back and forth a few times. Then try 'a' again...'a' is now jerky, and will remain so until an app restart.
This is 100% repeatable. It is subtle using the simulator, but quite obvious on a device.
I have tested for leaks--none are shown by leaks tool.
If the animation is removed from the 'b' operation (just comment-out the animation steps), the effect on 'a' is not observed after the 'b' subview swap is exercised.
If the pickers are removed from the swappable panel nibs, the effect is similarly eliminated.
If the 'a' animation transition is set to cache, then after 'b' it does not stutter in the middle, but seems to ignore animating, simply swapping the view (this may be a matter of perception).
In case I'm not clear: I am NOT triggering these separate operations at the same time. Animation 'a', after 'b' has been executed--and completed--is not the same as if 'b' had never been executed. Is there clean-up I should be doing after an animation? Is my subview-swapping code flawed? Or...?
Thanks in advance for any suggestions.
You do have two overlapping animations in your 'b' section. When you create an animation using a begin / commit block, it gets handed off to a background thread to perform. In your 'b' section, the two animations that should be sequential are actually being fired off at nearly the same time. This can cause bizarre behavior, possibly like what you are seeing.
I'd recommend adding a callback in your first animation to a delegate method using code like the following:
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(rotationAnimationFinished:finished:context:)];
within your first animation block in 'b' (the "First half of spin" part). Then you need to define the callback method within your class, in this case
- (void)rotationAnimationFinished:(NSString *)animationID finished:(BOOL)finished context:(void *)context;
Within that delegate method, which will be called when the first part of the spin animation has finished, place the remaining code from your 'b' method (everything after your "Finish spin" comment).
By separating apart these animations, that might prevent the weirdness you're seeing.
Brad's answer does seem to have lead me to a solution: the symptoms continued to suggest that something about running those 'b' animations left the system in a different state than when it started. Finally, it occurred to me that the transform property of the panelView was left set after the 'b' animations...and perhaps that impacted further animations of a superview containing panelView.
So I set up method as Brad suggested, to execute once the 'b' animations were complete--but all that method does is set the panelView transform back to the default: CGAffineTransformIdentity:
(void)spinFinished:(NSString *)animationID finished:(BOOL)finished context:(void *)context {
panelView.transform = CGAffineTransformIdentity;
}
With this in place, post-'b' executions of the 'a' animation appear to be back to normal. So thanks again, Brad, for your help here. It is much appreciated.