開門見山,先看效果圖:

自定義轉(zhuǎn)場動畫.gif
自定義 UIViewController Present 樣式,shrinking bubble 收縮和擴(kuò)張的泡沫。動畫來源于
https://github.com/andreamazz/BubbleTransition
對此進(jìn)行了一些改進(jìn):
1. 把 swift 源碼翻譯成 OC
2. 改進(jìn)了一些動畫機(jī)制,具體如下

BubbleTransition效果圖.gif
從它給的效果圖來看,升縮的效果非常贊 (~ ̄▽ ̄~) ——
但是。。
聰明的你可能已經(jīng)看見了,圖中的兩個 ViewController 背景就是純色,上面沒任何其他 View,所以顯得效果很贊。接下來我們看一下加上 View 的效果——

背景添加了一張圖片.gif
這就尷尬了 a( ̄3 ̄)a ——
利用 Reveal 我們看看 View 的層次結(jié)構(gòu)。

Reveal結(jié)果.png
中間那一層遠(yuǎn)大于375 x 667的 View 很引人注目呀 (#-.-)——
再來看看代碼:
//計(jì)算一些關(guān)鍵point和frame
CGPoint originalCenter = presentedControllerView.center;
CGSize originalSize = presentedControllerView.frame.size;
CGFloat lengthX = fmax(self.startPoint.x, originalSize.width - self.startPoint.x);
CGFloat lengthY = fmax(self.startPoint.y, originalSize.height - self.startPoint.y);
CGFloat offset = sqrt(lengthX * lengthX + lengthY * lengthY) * 2;
CGSize size = CGSizeMake(offset, offset);
//上圖中的大View,先縮小到最小,再用UIView的動畫變大,設(shè)置cornerRadius變成圓,然后漏出下面的VC的view
self.bubble = [[UIView alloc] initWithFrame:CGRectMake(0, 0, size.width, size.height)];
self.bubble.layer.cornerRadius = size.height/2.0f;
self.bubble.center = self.startPoint;
self.bubble.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.001, 0.001);
self.bubble.backgroundColor = self.bubbleColor;
[containerView addSubview:self.bubble];
//上層VC的View
presentedControllerView.center = self.startPoint;
presentedControllerView.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.001, 0.001);
presentedControllerView.alpha = 0;
[containerView addSubview:presentedControllerView];
[UIView animateWithDuration:self.duration animations:^{
self.bubble.transform = CGAffineTransformIdentity;
presentedControllerView.transform = CGAffineTransformIdentity;
presentedControllerView.alpha = 1;
presentedControllerView.center = originalCenter;
} completion:^(BOOL finished) {
[transitionContext completeTransition:finished];
}];
注釋中解釋了動畫原因。主要的原理是View的層級關(guān)系,通過上層 bubble 這個 View,慢慢變大,形成圓擴(kuò)大的動畫。但有一個前提是,下層的 View的背景色和bubble同色,混合之后,才能形成完整的動畫,一旦下層 View 有“噪點(diǎn)”,這個動畫就失效了。就像上面的gif展示的一樣。
改進(jìn)
既然原代碼是通過上下層 View 來實(shí)現(xiàn),那讓咱們換個思路,只需要修改一點(diǎn)點(diǎn)代碼就可以——
iOS不是還有一個好玩的東西,叫做 maskView 的嗎?
CGPoint originalCenter = presentedControllerView.center;
CGSize originalSize = presentedControllerView.frame.size;
CGFloat lengthX = fmax(self.startPoint.x, originalSize.width - self.startPoint.x);
CGFloat lengthY = fmax(self.startPoint.y, originalSize.height - self.startPoint.y);
CGFloat offset = sqrt(lengthX * lengthX + lengthY * lengthY) * 2;
CGSize size = CGSizeMake(offset, offset);
self.bubble = [[UIView alloc] initWithFrame:CGRectMake(0, 0, size.width, size.height)];
self.bubble.backgroundColor = [UIColor redColor];
self.bubble.layer.cornerRadius = size.height/2.0f;
self.bubble.center = self.startPoint;
self.bubble.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.001, 0.001);
//將上層 bubble 當(dāng)做下層 View 的 maskView
containerView.maskView = self.bubble;
presentedControllerView.center = originalCenter;
[containerView addSubview:presentedControllerView];
[UIView animateWithDuration:self.duration animations:^{
self.bubble.transform = CGAffineTransformIdentity;
} completion:^(BOOL finished) {
[transitionContext completeTransition:finished];
}];
Github鏈接:
https://github.com/Balzac646729740/WHBubbleTransition