标签:
CGFloat offset = scrollView.contentOffset.y;
CATransform3D avatarTransform = CATransform3DIdentity;
CATransform3D headerTransform = CATransform3DIdentity;
在这里我们获取一个当前垂直偏移量`offset`,并初始化2个`CATransform3D`变量。
### 下拉
—
下拉动作的管理:
if (offset < 0) {
CGFloat headerScaleFactor = -(offset) / header.bounds.size.height;
CGFloat headerSizevariation = (header.bounds.size.height * (1.0 + headerScaleFactor) - header.bounds.size.height) / 2.0;
headerTransform = CATransform3DTranslate(headerTransform, 0, headerSizevariation, 0);
headerTransform = CATransform3DScale(headerTransform, 1.0 + headerScaleFactor, 1.0 + headerScaleFactor, 0);
header.layer.transform = headerTransform;
}
首先,我们检查`offset`是否为负数:用户在下拉的过程中,将会进入`Scrollview`的弹性区域。
剩下的代码就是简单的数学逻辑。
`Header`的扩大是因为它的上边缘固定于屏幕的顶部,而底部的图片在等比缩放。
`the transformation is made by scaling and subsequently translating to the top for a value equal to the size variation of the view. `实际上,移动`ImageView`图层的中点到顶部并同时缩放它,你可以获得相同的效果。
headerTransform = CATransform3DTranslate(headerTransform, 0, MAX(-offset_HeaderStop, -offset), 0);
这句代码非常简单。我们只需定义一个让`Header`在此停止移动的最小值。
让我感到羞愧的是我比较懒!所以我写死了一些数值,像`offset_HeaderStop`。其实,我们可以通过计算UI元素的位置来获取相同的效果。下次有空再改吧。
### 头像
—
`Avatar`的缩放与我们处理下拉的逻辑一样,只是在这种情况下,图片是到达底部而不是顶部。这段代码和上边的比较相似,除了减小缩放的比例为1.4。
// Avatar -----------
CGFloat avatarScaleFactor = MIN(offset_HeaderStop, offset) / avatarImage.bounds.size.height / 1.4;
CGFloat avatarSizevariation = (avatarImage.bounds.size.height * (1.0 + avatarScaleFactor) - avatarImage.bounds.size.height) / 2.0;
avatarTransform = CATransform3DTranslate(avatarTransform, 0, avatarSizevariation, 0);
avatarTransform = CATransform3DScale(avatarTransform, 1.0-avatarScaleFactor, 1.0-avatarScaleFactor, 0);
就像你看到的,当`Header`停止变化时,我们用`MIN`函数来使`Avatar`的缩放停止。
此时,我们根据当前`offset`设置最顶层的图层。除非`offset`小于等于`offset_HeaderStop`,最顶层的图层是`Avatar`,否则是`Header`。
if (offset <= offset_HeaderStop) {
if (avatarImage.layer.zPosition < header.layer.zPosition) {
header.layer.zPosition = 0;
}
} else {
if (avatarImage.layer.zPosition >= header.layer.zPosition) {
header.layer.zPosition = 2;
}
}
}
### 白色Label
—
这段代码是白色`Label`的动画:
// ------------ Label
CATransform3D labelTransform = CATransform3DMakeTranslation(0, MAX(-distance_W_LabelHeader, offset_B_LabelHeader - offset), 0);
headerLabel.layer.transform = labelTransform;
这里有2个令我感到羞愧的变量值:当`offset`等于`offset_B_LabelHeader`时,黑色的`username`标签刚到触碰到`Header`的底部。
distance_W_LabelHeader
是Header
底部与白色Label
终点之间的距离。
这个变换是通过此逻辑计算:黑色Label
触碰到Header
,白色Label
就会立即出现,并且到达Header
中点位置就停止移动。所以我们使用下面代码创建Y
值:
MAX(-distance_W_LabelHeader, offset_B_LabelHeader - offset)
最后一个效果是Header
的模糊。为了得到合适的解决方案,我用了3个不同的库… … 我也尝试过用OpenGL ES
创建基类,但实时更新模糊总是非常缓慢。
然后我意识到我可以对模糊仅仅计算一次,将不模糊和模糊的图片进行重叠,只是改变alpha
值。我非常确信,Twitter
就是这样做的。
在viewDidAppear
中,我们计算Header
的模糊值并隐藏它,设置alpha
值为0。
// Header - Blurred Image
headerBlurImageView = [[UIImageView alloc] initWithFrame:header.bounds];
headerBlurImageView.image = [[UIImage imageNamed:@"header_bg"] blurredImageWithRadius:10 iterations:20 tintColor:[UIColor clearColor]];
headerBlurImageView.contentMode = UIViewContentModeScaleAspectFill;
headerBlurImageView.alpha = 0.0;
[header insertSubview:headerBlurImageView belowSubview:headerLabel];
header.clipsToBounds = YES;
模糊视图是用过FXBlurView
实现的。
在scrollViewDidScroll:
方法中,我们只需根据offset
设置alpha
:
// ------------ Blur
headerBlurImageView.alpha = MIN(1.0, (offset - offset_B_LabelHeader) / distance_W_LabelHeader);
这个计算的背后逻辑是:alpha
最大值是1,当黑色Label
触碰到Header
时模糊效果开始出现,当白色到达最终位置时,也将停止继续模糊。
就这样!
我希望你喜欢这个教程。学习如何重现这种很棒的动画效果对我来说是很大的乐趣。
Swift代码:Download Source
OC代码:Download Source
标签:
原文地址:http://blog.csdn.net/keleyundou/article/details/51010694