禁止轉(zhuǎn)載笤喳,原因是源碼不完整也并不耐看
前言
在某論壇看到一個置頂帖子弯予,說是仿支付寶首頁肛跌,手段大概是這樣的
scrollview里放一個超長的tableview,長到整個tableview內(nèi)容全部都一次展示出來钢猛,不讓它滑動伙菜,然后在tableview上面塞一個view,里面做動畫命迈。贩绕。。壶愤。
問題大概看出來了:性能“爆表”
文章中用到的tableview中的cell都是空的淑倾,沒有文字沒有圖片,順暢是應該的征椒,如果像支付寶一樣放點內(nèi)容進去呢娇哆?不說多了,20行就足夠它內(nèi)存爆炸了。
我的建議:菜鳥就不要在論壇發(fā)表“教程帖”了碍讨,論壇的大手們不要置頂這種帖子好不好治力?
那么應該怎么實現(xiàn)支付寶的首頁效果,讓內(nèi)存占用廉價一點垄开,代碼優(yōu)雅一點琴许?
1.scrollview不嵌套
2.tableview/collectionview復用cell
正文-解決方案
整體解讀
先上效果圖
1.除去頂部的導航欄溉躲,其它應該只用一個scrollview(tableview/collectionview)來解決
2.動畫是根據(jù)scrollview的contentoffset.y來控制的,通過notification或者scrollview.delegate來監(jiān)聽益兄,我這里用的delegate
3.將動畫分解為兩部分:導航欄動畫和header動畫
4.下拉刷新控件要放在header下面(解決方案是設置scrollview.contentinset.top锻梳,讓MJRefreshHeader放到header下面,這個方案collectionview和tableview通用净捅,如果用tableview.tableheaderview疑枯,是實現(xiàn)不了這個效果的)
5.小細節(jié):支付寶為了防止?jié)u變過程中用戶點擊按鈕出錯,將滑動停止在動畫的兩個分界點蛔六,實現(xiàn)類似于scrollview.pagingenabled的效果荆永,實現(xiàn)方式用的是scrollview.delegate中的-(void)scrollViewWillEndDragging:(UIScrollView*)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inoutCGPoint*)targetContentOffset方法
分解動畫解讀
1.導航欄動畫根據(jù)contentoffset.y從小到大,分為4部分:無動畫国章,帶輸入框的bar透明度從1到0具钥,只有按鈕的bar透明度從0到1,無動畫
2.header動畫根據(jù)contentoffset.y從小到大液兽,分為3部分:無動畫骂删,大按鈕透明度從1到0+大按鈕父控件時間差移動,無動畫
核心思想
1.原生導航欄隱藏四啰,使用自定義view創(chuàng)建3個導航欄宁玫,父控件是controller.view,根據(jù)層級從下到上:背景色view(無交互)柑晒,帶文本輸入框的bar(透明度動畫)欧瘪,小按鈕bar(透明度動畫)
2.設置scrollview.contentinset.top,預留出header的位置,將header放置到scrollview上(主要作用是將刷新控件頂?shù)较旅嫒ィ?/p>
3.大按鈕的時間差移動動畫用autoresizingMask(UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin)+ 父控件高度變化來實現(xiàn)匙赞,至于原理請自行搜索引擎
小白分割線
源碼
由于只是一時興起佛掖,單純的diss某論壇的置頂帖,所以代碼可讀性一般罚屋,不打算發(fā)github更不打算直接交給伸手黨苦囱,代碼發(fā)出來,看得懂就看脾猛,看不懂就查撕彤,查不出來就問,不要伸手!
如果這都看不懂又不自己研究的話羹铅,請留言蚀狰,我看心情更新注釋或者優(yōu)化可讀性,如果真的火了职员,我會優(yōu)化到可以放到github上的程度
PS:導航欄ChenNavigationView是自定義view麻蹋,不貼詳細代碼,請用UIView+UIButton來替換
#import "ChenTestViewController.h"
CGFloatHeaderHeight =100+140;
CGFloatHeaderContentViewHeight =140;
@interface ChenTestViewController ()
@property (nonatomic,weak)UITableView *tableView;
@property (nonatomic,weak)UIView *headerView;
@property(nonatomic,weak)UIView*headerButtonView;
@property(nonatomic,weak)ChenNavigationView*tempNavigationView;
@end
@implementationChenTestViewController
- (void)viewDidLoad {
? ? [super viewDidLoad];
? ? [self.navigationView removeAllItems];
? ? NSArray *buttonNames = @[@"icon_me_infomation",@"icon_me_bankcard",@"icon_me_history",@"icon_me_message"];
? ? for(NSString*buttonNameinbuttonNames) {
? ? ? ? [self.navigationView addLeftButtonWithImageNameNormal:buttonName imageNameHightlight:buttonName target:self action:@selector(test)];
? ? }
? ? self.navigationView.alpha = 0;
? ? UITableView *tableView = [[UITableView alloc]initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT) style:UITableViewStylePlain];
? ? [self.view insertSubview:tableView belowSubview:self.navigationView];
? ? self.tableView= tableView;
? ? if(@available(iOS11.0, *)) {
? ? ? ? tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
? ? }
? ? tableView.mj_header = [MJRefreshNormalHeader headerWithRefreshingTarget:self refreshingAction:@selector(test)];
? ? tableView.contentInset=UIEdgeInsetsMake(self.navigationView.frame.size.height+HeaderHeight,0,0,0);
? ? tableView.delegate=self;
? ? tableView.dataSource=self; ? ?
? ? tableView.scrollIndicatorInsets = UIEdgeInsetsMake(self.navigationView.frame.size.height + HeaderHeight, 0, 0, 0);
? ? UIView*headerView = [[UIViewalloc]initWithFrame:CGRectMake(0, -tableView.contentInset.top,SCREEN_WIDTH,self.navigationView.frame.size.height+HeaderHeight)];
? ? [tableViewaddSubview:headerView ];
? ? self.headerView= headerView;
? ? headerView.backgroundColor = [UIColor themeColor];
? ? CGFloatheaderButtonWidth =SCREEN_WIDTH/ buttonNames.count;
? ? CGFloat headerButtonHeight = HeaderHeight - HeaderContentViewHeight;
? ? UIView*headerButtonView = [[UIViewalloc]initWithFrame:CGRectMake(0,self.navigationView.frame.size.height,SCREEN_WIDTH, headerButtonHeight)];
? ? [headerViewaddSubview:headerButtonView];
? ? self.headerButtonView= headerButtonView;
? ? headerButtonView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin;
? ? CGFloatbuttonX =0;
? ? for(inti =0;i < buttonNames.count;i++){
? ? ? ? NSString*imageName = buttonNames[i];
? ? ? ? UIButton*headerButton = [[UIButtonalloc]initWithFrame:CGRectMake(buttonX,0, headerButtonWidth, headerButtonHeight)];
? ? ? ? [headerButtonViewaddSubview:headerButton];
? ? ? ? [headerButtonsetImage:[[UIImage imageNamed:imageName]scaleToSize:CGSizeMake(40, 40)] forState:UIControlStateNormal];
? ? ? ? buttonX += headerButtonWidth;
? ? }
? ? UIView*headerContentView = [[UIViewalloc]initWithFrame:CGRectMake(0,CGRectGetMaxY(headerButtonView.frame),SCREEN_WIDTH,HeaderContentViewHeight)];
? ? [headerViewaddSubview:headerContentView];
? ? headerContentView.backgroundColor= [UIColorwhiteColor];
? ? headerContentView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin;
? ? ChenNavigationView *tempNavigationView = [[ChenNavigationView alloc]init];
? ? [self.viewinsertSubview:tempNavigationViewbelowSubview:self.navigationView];
? ? self.tempNavigationView= tempNavigationView;
? ? UIButton*tempLeftButton = [tempNavigationViewaddRightButtonWithTitle:@"臨時"target:selfaction:@selector(test)];
? ? [tempNavigationViewaddRightButtonWithTitle:@"占位"target:selfaction:@selector(test)];
? ? UIView*tempNavigationBackgroundView = [[UIViewalloc]initWithFrame:tempNavigationView.frame];
? ? [self.viewinsertSubview:tempNavigationBackgroundViewbelowSubview:tempNavigationView];
? ? tempNavigationBackgroundView.backgroundColor= [UIColorthemeColor];
? ? CGRecttempLeftButtonRect = [tempLeftButton.superviewconvertRect:tempLeftButton.frametoView:tempNavigationView];
? ? UIView*tempView = [[UIViewalloc]initWithFrame:CGRectMake(12, tempLeftButtonRect.origin.y+6, tempLeftButtonRect.origin.x-12*2, tempLeftButtonRect.size.height-6*2)];
? ? [tempNavigationViewaddSubview:tempView];
? ? tempView.backgroundColor= [UIColorcolorWithString:@"0B80EE"alpha:1.0];
}
-(void)test{
? ? [self.tableView.mj_header performSelector:@selector(endRefreshing) withObject:nil afterDelay:1];
}
-(NSInteger)numberOfSectionsInTableView:(UITableView*)tableView{
? ? return 1;
}
-(NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section{
? ? return 100;
}
-(UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath{
? ? UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"test"];
? ? if(!cell){
? ? ? ? cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"test"];
? ? }
? ? cell.backgroundColor = [UIColor randomColor];
? ? returncell;
}
-(void)scrollViewDidScroll:(UIScrollView*)scrollView{
? ? CGFloatcontentOffsetY = scrollView.contentOffset.y;
? ? CGFloatheaderHeight =MIN(MAX(self.navigationView.frame.size.height, -contentOffsetY),self.navigationView.frame.size.height+HeaderHeight);
? ? CGFloatheaderY =MIN(0, contentOffsetY);
? ? CGFloattempNavigationAlpha =MIN(1,MAX(0, (headerHeight -self.navigationView.frame.size.height-HeaderContentViewHeight) / ((HeaderHeight-HeaderContentViewHeight) /2) -0.5));
? ? CGFloat headerButtonAlpha = MIN(1, MAX(0, (headerHeight - self.navigationView.frame.size.height - HeaderContentViewHeight) / ((HeaderHeight - HeaderContentViewHeight) / 2)));
? ? CGFloat navigationAlpha = MIN(1, MAX(0, 1 - (headerHeight - self.navigationView.frame.size.height - HeaderContentViewHeight) / (HeaderHeight - HeaderContentViewHeight)));
? ? NSLog(@"contentOffsetY:%.2f? headerHeight:%.2f? headerY:%.2f? tempNavigationAlpha:%.2f? headerButtonAlpha:%.2f? navigationAlpha:%.2f",contentOffsetY,headerHeight,headerY,tempNavigationAlpha,headerButtonAlpha,navigationAlpha);
? ? self.tempNavigationView.alpha= tempNavigationAlpha;
? ? self.navigationView.alpha= navigationAlpha;
? ? self.headerButtonView.alpha= headerButtonAlpha;
? ? self.headerView.frame=CGRectMake(self.headerView.frame.origin.x, headerY,self.headerView.frame.size.width, headerHeight);
}
-(void)scrollViewWillEndDragging:(UIScrollView*)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inoutCGPoint*)targetContentOffset{
? ? CGPointoriginalTargetContentOffset =CGPointMake(targetContentOffset->x, targetContentOffset->y);
? ? if(originalTargetContentOffset.y< -HeaderContentViewHeight){
? ? ? ? if(originalTargetContentOffset.y< -(scrollView.contentInset.top- (HeaderHeight-HeaderContentViewHeight) /2)){
? ? ? ? ? ? *targetContentOffset =CGPointMake(0, -scrollView.contentInset.top);
? ? ? ? }else{
? ? ? ? ? ? *targetContentOffset =CGPointMake(0, -(scrollView.contentInset.top- (HeaderHeight-HeaderContentViewHeight)));
? ? ? ? }
? ? }
}
@end