You can find my test project here.
You say your plug view should fully, exactly cover the socket view. We need to worry about two things: the plug's layer position (layer.position
) and layer size (layer.bounds.size
).
By default, position
controls the center of the layer (and view) because the default anchorPoint
is (0.5, 0.5). If we set anchorPoint
to (0, 0), then position
controls the upper-left corner of the layer, and we always want that to be at (0, 0) in the socket's coordinate system. So by setting both anchorPoint
and position
to CGPointZero
, we can avoid worrying about animating layer.position
.
That just leaves us to animate layer.bounds.size
.
When you animate a view using UIKit animations, it creates instances of CABasicAnimation
under the hood. CABasicAnimation
is a subclass of CAAnimation
that adds (among other things) fromValue
and toValue
properties, specifying start and end values of the animation.
CAAnimation
conforms to the CAMediaTiming
protocol, which means it has a beginTime
property. When you create a CAAnimation
, it has a default beginTime
of zero. Core Animation changes that to the current time (see CACurrentMediaTime
) when it commits the current transaction.
But if the animation already has a non-zero beginTime
, Core Animation uses it as-is. If that beginTime
is in the past, then the animation is already partially (or even fully) completed when it first appears on-screen, and is drawn with the appropriate amount of progress already made. We can essentially “backdate” an animation.
So if we dig up the CABasicAnimation
controlling the socket's bounds.size
, and add it to the plug, the plug should animate in exactly the way we want. When we attach the animation to the plug, its beginTime
is the time it started animating the socket. So even though we're attaching it to the plug later, it will be perfectly synchronized with the socket. And since we want the plug and the socket to have the same size, the fromValue
and toValue
are also already correct.
In my test app, I made the socket pink and the plug blue. Each is a UIImageView
displaying an image with lines at the edges, so we can be sure that the views have the correct sizes at all times. Here's what it looks like in action:

There is a further twist. If you animate a view that's already animating, UIKit doesn't halt the earlier animation. It adds the second animation, and both animations run concurrently.
This works because UIKit uses additive animations. When you animate a view's width from 320 to 160, UIKit sets the width to 160 immediately, and adds an additive animation that goes from 160 to 0. At the start of the animation, the apparent width is 160+160=320, and at the end, the apparent width is 160+0=160.
When UIKit adds a second animation while the first is running, the values of both animations are added to the apparent value used to draw view on the screen. Here's the effect:

What this means for us is we have to look for all of the socket animations with a keyPath
of position.size
, and copy all of them to the plug. Here's the code in my test app:
- (IBAction)plugWasTapped:(id)sender {
if (self.plugView.superview) {
[self.plugView removeFromSuperview];
return;
}
self.plugView.frame = self.socketView.bounds;
[self.socketView addSubview:self.plugView];
for (NSString *key in self.socketView.layer.animationKeys) {
CAAnimation *rawAnimation = [self.socketView.layer animationForKey:key];
if (![rawAnimation isKindOfClass:[CABasicAnimation class]]) {
continue;
}
CABasicAnimation *animation = (CABasicAnimation *)rawAnimation;
if ([animation.keyPath isEqualToString:@"bounds.size"]) {
[self.plugView.layer addAnimation:animation forKey:key];
}
}
}
Here's the result with multiple simultaneous animations:

UPDATE
Getting the full view hierarchy of the plug view to animate as if it had been there in the first place is frankly too much work.
Here's one alternative:
- Lay out the plug view at the original size of the socket and create an image of it (the "begin image").
- Lay out the plug view at the final size of the socket and create an image of it (the "end image").
- Put a placeholder image view into the socket.
- Copy the size animation from the socket to the placeholder.
- Use the size animation to create a contents animation on the placeholder that crossfades its contents from the begin image to the end image.
- When the animation ends, replace the placeholder with the plug view.
Here's what it looks like:

In addition to the imperfection of the crossfade, this version doesn't handle multiple animations running simultaneously. You can find this under the crossfade tag in my repository (linked at the top).
Another approach is to just render the plug view at its final size and put that in the placeholder without a crossfade. It looks like this:

I think it looks better this way, and this version handles stacked animations. You can find this under the stretch-end-image tag in my repository.
Finally, there's an entirely different approach that I didn't implement. This will only apply to resizing animations that you create yourself—it won't work for the rotation animation created by the system on an orientation change. You can simply animate the bounds of your socket view yourself, with a timer, instead of using UIKit animation. WWDC 2012 Session 228: Best Practices for Mastering Auto Layout discusses this toward the end. He suggests using an NSTimer
but I think you'd be better off using a CADisplayLink
. If you take this approach, the plug view's subviews will all animate perfectly. It's a fair bit more work than using UIKit animations, but should be straightforward to implement.