I'm trying to write a custom UIButton
subclass that will "animate" during press and release.
When pressed, the button should "shrink" (toward its center) to 90% of its original size. When released, the button should "expand" to 105%, shrink again to 95% and then return to its original size.
Here's the code I've got right now:
#pragma mark -
#pragma mark - Touch Handling
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
[self animatePressedDown];
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesCancelled:touches withEvent:event];
[self animateReleased];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesEnded:touches withEvent:event];
[self animateReleased];
}
- (void)animatePressedDown {
NSLog(@"button.frame before animatedPressedDown: %@", NSStringFromCGRect(self.frame));
[self addShadowLayer];
CATransform3D ninetyPercent = CATransform3DMakeScale(0.90f, 0.90f, 1.00f);
[UIView animateWithDuration:0.2f
animations:^{
self.layer.transform = ninetyPercent;
}
completion:^(BOOL finished) {
NSLog(@"button.frame after animatedPressedDown: %@", NSStringFromCGRect(self.frame));
}
];
}
- (void)animateReleased {
[self.shadowLayer removeFromSuperlayer];
CATransform3D oneHundredFivePercent = CATransform3DMakeScale(1.05f, 1.05f, 1.00f);
CATransform3D ninetyFivePercent = CATransform3DMakeScale(0.95f, 0.95f, 1.00f);
[UIView animateWithDuration:0.1f
animations:^{
self.layer.transform = oneHundredFivePercent;
}
completion:^(BOOL finished) {
NSLog(@"button.frame after animateReleased (Stage 1): %@", NSStringFromCGRect(self.frame));
[UIView animateWithDuration:0.1f
animations:^{
self.layer.transform = ninetyFivePercent;
}
completion:^(BOOL finished) {
NSLog(@"button.frame after animateReleased (Stage 2): %@", NSStringFromCGRect(self.frame));
[UIView animateWithDuration:0.1f
animations:^{
self.layer.transform = CATransform3DIdentity;
self.layer.frame = self.frame;
}
completion:^(BOOL finished) {
NSLog(@"button.frame after animateReleased (Stage 3): %@", NSStringFromCGRect(self.frame));
}
];
}
];
}
];
}
Anyway, the above code works perfectly... some of the time. At other times, the button animation works as expected, but after the "released" animation, the final frame of the button is "shifted" up and left from its original position. That's why I have those NSLog
statements, to track exactly where the button's frame is during each stage of the animation. When the "shift" occurs, it happens somewhere between animatePressedDown
and animateReleased
. At least, the frame shown in animatePressedDown
is ALWAYS what I expect it to be, but the first value for the frame in animateReleased
is wrong frequently.
I can't see a pattern to the madness, though the same buttons in my app tend to behave correctly or incorrectly consistently from app run to app run.
I'm using auto layout for all of my buttons, so I can't figure out what the difference is to make one button behave correctly and another one change its position.