I'm trying to move a UIVIew across the screen. I don't want to use CoreAnimation because I need to be able to vary the velocity of the view in real-time.
At the moment I have the following hierarchy:
UIView
-- UIView (subview)
I'm sub-classing the parent view and adding an update method.
-(void) update: (float) dt {
float newX = _subView.transform.tx + dt * dxdt;
[_subView setTransform: CGAffineTransformMakeTranslation(newX, 0)];
}
The update method is called every frame and I was hoping that this would cause the sub view to be animated.
Unfortunately it doesn't move. I've tried:
[_subView setNeedsDisplay]
But it still doesn't work. There must be something I'm missing to force the view to re-draw.
Related
In facebook'a new app, Pages, when you swipe down the menu appears at the top. The animation I am trying to do is the animation when you tap the settings button which is when each cell moves to the left one at a time, but very smoothly. How can I achieve such an animation without using Facebook's pop engine in Objective C ?
Bear in mind that each cell is probably a custom subclass of UIView (i.e. not UITableViewCell or other apple class) so you will have to design your UI carefully.
The animation, however, is easily achievable using the UIView class. Apple's documentation is a good place to start to learn about animation.
What you want is something like:
NSTimeInterval delay = 0.2;
for (UIView *myView in myViewArray) {
[UIView animateWithDuration:0.5 delay:delay options:UIViewAnimationOptionCurveEaseInOut animations:^{
/*
* This is where you set the properties you want to animate.
* If you're using AutoLayout (i.e. NSLayoutConstraint) you need to set the constant property of the relevant constraint, not the view's frame property.
*/
} completion:nil];
delay += 0.2;
}
This will provide you with animations that occur one after the other (0.2 seconds apart).
I am trying to make a UITableView appear when a user taps on a button and disappear when the button is re-tapped.
I implemented the following code but nothing seems to appear when I tap the button.
- (IBAction)dropDown:(UIButton *)sender
{
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.6];
CGAffineTransform transfrom = CGAffineTransformMakeTranslation(0, 200);
self.markersTableView.transform = transfrom;
self.markersTableView.alpha = self.markersTableView.alpha * (-1) + 1;
[UIView commitAnimations];
}
What may potentially be the issue?
EDIT:
I was able to make the UITableView appear and disappear by adding self.markersTableView.hidden = YES; in viewDidLoad() and self.markersTableView.hidden = NO; in the IBAction method.
However, the table view disappears when I initially tap on the button as shown in the screenshot:
The fading of the rows is an indication it is moving down the screen, and then it disappears.
It only reappears when I re-tap on the UIButton the 2nd time.
Any clues?
Don't use a transform on your table view. That will make it LOOK like it's in a different position, but it won't respond to taps correctly.
Instead, use the newer UIView block-based animation methods and change the view's center.
The code might look like this (if you're NOT using auto-layout)
[UIView AnimateWithDuration: .2
animations: ^
{
CGPoint center = self.markersTableView.center;
center.y += 200;
self.markersTableView.center = center;
}
];
If you're using auto-layout, though, that won't work and you will need to animate the view's position using constraints.
From memory, here's an outline of how to do auto-layout based animations: You would create a vertical position constraint on your table view and connect the constraint to an IBOutlet in your view controller. In your animation code you change the constant of the constraint (the vertical position) and then in the animation block, send the view a needsLayout message.
I need to change the width of a subview depending on, say, available disk space. So I have a selector that's called upon the view controller's viewWillLayoutSubviews as such:
CGRect rect = self.usageView.bounds;
rect.size.width = self.someCalculatedwidth;
[self.usageView setFrame:rect];
[self.usageView setNeedsDisplay];
Really, I just want to change the width of the subview. It works if the view controller is the initial controller; however, if it is transitioned from, say, a Push Segue it stopped working. What happens is I'd see my desired width rendered for moment but then it gets changed to the original width as per its blueprint on the Storyboard.
The behavior feels like the iOS caches the original (storyboard) view in a block during the push segue animation, and upon completion it executes the block which doesn't have my calculations above; thereby overridden the desired view. Any idea?
There are two approaches.
The first approach is to circumvent the problem, with a side benefit of cool animation. Since I have no clue when or how many times or exactly how iOS enforces the auto-constraints, I simply delay my UIView modifications and smooth it out with animation. So I wrap view animation around the code in my selector:
[UIView animateWithDuration:.25 animations:^{
CGRect rect = self.usageView.bounds;
rect.size.width = self.someCalculatedwidth;
[self.usageView setFrame:rect];
[self.usageView setNeedsDisplay];
}];
Then I'd call my selector in my controller's viewDidAppear:animated:
[self performSelector:#selector(resetUsageView) withObject:self afterDelay:0.0];
Now most would say this is a cop-out or a kludge. And that's fair.
In the second approach I attack the root of the problem - auto layout/constraints. I add a Width constraint to my usageView in the storyboard, and connect its IBOutlet to my code.
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *usageViewWidthConstraint;
Then I modify the constraint as per the calculated width in my controller's viewWillAppear:animated:
[self.usageViewWidthConstraint setConstant:self.someCalculatedWidth];
Voila! A one liner.
Now what if I want animation given I got a taste of it from the first approach? Well, constraint changes are outside the realm of animation so basically I'd need a combination of the first and second approaches. I change the UIView's frame for animation, and modify the constraint as well to "set the record straight":
[UIView animateWithDuration:.25 animations:^{
CGRect rect = self.usageView.bounds;
rect.size.width = self.someCalculatedwidth;
[self.usageView setFrame:rect];
[self.usageViewWidthConstraint setConstant:self.someCalculatedWidth]; // <<<<
[self.usageView setNeedsDisplay];
}];
I'm working with a designer to build a simple game for iOS. We've been using storyboards to build the menu scenes.
We have custom view objects, which are composed of multiple subviews (multiple buttons, labels, etc.), which we'd like to animate/slide onscreen after the associated view controller has loaded.
How can I animate the position of these views, which have been built with Storyboards? I can't seem to figure out where in the ViewController lifecycle to implement the animation, as the x/y position specified in the storyboard always seems to override the animation I implement in viewDidLoad, or viewDidAppear, etc.
In a perfect world, my designer would be able to place the view in the desired 'target' position in the storyboard, and I'd then reposition it offscreen in code, and animate it onscreen back to the target position. That'd be easiest from a workflow perspective.
But we'd also settle for positioning the view offscreen on the storyboards, and then simply sliding it onscreen after the page has loaded. So for example, assuming that on the storyboard, viewIWantToAnimate has an initial frame position of (0, -100). And I want to slide it down to (0,0)...
Is there a simple way to do something like:
#interface MyGameViewController : UIViewController
{
__weak IBOutlet UIView *viewIWantToAnimate;
}
#implementation MyGameViewController
- (void)viewDidAppear:(BOOL)animated
{
[UIView animateWithDuration:0.1f
animations:^{
CGRect onScreenFrame = CGRectMake(0,0, viewIWantToAnimate.frame.size.width, viewIWantToAnimate.frame.size.height )
viewIwantToAnimate.frame = onScreenFrame;
}];
}
#end
I have this animation block:
[UIView animateWithDuration:10 animations:^{
CGPoint centerLeft;
centerLeft.x = self.leftMapPane.center.x - 100;
centerLeft.y = self.leftMapPane.center.y;
CGRect leftMove = CGRectMake(self.leftMapPane.frame.origin.x - 100, self.leftMapPane.frame.origin.x, self.leftMapPane.frame.size.width, self.leftMapPane.frame.size.height);
[self.leftMapPane setFrame:leftMove];
[self.leftMapPane setCenter:centerLeft];
}];
but for some reason although it gets inside the animation block, it doesn't move the mapViews I have around on the screen.
It should be noted that I'm not talking about moving the map but the view that contains the map, aka the mapview.
Any thoughts?
The animation doesn't work in viewDidLoad because at that point the views have been loaded into memory but have not been necessarily added to the view hierarchy. So when you try to animate the views it won't work.
Instead, put your animation call in viewDidAppear and it should work. This way you're sure the views you're animating are in the view hierarchy. I tried this in a sample project using your animation code and it worked fine.