I got this warning:
'UIView' may not respond to 'addSubview:withAnimation:'
The line of code which produce that warning is this:
[self.masterView addSubview:self.detailImage withAnimation:def];
And my relevant code is like this:
ExUIViewAnimationDefinition *def = [[ExUIViewAnimationDefinition alloc] init];
def.type = ExUIAnimationTypeTransition;
def.direction = ExUIAnimationDirectionMoveUp;
[self.masterView addSubview:self.detailImage withAnimation:def];
[def release];
I looked on the UIView documentation, i thought addSubview may be deprecated, but it still like this.
Does any one know how to solve this warning? Thanx in advance.
addSubview is a method UIView will respond to. addSubview:withAnimation: is not a method UIView will respond to.
If you want to add a subview with a fade or something like that, try this:
self.detailImage.alpha = 0.0;
[self.masterView addSubview:self.detailImage];
[UIView animateWithDuration:0.3 animations:^{
self.detailImage.alpha = 1.0;
}];
To add a subview to a parent, call the addSubview: method of the parent view. This method adds the subview to the end of the parent’s list of subviews.
To insert a subview in the middle of the parent’s list of subviews, call any of the insertSubview:... methods of the parent view. Inserting a subview in the middle of the list visually places that view behind any views that come later in the list.
[self.masterView addSubView:self.def];
[def release];
This helped me to animate subview by sliding out from down of border of parent view
-(void) addAnimatadView:(UIView *) animatedView toView:(UIView *)aView {
CGRect frame = animatedView.frame;
float origin = frame.origin.y;
frame.origin.y = aView.frame.size.height;
[animatedView setFrame:frame];
[aView addSubview:animatedView];
frame.origin.y = origin;
[UIView animateWithDuration:0.4 animations:^{[animatedView setFrame:frame];}];
}
Just change frame origins as you want to reach free sliding
Related
so I have a very simple button that when clicked goes to fullscreen and when clicked again goes back to the same position it was initially in. For some reason it works perfectly without the animation. When I uncomment the animation part when I initially click the button it does nothing, the second time I click it slightly enlarges. The third time I click it animates slowly but back to it's smaller original size... Why is it animating the opposite way?
- (IBAction)viewImage1:(id)sender {
UIButton *btn = (UIButton*) sender;
if (btn.tag == 0)
{
CGRect r = [[UIScreen mainScreen] bounds];
/*[UIView animateWithDuration:0.5f delay:0.0f options:0 animations:^{*/
[sender setFrame: r];
/*}completion:nil];*/
btn.tag = 1;
}
else
{
btn.tag = 0;
[sender setFrame:CGRectMake(0,0,370,200)];
}
}
There are two solutions to your problem either of which will work:
Disable Autolayout. (discouraged)
You can do that in Interface Builder by opening the File Inspector
in the right pane and unchecking the respective check box.
However, if you want to use Autolayout for constraining other UI elements in your view (which is quite a good idea in most cases) this approach won't work which is why I would recommend the second solution:
Keep Autolayout enabled, create an outlet for your button in your view controller and set
self.myButton.translatesAutoresizingMaskIntoConstraints = YES;
in your view controller's viewDidLoad method.
You could also add layout constraints to your button and animate those. (This excellent Stackoverflow post explains how it's done.)
The reason for this tricky behavior is that once you enable Autolayout a view's frame is no longer relevant to the actual layout that appears on screen, only the view's layout constraints matter. Setting its translatesAutoresizingMaskIntoConstraints property to YES causes the system to automatically create layout constraints for your view that will "emulate" the frame you set, in a manner of speaking.
It is easier to do this with auto layout and constraints. Create an IBOutlet for the height constraint of your button call it something like btnHeight. Do the same for the width constraint call it something like btnWidth. Then create an IBAction like so:
- (IBAction)buttonPress:(UIButton *)sender {
UIButton *btn = (UIButton *) sender;
CGRect r = [[UIScreen mainScreen] bounds];
if (CGRectEqualToRect(btn.frame, CGRectMake(0.0, 0.0, 370, 200))) {
[UIView animateWithDuration:0.5 delay:0.0 options:0 animations:^{
self.btnHeight.constant = r.size.height;
self.btnWidth.constant = r.size.width;
[self.view layoutIfNeeded];
} completion:^(BOOL finished){
}];
}else{
[UIView animateWithDuration:0.5 delay:0.0 options:0 animations:^{
self.btnHeight.constant = 200.0;
self.btnWidth.constant = 370.0;
[self.view layoutIfNeeded];
} completion:^(BOOL finished){
}];
}
}
In my experience animating the frame of a UIButton does not work well, a, the only method, I'm aware of, is to use CGAffineTransformScale which will rasterize the title of the button and scale it as well.
I have two UIViews (My bad it is a UIView and a UIButton) which I am animating at the same time. I originally had a view and a containerView which would animate just fine and worked like a charm.
Now only one of my UIViews will move/animate in animateWithDuration even though through debugging the frame of the other view says that it is in a position it is not.
CGRect rect = self.toggle.frame;
CGRect tabRect = self.tabButton.frame;
rect.origin.x = rect.origin.x - rect.size.width;
NSLog(#"%f Before",tabRect.origin.x);
tabRect.origin.x = tabRect.origin.x - rect.size.width;
NSLog(#"%f After", tabRect.origin.x);
[UIView animateWithDuration:0.3 animations:^{ // animate the following:
self.toggle.frame = rect; // move to new location
self.tabButton.frame = tabRect;
}];
NSLog(#"%f AfterAnimation", tabButton.frame.origin.x);
The toggle view moves fine, but the tabButton view does not animate or move. The strange thing is that both the "After" and "AfterAnimation" debugging code returns the same value, which suggests the frame has indeed moved. Is there a specific reason that this will not work when toggle is a UIView when it would work as a UIContainerView?
Note that if I remove the line
self.toggle.frame = rect;
tabButton will animate correctly, but if I move toggle, tabButton will not move regardless of whether it is first in the animation block or second.
Edit: I have tried moving them into separate blocks and to change the center point rather than the frame, to no avail. It seems that if the toggle view moves, the tabButton will not move.
Edit 2: The pictorial evidence.{
In the following screenshots tabButton bg is green and toggle bg is red.
Above: Initial position (toggle is off-screen) correct position
Above: The problem in question toggle is correct tabButton is not
Above: When self.toggle.frame = rect is commented out (tabButton correct, toggle not)
}
Edit 3: It's even worse than I feared.{
I have done a few more tests and even if I take the toggle change out of the animation block to make it an instant thing, the tabButton will still not animate. This makes me think the tabButton may just fundamentally dislike the toggle view and/or myself so will not move just to spite me.
}
Edit 4:{
If I change the tabButton animation to tabButton.frame = CGRectMake(10,10,100,100) the View snaps instantly to that location and animates back to its original position in the same time as the animation duration.
}
I better add more bookkeeping/TLDR information in case things aren't clear.
toggle is an instance of ToggleDraw which is a subview of UIView which I created.
tabButton is a UIButton which is part of my IB viewController and a property of the class
Both toggle and tabButton are subviews of self.view
The animations will work individually with no modifications to the logic of the rects but will not work if they are animated at the same time
toggle animation seems to take precedence over tabButton animation regardless of the order
I had a problem with the animation of an UIView created in IB (the animation didn't start from the current position of the view, and ended in the initial position).
All worked fine after sending layoutIfNeeded() to the underlaying view before the animation block:
self.view.layoutIfNeeded()
UIView.animateWithDuration(0.5) { () -> Void in
...
I think it is not a problem about a UIView Animation. Maybe your toggle posiztion is related to your tabButton. For a try, your can set toggle frame to a rect lick (10, 10, 100,100), then check the result.
I've created an example of what you describe and everything seems to work fine. This is what I used:
UIView *toggle = [[UIView alloc] initWithFrame:CGRectMake(320, 64, 100, 100)];
[toggle setBackgroundColor:[UIColor redColor]];
[self.view addSubview:toggle];
UIButton *tabButton = [[UIButton alloc] initWithFrame:CGRectMake(220, 64, 100, 100)];
[tabButton setBackgroundColor:[UIColor greenColor]];
[self.view addSubview:tabButton];
CGRect rect = toggle.frame;
CGRect tabRect = tabButton.frame;
rect.origin.x = rect.origin.x - rect.size.width;
NSLog(#"%f Before",tabRect.origin.x);
tabRect.origin.x = tabRect.origin.x - rect.size.width;
NSLog(#"%f After", tabRect.origin.x);
[UIView animateWithDuration:1 animations:^{ // animate the following:
toggle.frame = rect; // move to new location
tabButton.frame = tabRect;
}];
What I can suggest is to make sure that the code is being ran on mainthread:
dispatch_async(dispatch_get_main_queue(), ^{
[UIView animateWithDuration:0.3 animations:^{
self.toggle.frame = rect; // move to new location
self.tabButton.frame = tabRect;
}];
});
Also take into account that the log you have after the animation code is incorrect as it won't run after the animation, but rather right next to asking for the animation.
If you want code to run after the animation you should use:
[UIView animateWithDuration:0.3 animations:^{
self.toggle.frame = rect; // move to new location
self.tabButton.frame = tabRect;
} completion:^(BOOL finished){
NSLog(#"Finished animating!");
}];
I have found a solution to the problem. If I initialise the UIButton (tabButton) programmatically rather than through the interface builder, both views will animate simultaneously.
This however seems very hacky to me, kind of like putting a bandaid over a missing foot and hoping it will sort itself out.
I could not work out the root cause of the problem but at least I could avoid the symptoms.
If anyone knows why the views would not animate when the button was made in the interface builder post an answer here, I am interested in knowing the reason behind this.
Thanks for your help everyone.
I have a UIView that I am trying to move up bit when that parent view controller comes onto the screen. I have been reading up on this and most I see seem to say to use the viewDidAppear method to make any visual adjustments to the layout. I have tried this and it doesn't seem to work. Nothing happens, and went I nslog the origin.y I get back -47,000, which I then maybe assume that something is not initialized yet. Here is what I have tried.
- (void) viewDidAppear:(BOOL)animated
{
// set the save view y postion
saveData.center = CGPointMake( 0.0f, 0.5f );
NSLog(#"This is the y %f", saveData.frame.origin.y);
NSLog(#"This is the center points on load %#", NSStringFromCGPoint(optionalData.center));
}
But if I do something like this where I add a delayed method call in the viewDidLoad method:
[self performSelector:#selector(moveSaveView) withObject:nil afterDelay:0.7f];
and have this, it works
- (void) moveSaveView
{
// set the save buttons y postion
[UIView animateWithDuration:0.5 delay:0.0 options:0 animations:^{
// Animate the alpha value of your imageView from 1.0 to 0.0 here
optionalData.alpha = 0.0f;
} completion:^(BOOL finished) {
// Once the animation is completed and the alpha has gone to 0.0, hide the view for good
optionalData.hidden = YES;
}];
// move the save button up
[UIView animateWithDuration:0.5
animations:^{saveData.center = CGPointMake( 160.0f, 280.5f );}];
saveData.center = CGPointMake( 160.0f, 280.5f );
}
Is this also an issue due to the fact that I am using auto layout? I would just like my view to start in the place I need it to, and not use some delayed call to make that happen.
Edit:
So I gave this a shot and came up with this to try and move my UIView:
- (void) viewDidAppear:(BOOL)animated
{
NSLog(#"this is the constraing %f", saveData.saveButtomConstraint.constant); // gives me 93 which is here its at.
saveData.saveButtomConstraint.constant = 32;
[saveData setNeedsUpdateConstraints];
[saveData layoutIfNeeded];
NSLog(#"this is the constraing %f", saveData.saveButtomConstraint.constant); // gives me 32 which is here its at.
}
The problem is that the view never moves on the screen. What am I missing? Also is it ok to post and edit like this, when its related to the same question? I'm still trying to get the hang of this form.
Yes, your problem is due to the fact you are using auto layout. Frame animation is not compatible with auto layout, so instead you need to animate the constraints on your view. Check out this answer for detailed info, this might also help too. Good luck!
Edit:
So it looks like you have added a property to your saveData UIView called saveButtomConstraint. This is good as it gives you access to that constraint. However are you sure that that constraint is actually a member of the [saveData constraints] array? Generally constraints in Interface Builder are added to the parent UIView. I think the problem is most likely are calling layoutIfNeeded on the wrong view, you need to call it on parent view of saveData, or possibly on the root view of the view controller, [self view].
My ViewController's View has several subviews. On the user's action I add more subviews to it, and try to modify the positions of all the subviews. Only the positions of the newly added subviews are changing, the old ones are not.
If I change the positions of the old subviews without adding the new ones to my View, everything works as expected.
I've also tried changing their sizes. That appears to be working. The problem is only with the position.
Anyone encountered a similar problem? Thanks in advance!
Edit:
I`ve tried by changing the center and by changing the origin of their frames.
[UIView animateWithDuration:3
delay:0
options:UIViewAnimationOptionCurveEaseInOut
animations:^{
for (UIView *view in self.oldSubviews) {
view.center = center1;
}
for (UIView *view in self.newSubviews) {
view.center = center2;
}
} completion:^(BOOL finished) {
}];
When the views in the newSubviews aren't added as subviews, everything is fine. I've printed the array of self.view.subviews and there is no visible difference between the new and the old subviews.
This is what I tried with the frame:
for (UIView *view in self.oldSubviews) {
CGRect frame = view.frame;
frame.origin = CGPointZero;
frame.size = CGSizeMake(150, 300);
view.frame = frame;
}
Their sizes are changed, but they are not moved to the upper left corner.
Ok, found the issue, i guess. I was doing some settings in the viewWillLayoutSubviews method. I did not know, it is called after you add some subviews. Thanks for the help
I have a simple UIView animation block. In the block, I only change the view's alpha, but the view's frame is also being animated! WTF?
Here's my code:
UIButton *button = [flowerViews objectAtIndex:index];
UIImageView *newGlowView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"grid_glow.png"]];
newGlowView.frame = CGRectMake(0, 0, 130, 130);
newGlowView.center = button.center;
newGlowView.alpha = 0.0;
[scrollView_ addSubview:newGlowView];
[scrollView_ sendSubviewToBack:newGlowView];
[UIView animateWithDuration:0.3 animations:^{
newGlowView.alpha = 1.0;
}];
As you see, I'm creating a new view and adding it to scrollView_. I'm setting the view's position and alpha before adding it to scrollView_. Once it's added, I have an animation block to animate the view's alpha from 0 to 1.
The problem is, the view's position is also being animated! As it fades in, it looks as if it's animating from an original frame of CGRectZero to the one I've assigned it.
Ostensibly, only properties set within the animation block should be animated, right? Is this a bug? Am I missing something?
Thanks!
Perhaps the whole thing being called from an animation block or maybe within an event that is within an animation block like the autorotate view controller delegate methods.