之前项目中产品经理丢给我一个页面,要求交互效果要和网易云音乐App中"账号"模块一样。

拿到需求后,我关注到松手动作有一个bounce的效果,所以我谨慎的猜测外层是一个UITableView,而头部视图可能是UITableView的tabelHeaderView。
接下来我使用界面分析神器Reveal对网易云音乐的界面进行分析:

可见最外层确实是一个tableview。
跟我猜测有出入的是头部视图是作为NMSettingTable的subView添加进去的,而不是tableHeaderView:
_subviewCache:@[#"<NMSettingCardContainerView: 0x12e22be30; frame = (0 -284; 375 284); clipsToBounds = YES; layer = <CALayer: 0x12e22bfd0>>"
�注意NMSettingCardContainerView的实例clipsToBounds = YES;
到这里已经基本有眉目了,NMSettingHeadView和NMVipCardView作为NMSettingCardContainerView的subView。NMSettingCardContainerView作为NMSettingTableView的subView。NMSettingCardContainerView的height随着NMSettingTableView的contentOffset而变化,高度一变化,NMVipCardView遮挡的部分自然就会显现出来。而NMSettingHeadView和NMVipCardView的frame属性NMSettingTableView的contentOffset做一下微调就可以。
主要代码,代码已经去掉业务相关的部分
#import "ProfileViewController.h"
#import "ProfileHeadView.h"
#import "ProfileRedCardView.h"
#define ContainerViewH 200
#define HeadViewH 150
#define DragDistance 120
@interface SettingTableView : UITableView
@end
@implementation SettingTableView
- (void)setContentOffset:(CGPoint)contentOffset {
CGFloat y = contentOffset.y < - ContainerViewH - DragDistance ? - ContainerViewH - DragDistance : contentOffset.y;
[super setContentOffset:CGPointMake(0, y)];
}
@end
@interface ProfileViewController ()<UITableViewDelegate, UITableViewDataSource, ProfileHeadViewDelegate, ProfileToolCellDelegate>
@property (nonatomic, strong) SettingTableView *tableView;
@property (nonatomic, strong) UIView *containerView;
@property (nonatomic, strong) ProfileHeadView *headView;
@property (nonatomic, strong) ProfileRedCardView *redCardView;
@end
@implementation ProfileViewController
@dynamic viewModel;
- (void)viewDidLoad {
[super viewDidLoad];
self.fd_prefersNavigationBarHidden = YES;
[self.view addSubview:self.tableView];
[self.view addSubview:self.customNavBar];
[self.customNavBar addSubview:self.setBtn];
[self.tableView addSubview:self.headerView];
[self.headerView addSubview:self.headView];
[self.headerView addSubview:self.redCardView];
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGFloat offsetY = scrollView.contentOffset.y;
// NSLog(@"%f",offsetY);
if (offsetY < -ContainerViewH) {
CGFloat dis = -(offsetY + ContainerViewH);
dis = dis > DragDistance ? DragDistance : dis;
self.containerView.top = - ContainerViewH - dis;
self.containerView.height = ContainerViewH + dis;
//微调headView和CardView的frame
self.redCardView.top = HeadViewH + dis * .5;
self.headView.top = dis *.25;
}else {
self.containerView.top = -ContainerViewH;
self.containerView.height = ContainerViewH;
self.headView.top = 0;
self.redCardView.top = HeadViewH;
}
}
#pragma mark - getter
- (SettingTableView *)tableView {
if (_tableView == nil) {
_tableView = [[SettingTableView alloc]initWithFrame:CGRectMake(0, kTopHeight, kScreenW, kScreenH - kTopHeight) style:UITableViewStyleGrouped];
_tableView.bounces = YES;
_tableView.backgroundColor = WhiteColor;
_tableView.delegate = self;
_tableView.dataSource = self;
_tableView.sectionFooterHeight = 0.0;
_tableView.sectionHeaderHeight = 10.0;
_tableView.showsVerticalScrollIndicator = NO;
_tableView.showsHorizontalScrollIndicator = NO;
_tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
_tableView.contentInset = UIEdgeInsetsMake(ContainerViewH, 0, kTabBarHeight, 0);
_tableView.tableHeaderView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 0, CGFLOAT_MIN)];
_tableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 0, CGFLOAT_MIN)];
}
return _tableView;
}
- (UIView *)containerView {
if (_containerView == nil) {
_containerView = [UIView new];
_containerView.frame = CGRectMake(0, -ContainerViewH, kScreenW, ContainerViewH);
_containerView.clipsToBounds = YES;
}
return _containerView;
}
- (ProfileHeadView *)headView {
if (_headView == nil) {
_headView = [[ProfileHeadView alloc] initWithFrame:CGRectMake(0, 0, kScreenW, HeadViewH)];
_headView.delegate = self;
}
return _headView;
}
- (ProfileRedCardView *)redCardView {
if (_redCardView == nil) {
_redCardView = [[ProfileRedCardView alloc] initWithFrame:CGRectMake(0, HeadViewH, kScreenW, 110)];
}
return _redCardView;
}
@end
最终的效果如下:

网友评论