如何实现Path个人主页的景深效果

Path3.0的个人主页的个人图片上面有一个很明显的景深特效,当用户下拉的时候可以看到更多的图片。如下图所示:

看起来很高端霸气上档次的效果,其实是很好实现的。

工作原理

当你下拉tableview的时候,会根据tableview的offset来调整上面那张图的位置,以及显示区域。

但是,每次都要调整imageView的drawrect是非常麻烦的,我们可以用两个层来模拟这个效果:

  • 上层是一个上部镂空,下部是数据的tableview
  • 下层是一个ImageView。

这样,只要在TableView 滑动的时候,监听它的offset,来同步调整底层的图片,就可以实现了。

核心部分

设计细节上,要注意一个问题,就是这个模型一共有多少个状态,其实完全可以不考虑tableview的滚动方向的,上文已说,通过监听tableview的offset即可实现效果的。

于是我们有:

  • offset为正值——tableview向上滚动,那么底层的imageview跟随offset向上偏移即可
  • offset为负值且offset绝对值小于图片高度-露出高度——图片还没完全显示,那么底层imageView的偏移为offset/2
  • offset为负值且offset绝对值大于图片高度-露出高度——图片完全显示,那么底层imageView的偏移为offset-(图片高度-露出高度)/2

换成代码的话就如下:

1
2
3
4
5
6
7
8
9
10
11
12
- (void)updateOffsets {
    CGFloat yOffset   = _tableView.contentOffset.y;
    CGFloat threshold = kImageHeight - kWindowHeight;

    if (yOffset > -threshold && yOffset < 0) {
        _scrollView.contentOffset = CGPointMake(0.0, floorf(yOffset / 2.0));
    } else if (yOffset < 0) {
        _scrollView.contentOffset = CGPointMake(0.0, yOffset + floorf(threshold / 2.0));
    } else {
        _scrollView.contentOffset = CGPointMake(0.0, yOffset);
    }
}

这里我们用scrollView来做底层的imageview的容器,方便调整offset,以及tableview offset的监听可以使用tableview父类scrollview的delegate

1
- (void) scrollViewDidScroll:(UIScrollView *)scrollView

部分镂空的tableView

  • tableView的背景应为透明
  • tableViewCell设置一个透明的cell,cell的高度应和imageView默认状态下显示出来的图片相同

tableView DataSource 和 Delegate 部分的设置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#pragma mark - UITableViewDataSource

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 2;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    if (!section) { return 1;  }
    else return 10;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *cellReuseIdentifier   = @"cell";
    static NSString *windowReuseIdentifier = @"clean";

    UITableViewCell *cell = nil;

    if (indexPath.section == 0) {
        cell = [tableView dequeueReusableCellWithIdentifier:windowReuseIdentifier];
        if (!cell) {
            cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:windowReuseIdentifier] autorelease];
            cell.backgroundColor             = [UIColor clearColor];
            cell.contentView.backgroundColor = [UIColor clearColor];
            cell.selectionStyle              = UITableViewCellSelectionStyleNone;
        }
    }
    else
    {
        cell = [tableView dequeueReusableCellWithIdentifier:cellReuseIdentifier];
        if (!cell) {
            cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellReuseIdentifier] autorelease];
            cell.selectionStyle              = UITableViewCellSelectionStyleNone;
        }
    }
    return cell;
}


#pragma mark - UITableViewDelegate

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    if (indexPath.section == 0) { return kWindowHeight;}
    else return 44;
}


#pragma mark - UIScrollViewDelegate
- (void) scrollViewDidScroll:(UIScrollView *)scrollView
{
    [self updateOffsets];
}

- (void)updateOffsets {
    CGFloat yOffset   = _tableView.contentOffset.y;
    CGFloat threshold = kImageHeight - kWindowHeight;

    if (yOffset > -threshold && yOffset < 0) {
        _scrollView.contentOffset = CGPointMake(0.0, floorf(yOffset / 2.0));
    } else if (yOffset < 0) {
        _scrollView.contentOffset = CGPointMake(0.0, yOffset + floorf(threshold / 2.0));
    } else {
        _scrollView.contentOffset = CGPointMake(0.0, yOffset);
    }
}

初始化

比较偷懒的使用了Storyboard,层次如图:

注意除了imageView以外,全都要设置AutoResizing,以适应iPhone5

Comments