Calling layoutIfNeeded inside UIView animation block cause subviews to move earlier - ios

I'm trying to create a custom callout bubble.
I have an animation block setting the scale transform of the bubble UIView:
self.view.transform = CGAffineTransformMakeScale(0, 0); // (1)
self.view.transform = CGAffineTransformIdentity; // (2)
I either start the bubble view with scale (0, 0) as in (1) and animate to Identity as in (2) inside the animation block, or the opposite, going from (2) to (1).
If I don't have the [self.view layoutIfNeeded]; in my animation block, going from (1) to (2) works fine as in:
But when going back from (2) to (1) without the [self.view layoutIfNeeded];, the subviews jump to the left before the animation is finished:
Now, if I do add the [self.view layoutIfNeeded]; the subviews animate with the bubble view, but with a sort of delay:
Either going from (1) to (2):
Or from (2) to (1):
I have already tried replacing all the top and leading subview's constraints with center constraints like in How do I adjust the anchor point of a CALayer, when Auto Layout is being used? and have also tried the layer transform solution (but this one breaks the layout constraints saying it can't satisfy all constraints).
Any ideas on how to solve my animation problem?
Thanks in advance.
UPDATE:
I'm updating the question with the actual method that I call on
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)annotationView
and
- (void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)annotationView
to present and dismiss my custom callout bubble (forget the Expanded state for now).
- (void)setCalloutState:(CalloutState)calloutState
animated:(BOOL)animated
annotationView:(MKAnnotationView *)annotationView
completion:(void (^)(BOOL finished))completion
{
if (self.view.superview == annotationView || !annotationView) {
} else {
// [self.view.layer removeAllAnimations];
[self.view removeFromSuperview];
self.view.transform = CGAffineTransformIdentity;
self.view.bounds = CGRectMake(0, 0, normalViewWidth, normalViewHeight);
self.view.transform = CGAffineTransformMakeScale(0, 0);
self.view.center = CGPointMake(annotationView.bounds.size.width / 2, 0);
[annotationView addSubview:self.view];
}
void (^animationBlock)(void) = ^{
self.view.transform = CGAffineTransformIdentity;
switch (calloutState) {
case CalloutStateHidden:
self.view.bounds = CGRectMake(0, 0, normalViewWidth, normalViewHeight);
self.view.transform = CGAffineTransformMakeScale(0, 0);
break;
case CalloutStateNormal:
self.view.bounds = CGRectMake(0, 0, normalViewWidth, normalViewHeight);
break;
case CalloutStateExpanded:
self.view.bounds = CGRectMake(0, 0, expandedViewWidth, expandedViewHeight);
break;
default:
break;
}
self.view.center = CGPointMake(annotationView.bounds.size.width / 2, 0);
[self.view layoutIfNeeded];
};
if (animated) {
// TODO: figure out why the first animateWithDuration is needed in this nested thing
[UIView animateWithDuration:0
delay:0
options:UIViewAnimationOptionBeginFromCurrentState
animations:NULL
completion:^(BOOL finished) {
[UIView animateWithDuration:1.3
delay:0
options:UIViewAnimationOptionBeginFromCurrentState
animations:animationBlock
completion:^(BOOL finished) {
if (finished) {
self.calloutState = calloutState;
// TODO: figure out how to end UIView animation instantly so we don't need the second condition at the if
// having a concurrency problem here
if (calloutState == CalloutStateHidden && self.view.superview == annotationView) {
[self.view removeFromSuperview];
}
self.editingEnabled = calloutState == CalloutStateExpanded;
}
if (completion) {
completion(finished);
}
}];
}];
// ---------------------------------------------------------------------------------
} else {
animationBlock();
self.calloutState = calloutState;
if (calloutState == CalloutStateHidden) {
[self.view removeFromSuperview];
}
self.editingEnabled = calloutState == CalloutStateExpanded;
if (completion) {
completion(YES);
}
}
}

This might help. As per Apple documentation -layoutIfNeeded forces layout early
- (void)setNeedsLayout;
- (void)layoutIfNeeded;
So, you can try setNeedsLayout. This should satisfy the first case you mentioned.

Related

UIImageView rotation + center change cause the image to blow

I am trying to do a UIImageView change every second.
The change can have one of the two:
- Rotation
- Location change
I am using the following:
This is the initialization code:
+(instancetype)newWithFrame:(CGRect)frame {
MySateliteView *v = [[[NSBundle mainBundle] loadNibNamed:#"Satelite" owner:self options:nil] objectAtIndex:0];
v.frame = frame;
v.lastLocation = [SateliteCoordinate new];
return v;
}
This is the full code for the view:
-(void)createSateliteViewFromLocation:(SateliteLocation *)location {
CGPoint center = [self createPointFromLocation:location];
MySateliteView *locationView;
for (MySateliteView *v in _satelites) {
if (v.tag == location.sateliteNumber.integerValue) {
locationView = v;
break;
}
}
if (!locationView) {
locationView = [MySateliteView newWithFrame:CGRectMake(center.x - 15, center.y - 15, 30, 30)];
locationView rotate:location.coordinates.degree];
locationView.tag = location.sateliteNumber.integerValue;
[_satelites addObject:locationView];
[UIView animateWithDuration:0.7 animations:^{
[self addSubview:locationView];
}];
} else {
if ([locationView needsNewCenter:location.coordinates]) {
[UIView animateWithDuration:0.2 animations:^{
locationView.bounds = CGRectMake(0, 0, 30, 30);
locationView.center = center;
locationView.superview.clipsToBounds = YES;
}];
}
if ([locationView needsRotate:location.coordinates]) {
[locationView rotate:location.coordinates.degree];
}
}
}
For some reason, once the center is changed with a rotation already applied, the image is getting larger!
Anyone have any idea why and what I can do?
Thanx!
The frame is getting larger because you have constraints in a view and you're messing around with the center manually. You shouldn't mix auto layout and manual layout in this way. I'd recommend either:
Remove the constraints and do all your view layout manually by overriding layoutSubviews and drawRect: as appropriate while continuing to keep the code you already have.
Interact with the constraints instead of the frame/center/bounds. You can create an IBOutlet from the constraints in the xib so you can modify their values. You can override the system provided updateConstraints method in your view to ensure constraints are provided appropriately.
An example of updating the constraints to move your view might look like this:
[UIView animateWithDuration: .7, animations: ^{
self.constraint1.constant = 23;
[NSLayoutConstraint deactivateConstraints: #[self.constraint2]];
[self layoutIfNeeded];
}];

UIView jumps down at beginning

I need to change UIView position on scroll of tableview. When i change the frame size of UIView in the animation block it goes down and than move to correct position. Please look at my code.
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGPoint scrollVelocity = [_collectionViewLeaderboard.panGestureRecognizer velocityInView:_collectionViewLeaderboard.superview];
if (scrollVelocity.y > 0.0f){
NSLog(#"going down");
[UIView animateWithDuration:0.3f
animations:^ {
_headerview.frame = CGRectMake(0, 0, _headerview.frame.size.width, _headerview.frame.size.height);
_headerviewSecond.frame = CGRectMake(0, _headerview.frame.size.height, _headerviewSecond.frame.size.width, _headerviewSecond.frame.size.height);
self.collectionViewLeaderboard.frame = CGRectMake(self.view.frame.origin.x, _headerviewSecond.frame.size.height+_headerview.frame.size.height, self.view.frame.size.width, self.view.frame.size.height);
frameconditon = _headerview.frame;
} completion:^ (BOOL completed) {
}];
}
else if (scrollVelocity.y < 0.0f){
NSLog(#"going up");
//CGAffineTransform transform = CGAffineTransformMake(1, 0, 0, 1, _headerview.frame.origin.x, _headerview.frame.origin.y);
[UIView animateWithDuration:5.0 animations:^{
NSLog(#"test");
_headerview.frame = CGRectMake(0, -(_headerview.frame.size.height), _headerview.frame.size.width, _headerview.frame.size.height);
_headerviewSecond.frame = CGRectMake(0, (_headerview.frame.size.height)-40, _headerviewSecond.frame.size.width, _headerviewSecond.frame.size.height);
} completion:^(BOOL finished) {
}];
self.collectionViewLeaderboard.frame = CGRectMake(self.view.frame.origin.x, _headerviewSecond.frame.size.height, self.view.frame.size.width, self.view.frame.size.height);
}
}
headerview should move to top of view and it work but when i run it first time, it goes down and back to correct postion. How will i change constraints at the time of scrolling.
For constraint based views try to animate through changing constraints constant property using an outlet.

MKAnnotationView drag state ending animation

I'm using the custom MKAnnotationView animations provided by Daniel here: Subclassing MKAnnotationView and overriding setDragState but I run into an issue.
After the pin drop animation, when I go to move the map the mkannotationview jumps back to its previous location before the final pin drop animation block is called.
It seems to me that dragState=MKAnnotationViewDragStateEnding is being called before the animation runs? How can I get around this issue and set the final point of the mkannotationview to be the point it's at when the animation ends?
#import "MapPin.h"
NSString *const DPAnnotationViewDidFinishDrag = #"DPAnnotationViewDidFinishDrag";
NSString *const DPAnnotationViewKey = #"DPAnnotationView";
// Estimate a finger size
// This is the amount of pixels I consider
// that the finger will block when the user
// is dragging the pin.
// We will use this to lift the pin even higher during dragging
#define kFingerSize 20.0
#interface MapPin()
#property (nonatomic) CGPoint fingerPoint;
#end
#implementation MapPin
#synthesize dragState, fingerPoint, mapView;
- (void)setDragState:(MKAnnotationViewDragState)newDragState animated:(BOOL)animated
{
if(mapView){
id<MKMapViewDelegate> mapDelegate = (id<MKMapViewDelegate>)mapView.delegate;
[mapDelegate mapView:mapView annotationView:self didChangeDragState:newDragState fromOldState:dragState];
}
// Calculate how much to life the pin, so that it's over the finger, no under.
CGFloat liftValue = -(fingerPoint.y - self.frame.size.height - kFingerSize);
if (newDragState == MKAnnotationViewDragStateStarting)
{
CGPoint endPoint = CGPointMake(self.center.x,self.center.y-liftValue);
[MapPin animateWithDuration:0.2
animations:^{
self.center = endPoint;
}
completion:^(BOOL finished){
dragState = MKAnnotationViewDragStateDragging;
}];
}
else if (newDragState == MKAnnotationViewDragStateEnding)
{
// lift the pin again, and drop it to current placement with faster animation.
__block CGPoint endPoint = CGPointMake(self.center.x,self.center.y-liftValue);
[MapPin animateWithDuration:0.2
animations:^{
self.center = endPoint;
}
completion:^(BOOL finished){
endPoint = CGPointMake(self.center.x,self.center.y+liftValue);
[MapPin animateWithDuration:0.1
animations:^{
self.center = endPoint;
}
completion:^(BOOL finished){
dragState = MKAnnotationViewDragStateNone;
if(!mapView)
[[NSNotificationCenter defaultCenter] postNotificationName:DPAnnotationViewDidFinishDrag object:nil userInfo:[NSDictionary dictionaryWithObject:self.annotation forKey:DPAnnotationViewKey]];
}];
}];
}
else if (newDragState == MKAnnotationViewDragStateCanceling)
{
// drop the pin and set the state to none
CGPoint endPoint = CGPointMake(self.center.x,self.center.y+liftValue);
[UIView animateWithDuration:0.2
animations:^{
self.center = endPoint;
}
completion:^(BOOL finished){
dragState = MKAnnotationViewDragStateNone;
}];
}
}
- (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event
{
// When the user touches the view, we need his point so we can calculate by how
// much we should life the annotation, this is so that we don't hide any part of
// the pin when the finger is down.
fingerPoint = point;
return [super hitTest:point withEvent:event];
}
#end
I had the same problem, especially under iOS 8. After many hours of testing I believe that iOS keeps track of where it thinks self.center of the annotation is during the time that the state is MKAnnotationViewDragStateDragging. You need to use extreme caution if you animate self.center when handling MKAnnotationViewDragStateEnding. Read that as "I couldn't get that to work, ever."
Instead, I kept Daniel's original code when handling states MKAnnotationViewDragStateStarting and MKAnnotationViewDragStateCanceling, I animated self.center. When handling MKAnnotationViewDragStateEnding I animated self.transform instead of self.center. This maintains the actual location of the annotation and just changes how it is rendered.
This works well for me running either iOS 7.1 and iOS 8.0. Also fixed a bug in hitTest, and added some code to reselect the annotation after dragging or canceling. I think that is the default behavior of MKPinAnnotationView.
- (void)setDragState:(MKAnnotationViewDragState)newDragState animated:(BOOL)animated
{
if(mapView){
id<MKMapViewDelegate> mapDelegate = (id<MKMapViewDelegate>)mapView.delegate;
[mapDelegate mapView:mapView annotationView:self didChangeDragState:newDragState fromOldState:dragState];
}
// Calculate how much to lift the pin, so that it's over the finger, not under.
CGFloat liftValue = -(fingerPoint.y - self.frame.size.height - kFingerSize);
if (newDragState == MKAnnotationViewDragStateStarting)
{
CGPoint endPoint = CGPointMake(self.center.x,self.center.y-liftValue);
[UIView animateWithDuration:0.2
animations:^{
self.center = endPoint;
}
completion:^(BOOL finished){
dragState = MKAnnotationViewDragStateDragging;
}];
}
else if (newDragState == MKAnnotationViewDragStateEnding)
{
CGAffineTransform theTransform = CGAffineTransformMakeTranslation(0, -liftValue);
[UIView animateWithDuration:0.2
animations:^{
self.transform = theTransform;
}
completion:^(BOOL finished){
CGAffineTransform theTransform2 = CGAffineTransformMakeTranslation(0, 0);
[UIView animateWithDuration:0.2
animations:^{
self.transform = theTransform2;
}
completion:^(BOOL finished){
dragState = MKAnnotationViewDragStateNone;
if(!mapView)
[[NSNotificationCenter defaultCenter] postNotificationName:DPAnnotationViewDidFinishDrag object:nil userInfo:[NSDictionary dictionaryWithObject:self.annotation forKey:DPAnnotationViewKey]];
// Added this to select the annotation after dragging.
// This is the behavior for MKPinAnnotationView
if (mapView)
[mapView selectAnnotation:self.annotation animated:YES];
}];
}];
}
else if (newDragState == MKAnnotationViewDragStateCanceling)
{
// drop the pin and set the state to none
CGPoint endPoint = CGPointMake(self.center.x,self.center.y+liftValue);
[UIView animateWithDuration:0.2
animations:^{
self.center = endPoint;
}
completion:^(BOOL finished){
dragState = MKAnnotationViewDragStateNone;
// Added this to select the annotation after canceling.
// This is the behavior for MKPinAnnotationView
if (mapView)
[mapView selectAnnotation:self.annotation animated:YES];
}];
}
}
- (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event
{
// When the user touches the view, we need his point so we can calculate by how
// much we should life the annotation, this is so that we don't hide any part of
// the pin when the finger is down.
// Fixed a bug here. If a touch happened while the annotation view was being dragged
// then it screwed up the animation when the annotation was dropped.
if (dragState == MKAnnotationViewDragStateNone)
{
fingerPoint = point;
}
return [super hitTest:point withEvent:event];
}

Resize views on click with animation

I'm trying to make a user interface that animates when I click on it.
This is my sketch:
It starts with the mapview as small as on the left sketch. The rest is filled with a tableview. Now when I click on the map view it slides to the bottom like on the right sketch so the mapview fills the most off the screen. Ans visa versa when I click on the small Tableview.
How can I achieve this?
I thought off creating a View and then add mapview and tableview as subviews, but then I don't know how to animate that. Did some real simple animations until now.
Can someone point me in the right direction?
NSNumber isMapExpanded = 0;
- (void) expandMap
{
[UIView animateWithDuration:1.0
delay:0.2
options:nil
animations:^{
if([isMapExtended integerValue] == 0)
{
mapview.frame = CGRectMake(mapview.frame.origin.x, mapview.frame.origin.y, mapview.frame.size.width, mapview.frame.size.height + heightTobeExpanded);
tableView.frame = CGrectMake(tableView.frame.origin.x, tableView.frame.origin.y - heightTobeExpanded, tableView.frame.size.width, tableView.frame.size.height + heightTobeExpanded);
}
else if([isMapExtended integerValue] == 1)
{
mapview.frame = CGRectMake(mapview.frame.origin.x, mapview.frame.origin.y, mapview.frame.size.width, mapview.frame.size.height - heightTobeExpanded);
tableView.frame = CGrectMake(tableView.frame.origin.x, tableView.frame.origin.y + heightTobeExpanded, tableView.frame.size.width, tableView.frame.size.height - heightTobeExpanded);
}
}
completion:nil];
}
something along the lines of:
[UIView animateWithDuration:1.0
delay:0
options:nil
animations:^{
map.frame = CGRectMake(0,0,newheight,320);
table.frame = CGrectMake(0,newheight,screenheight-newheight, 320);
}
completion:nil];
you can call something like that in your click method. this is just an example - you should not use hardcoded numbers in your application :)
Please try this code:-
[UIView beginAnimations:#"Expand MApview" context:nil];
[tblView setFrame:CGRectMake(0, self.view.frame.size.height-50, tblView.frame.size.width,tblView.frame.size.height)];
[mapview setFrame:CGRectMake(0,0,mapview.frame.size.width,self.view.frame.size.height-50)];
[UIView setAnimationDelay:2];
[UIView commitAnimations];
As you already stated, put both the map and the table in a superview.
On click, you may use the following :
[UIView animateWithDuration:0.5 animations:^{
map.frame = CGRectMake(x,y,width,newHeight); //Set the frame to be with the new map height
tableView.frame = CGRectMake(x,NewYCoordinate,width,height); //Move the tableView down
}];
- (void) changeFrameBetweenMapAndTable
{
[UIView animateWithDuration:1.0
delay:0.5
options:nil
animations:^{
CGRect mapRect = mapview.frame;
mapview.frame = tableView.frame;
tableView.frame = mapRect;
}
completion:nil];
}

UIView block animation not beginning from current state

I'm trying to animate a some subviews of a subview of an annotation view.
So, to be more clear, the gray pin is my annotation view, which has an invisible subview, and this subview contains those 4 colored circle views.
annotation view
| invisible view (called typeSelectionView)
| yellow view (called typeButton)
| blue view (called typeButton)
| green view (called typeButton)
| red view (called typeButton)
First the circles are not visible (transform scale (0, 0) and their center at the head of the gray pin), then, when I select the gray pin, those circles come from the pin head growing and moving to their original position (the one on the picture above).
When I deselect the pin, the opposite animation happens.
And when I select and deselect (or the opposite) before the animation is finished, it changes the way it was going (if it was growing it shrinks) reverting the animation in the middle. That is why I need the UIViewAnimationOptionBeginFromCurrentState.
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)annotationView
{
// in case the typeSelectionView was already being showed by another annotationView
if (self.typeSelectionView.superview != annotationView) {
[self.typeSelectionView removeFromSuperview];
[self.typeSelectionView showTypeButtons:NO animated:NO completion:NULL];
}
[annotationView addSubview:self.typeSelectionView];
[self.typeSelectionView showTypeButtons:YES animated:YES completion:NULL];
}
- (void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)annotationView
{
if (self.typeSelectionView.superview) {
[self.typeSelectionView showTypeButtons:NO
animated:YES
completion:^(BOOL finished) {
if (finished) {
[self.typeSelectionView removeFromSuperview];
}
}];
}
}
- (void)showTypeButtons:(BOOL)show animated:(BOOL)animated completion:(void (^)(BOOL))completion
{
void (^block)(void) = ^{
for (int i = 0; i < self.typeButtons.count; i++) {
TypeButton *typeButton = self.typeButtons[i];
if (show) {
typeButton.center = [self _typeButtonCenterForIndex:i numberOfButtons:self.typeButtons.count];
typeButton.transform = CGAffineTransformIdentity;
} else {
typeButton.center = CGPointMake(viewWidth / 2, viewheight + 5); // pin head center
typeButton.transform = CGAffineTransformMakeScale(0, 0);
}
}
};
if (animated) {
[UIView animateWithDuration:0.5
delay:0
options:UIViewAnimationOptionBeginFromCurrentState
animations:block
completion:^(BOOL finished) {
if (completion) {
completion(finished);
}
}];
} else {
block();
if (completion) {
completion(YES);
}
}
}
So far no problem, but when one gray pin is displaying the typeSelectionView (like in the picture above) and then I select another pin, it's like this part:
if (self.typeSelectionView.superview != annotationView) {
[self.typeSelectionView removeFromSuperview];
[self.typeSelectionView showTypeButtons:NO animated:NO completion:NULL];
}
did nothing.
The 4 circles simple jump from one pin to the other without any animation.
What I would expect is that the [self.typeSelectionView showTypeButtons:NO animated:NO completion:NULL]; set those buttons to be "hidden" (scale (0, 0) and center in the head of the pin) without any animation (because the invisible view doesn't have a superview anymore, so they are not even showing), and then when I add the typeSelectionView to the new annotationView with [annotationView addSubview:self.typeSelectionView];, I animate the circles to their original position again with [self.typeSelectionView showTypeButtons:YES animated:YES completion:NULL];.
Btw, doing [typeButton.layer removeAllAnimations] at the beginning of showTypeButtons:animated:completion: does nothing.
How do I solve this?
Thanks in advance.
EDIT: (BONUS if someone can explain that to me... and help me solve it) =)
Suppose the circles are showing like in the picture above, then this code:
NSLog(#"type selected");
[self.typeSelectionView showTypeButtons:NO
animated:YES
completion:^(BOOL finished) {
NSLog(#"finisheddddd: %d", finished);
}];
[self.typeSelectionView showTypeButtons:NO
animated:YES
completion:^(BOOL finished) {
NSLog(#"finished: %d", finished);
}];
generates the following output:
type selected
finished: 1
finisheddddd: 1
So the second animation finishes first and both animations finish with finished == YES.
Also the second animation (which finishes first) finishes instantly and not after the end of the animation time.
O.o
Check the code I wrote but not tested. Please experiment with it to get your result
- (void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)annotationView
{
if (self.typeSelectionView.superview)
{
[self.typeSelectionView showTypeButtons:NO
animated:YES
completion:^(BOOL finished) {
if (finished) {
[self.typeSelectionView removeFromSuperview];
}
}];
}
}
- (void)showTypeButtons:(BOOL)show animated:(BOOL)animated completion:(void (^) (BOOL))completion
{
[UIView animateWithDuration:(animated) ?0.5f : 0.0f
delay:(self.animationStarted)? 0.5 : 0.0
options:UIViewAnimationOptionBeginFromCurrentState
animations:^{
self.animationStarted = YES;
[self setButtonVisible:show];
}
completion:^(BOOL finished) {
self.animationStarted = NO;
if (completion) {
completion(finished);
}
}];
}
-(void)setButtonVisible:(BOOL)visible
{
[self.typeButtons enumerateObjectsUsingBlock:^(TypeButton typeButton, NSUInteger idx, BOOL *stop) {
if (visible)
{
typeButton.center = [self _typeButtonCenterForIndex:idx numberOfButtons:self.typeButtons.count];
typeButton.transform = CGAffineTransformIdentity;
}
else
{
typeButton.center = CGPointMake(viewWidth / 2, viewheight + 5); // pin head center
typeButton.transform = CGAffineTransformMakeScale(0, 0);
}
}];
}
Turns out the problem is that when I set my typeButtons non-animated, they are not redraw instantly, so they don't change their current state, so what happens is:
one mapView:didSelectAnnotationView: method call:
- show the buttons animated
***redraw cycle here***
another mapView:didSelectAnnotationView: method call:
- hide the buttons non-animated
(no redraw cycle here, so buttons are still showing)
- show the buttons animated
So I came up with this shitty solution:
- (void)showTypeButtons:(BOOL)show animated:(BOOL)animated completion:(void (^)(BOOL))completion
{
void (^block)(void) = ^{
for (int i = 0; i < self.typeButtons.count; i++) {
TypeButton *typeButton = self.typeButtons[i];
if (show) {
typeButton.center = [self _typeButtonCenterForIndex:i numberOfButtons:self.typeButtons.count];
typeButton.transform = CGAffineTransformIdentity;
} else {
typeButton.center = CGPointMake(viewWidth / 2, viewheight + 5); // pin head center
typeButton.transform = CGAffineTransformMakeScale(0, 0);
}
}
};
if (animated) {
[UIView animateWithDuration:0.5
delay:0
options:self.typeButtonsChangedWithoutAnimation ? 0 : UIViewAnimationOptionBeginFromCurrentState
animations:block
completion:^(BOOL finished) {
if (completion) {
completion(finished);
}
}];
self.typeButtonsChangedWithoutAnimation = NO;
} else {
self.typeButtonsChangedWithoutAnimation = YES;
block();
if (completion) {
completion(YES);
}
}
}
Without the UIViewAnimationOptionBeginFromCurrentState, the animation starts from its actual state and not from its draw state.
One solution that I found, but did not work was: What is the most robust way to force a UIView to redraw?
Even if it did work, I wouldn't want it either...
Btw, I'm not gonna accept this answer, because it sucks.
It does not actually solve my question, which is to change the current state, not pass through it.
I'm just posting it in case someone sees and gets an idea of how to actually solve my original question.

Resources