I'm a little confused by UIView animateWithDuration.
I have a label placed at (224,93,152,39), centred horizontally in my storyboard. When I run viewDidLoad, I want it to slide up from centre vertically and horizontally to the position I've placed in my storyboard. So intuitively, I did this:
[UIView animateWithDuration:1.0 animations:^{
self.titleLabel.frame = CGRectMake(self.titleLabel.frame.origin.x,self.view.center.y, 0, 0);
}];
This actually did the opposite for me. The label slides from above the status bar to the desired position (224,93,152,39). I want it to start from centre of the viewController to the desired position (224,93,152,39).
I think I'm not getting something essential of the UIView animations. Would appreciate it if someone can point it out for me.
May be you can try by place the above code to viewDidAppear method
The frame you set in the animations block is the ending frame. Set the starting frame right before you call animateWithDuration if needed.
Related
I'm making this type of screen.
I've used 3 UIButton and programmatically gave them border. The little red line is a UIView. I've provided a constraint to UIView Equal Widths as Trending Button.
Now my question that when user taps the next button this UIView should move to the next one. View Controller is 600x600 and next button is at 200x0 so if I change the value of UIView to 200 that will be hard coded and it'll alter according to the screen size. I want it to be perfect and don't know any other way.UPDATE:I'm using AutoLayout so for this purpose I used [self.buttonBottomView setTranslatesAutoresizingMaskIntoConstraints:YES]; and when I run the app the buttons were messed up like in the screenshot. I've applied some constraints on buttons.
You can use NSLayoutConstraint ,change it's LeadingConstaint when you tap on the next button.
Code:
- (void)changeSelectedByTapView:(UIView *)tapView {
_currentSelectedView = tapView;
self.lineImageViewLeadingConstaint.constant = tapView.frameX;
self.lineImageViewWidthConstaint.constant = tapView.width;
[UIView animateWithDuration:0.5f animations:^{
[self.lineImageView.superview layoutIfNeeded];
}];
}
change frame of your UIView.
view.frame = CGRectMake(0+buttonWidth*i, y, width, height);
i is index which is 0 for Trending, 1 for Made by the fans and 2 for your rules.
Also when you change frame for your view, it is shown only on one button at a time.
I have a UILabel inside of a UITableViewCell. I am trying to animate the label moving to the right when the user taps the cell. I have this code:
CGRect otherFrame = cellLabel.frame;
otherFrame.origin.x +=50;
[UIView animateWithDuration:1.0f animations:^{
cellLabel.frame = otherFrame;
}];
The odd thing that's happening is that the label is jumping 50 pixels to the left and animating back to its origin (where it was before the action began).
I actually had this working earlier in the week and didn't have any trouble with it, and after scouring through the revision history, I can't figure out where I've gone wrong. I must be missing something stupid.
EDIT:
Based on the answer from Jakub, I found that this works:
[UIView animateWithDuration:0.01f animations:^{}
completion:^(BOOL finished)
{
CGRect otherFrame = cellLabel.frame;
otherFrame.origin.x += 50;
[UIView animateWithDuration:1.0f animations:^{
cellLabel.frame = otherFrame;
}];
}];
Oddly, if I move all of the logic into a completion handler that performs a new animation after the first one completes (without the first actually doing anything), everything animates properly. This is super hacky, and I'm not at all happy with it.
Can anyone think of what would cause the initial animation to move the frame to the negative offset of the intended destination, only to animate it back to its origin, and why triggering a new animation as the completion handler of an empty animation would work?
EDIT 2:
I am going to mark Duncan's answer as the right one because it pointed me in the right direction, but I am still baffled why/how these symptoms can happen:
The animation moves the frame to the negative offset of the
destination, then animates it back to the origin (rather than from
the origin to the destination)
Running an empty animation block but adding another animation to the first block's completion handler animates correctly
Info for the attempted answers:
I have to use auto layout for the project, and as far as I know, I
can't disable it for a single view
I am not putting anything onto a background thread. I didn't try specifically dispatching to the main thread, but I think I was already there. Isn't all visible UI always on the main thread? It was animating, just not as expected.
The reason I didn't go the route of changing constraints to begin with is that I am using prototype cells and IB doesn't let you create IBOutlets from prototype cells. There's a bit of work to walk a constraint list and detect a specific one, so I left the constraints blank and tried to animate the frame (and as I said, it was working earlier in the week -- and still worked when animating from an animation block's completion handler).
So the final solution was to add constraints to the container cell (the important one here being the leading), then to animate, I had to find the constraint:
NSLayoutConstraint *titleLeadingConstraint = nil;
for( NSLayoutConstraint *constraint in cellLabel.superview.constraints )
{
if( constraint.firstItem == cellLabel && constraint.firstAttribute == NSLayoutAttributeLeading )
{
titleLeadingConstraint = constraint;
}
}
Then set the constraint constant:
titleLeadingConstraint.constant = 55.0;
Then set the animation block:
[UIView animateWithDuration:1.0f animations:^{
[self.view layoutIfNeeded];
}];
This solution should be more future proof (and robust, reliable and stable) than moving the frame, but it turned out to be a fair amount of work in discovery.
Do you have auto layout set in your storyboard or XIB by mistake? (It is on by default). If so you either need to turn AutoLayout off or animate a constraint rather than manipulating your view's frame.
Where are you calling this code?
Try calling UIView animateWithDuration:... method on the main thread, in a
dispatch_async(dispatch_get_main_queue(), ^{
// Your animation here
});
If this method is not executed on the main thread, it usually jumps to the final stage of the animation.
You should reset the origin after animation.
I have a UIView "MainView" that initially appears as follows:
The gradient bar is part of MainView, the whitespace beneath is part of a Container View subview.
When the search button in top-right is tapped, I animate a searchBar from offscreen to be visible in the view:
I manage to do this by the following code:
CGRect currentViewFrame = self.view.bounds;
currentViewFrame.origin.y += searchViewHeight;
[UIView animateWithDuration:0.4
delay:0.0
usingSpringWithDamping:1.0
initialSpringVelocity:4.0
options:UIViewAnimationOptionCurveEaseInOut animations:^{
self.view.frame = currentViewFrame;
}
completion:^(BOOL finished)
{
}];
Visually, the result of this animation is perfect. The entire view shifts, and the searchBar is now on screen. However, the searchBar does not respond to interaction. Correct me if I'm wrong, but I expect this is because the MainView's frame no longer includes the screen area that the searchBar now occupies, so its effectively a gesture deadzone.
So this makes me think that instead of lazily animating the entire MainView down to accomodate the searchBar, I must instead individually translate all subviews of MainView one at a time. In this simple situation, that would not be a big problem, but I can envision a circumstance with tens of subviews making that completely unrealistic.
What is the best method to accomplish what I am trying to do? Is there a secret to animating entire views/subviews without having gesture deadzones? Thanks in advance!!
I'm trying to slide my main view controller view to the right when the user taps a button. I use this code:
[UIView animateWithDuration:1
delay:0
options:UIViewAnimationOptionBeginFromCurrentState
animations:^(void){ self.view.left = 300; }
completion:nil];
The result is that view.frame.origin.x does not take into account device orientation. If the screen is landscape left, then setting x = 300 does not move the view to the right, it moves it down. I could do a big switch statement to change the relevant parameter depending on orientation but I feel like I've done this before without having to resort to such shenanigans. Am I missing something obvious?
I've tried with no options, no difference.
I'm using a category on UIView so that I don't have to type out the entire CGRectMake explicitly. The results are the same if I do it with the full CGRectMake statement.
I had the same issue. Animating the view's bounds instead of the view's frame (I am assuming this is what the category is doing) worked for me.
I have a UISegmentedControl set up in my XIB. I want it to appear on viewDidLoad and if the user taps the area of the screen it's in, and then to disappear if the user taps it again or to fade out if the user leaves it alone.
In looking around for how to manage this I've found a lot of stuff about fading UIViews, but not as much on fading individual subviews, and little at all on fading elements in the XIB. I tried to adapt the UIView stuff but failed.
How can I make this work?
EDIT: Okay, I've got the appearance at viewDidLoad and the fade out working. But when the user taps the area where the UISegmentedControl is (now invisible because alpha=0), nothing happens. This is the code I'm using:
- (IBAction)tapInvisibleSegContr
//This is connected to the UISegmentedControl with the action Touch Up Inside. Until now, the segmented control has been at alpha=0 since fading after viewDidLoad.
{
self.segContrAsOutlet.alpha=1.0;
[self fadeMethodThatWorksInViewDidLoad];
NSLog(#"Yup, tapped.");
}
I'm not even getting the NSLog. I've got the action hooked up to the UISegmentedControl, with the action Touch Up Inside. What am I missing?
If it is resident in a xib, just put his alpha to 0, do the properly connections: an Outlet and an IBAction for value changed
Then in the viwDidLoad right after [super viewDidLoad] write:
[UIView animateWithDuration:1 animations:^{self.mySegOutlet.alpha = 1;}];
Inside the IBAction right after you code the answer before the last } write:
[UIView animateWithDuration:1 animations:^{self.mySegOutlet.alpha = 0;}];
This is the easiest method.
Bye
In the xib set your control's alpha to 0.0, then use UIView animation methods to animate its alpha to 1.0. For example:
[UIView animateWithDuration:1.0 animations:^{
self.segmentedControl.alpha = 1.0f;
}];
EDIT: To your problem with not getting the action called, try attaching it for the value changed control event - I don't think UISegmentedControl sends for touch up inside.