#######首先申明一下:本篇内容不涉及到分段选择( 以下称为:segmentView)功能的实现,仅仅只是对分段选择的渐变效果进行讨论
最近双十一,双十二轮番轰炸,不知道又要有多少小伙伴剁手吃土了。当然,我属于一个例外,因为我老婆帮做了这件事。在我查看我老婆购买的东西的时候,无意间看到淘宝 APP,店铺首页的 segmentView 的动画效果
然后就想着也来实现一下这个效果,因此也就有了这篇文章。
先看下,我实现的效果图:
简单说一下效果:随着 tableView 上滑,当segmentView接触到导航栏的时候,图片逐渐透明消失,文字逐渐变大;随着 tableView 下滑,当indexPath.row = 0的 cell 出现的时候,文字逐渐变小,图片逐渐显示出来。
首先我们还是先来分析一下:
一眼看过去,很容易就可以发现整个界面有三个部分:顶部店铺信息界面(以下称为:storeInfoView)、中间segmentView、底部数据展示界面。
数据展示选用 UITableView,你也可以用 UICollectionView。因为segmentView 有个顶部悬停的效果,所以有的小伙伴可能会想到这个可能是 tableView 的 headView。那么到底是不是呢?我截了一张淘宝 App 的原图。
当你向下滑动的时候,会出现一段空白。如果segmentView 是 tableView 的 headView 的话,是不会出现这段空白的。所以不是利用tableView 的 headView 来实现的。
下面来看看如何实现:
先看下视图的层次结构:
storeInfoView 和 segmentView 是直接罩在 tableView 上面。为了不遮挡住 tableView 的数据展示,设置了 tableView.contentInset。
- (UITableView *)tableView
{
if (_tableView == nil) {
_tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
_tableView.contentInset = UIEdgeInsetsMake(200, 0, 0, 0);
_tableView.backgroundColor = [UIColor colorWithRed:(240 / 255.0) green:(240 / 255.0) blue:(240 / 255.0) alpha:1.0];
_tableView.dataSource = self;
_tableView.delegate = self;
[_tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"cell"];
}
return _tableView;
}
那么如何做到 storeInfoView 和 segmentView 随着 tableView 的滑动而移动的呢?主要的实现是在 UIScrollViewDelegate 中的 scrollViewDidScroll: 方法中实现的。因为 UITableView 是继承 UIScrollView 的,所以可以在 scrollViewDidScroll: 中获取到 tableView.contentOffset.y,然后根据这个 y 值来计算 storeInfoView 的 frame 和 segmentView 的 frame。
至于看到 segmentView 悬停在上方,是因为控制了tableView.contentOffset.y的范围。
#pragma mark - UIScrollViewDelegate
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
CGFloat offSetY = scrollView.contentOffset.y;
self.segmentView.offSet = offSetY;
if (offSetY >= -113) {
offSetY = -113;
}else {
if (offSetY <= -264) {
offSetY = -264;
}
}
CGRect infoViewFrame = self.infoView.frame;
infoViewFrame.origin.y = -200 - offSetY;
self.infoView.frame = infoViewFrame;
CGRect segmentViewFrame = self.segmentView.frame;
segmentViewFrame.origin.y = -64 - offSetY;
self.segmentView.frame = segmentViewFrame;
}
完成 stroeInfoView 和 segmentView的移动和悬停,接下来就是要实现 segmentView 中的渐变效果了。这里我自定义了一个GGSegmentView,并且将tableView.contentOffset.y的值传递进去。在这里,我是在segmentView与导航栏接触的时候,再多滑动30的时候来完成效果。所以根据这多余的30可以计算出一个0~1的比值,然后利用这个比值,来设置图片的透明度,文字的大小。同时,我让 segment 有15的高度隐藏在了导航栏下面,然后让label 的高度增加15,这样就会让用户仅仅看到 label,还能产生出 segmentView 变矮的错觉。
- (void)setOffSet:(CGFloat)offSet
{
if (offSet <= - 128) {
offSet = - 128;
}else{
if (offSet >= -98) {
offSet = -98;
}
}
CGFloat proportion = (128 + offSet) / 30;
CGFloat fontSize = 12 + (18 - 12) * proportion;
for (UIImageView *imageView in _imageViewArray) {
imageView.alpha = 1- proportion;
}
for (UILabel *label in _labelArray) {
label.font = [UIFont systemFontOfSize:fontSize];
CGRect labelFrame = label.frame;
labelFrame.origin.y = ImageViewHeigh - 15*proportion;
labelFrame.size.height = self.bounds.size.height - ImageViewHeigh + 15*proportion;
label.frame = labelFrame;
}
}
附上 Demo 地址:https://github.com/Gunial/StroeHomeDemo
#######写在最后,写本文的目的并不在于教会别人,而是在于记录自己的思考过程。如果各位看官有更好的实现思路,可以给我指点一下,帮助我成长,如果你在看的过程中有什么疑问也可以回复我,我会及时回复你。