仿支付寶首頁的交互動畫

禁止轉(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+大按鈕父控件時間差移動,無動畫

分解動畫-header

核心思想

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


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末焊切,一起剝皮案震驚了整個濱河市扮授,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌专肪,老刑警劉巖刹勃,帶你破解...
    沈念sama閱讀 216,496評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異嚎尤,居然都是意外死亡荔仁,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評論 3 392
  • 文/潘曉璐 我一進店門芽死,熙熙樓的掌柜王于貴愁眉苦臉地迎上來乏梁,“玉大人,你說我怎么就攤上這事关贵∮銎铮” “怎么了?”我有些...
    開封第一講書人閱讀 162,632評論 0 353
  • 文/不壞的土叔 我叫張陵坪哄,是天一觀的道長质蕉。 經(jīng)常有香客問我,道長翩肌,這世上最難降的妖魔是什么模暗? 我笑而不...
    開封第一講書人閱讀 58,180評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮念祭,結(jié)果婚禮上兑宇,老公的妹妹穿的比我還像新娘。我一直安慰自己粱坤,他們只是感情好隶糕,可當我...
    茶點故事閱讀 67,198評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著站玄,像睡著了一般枚驻。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上株旷,一...
    開封第一講書人閱讀 51,165評論 1 299
  • 那天再登,我揣著相機與錄音尔邓,去河邊找鬼。 笑死锉矢,一個胖子當著我的面吹牛梯嗽,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播沽损,決...
    沈念sama閱讀 40,052評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼灯节,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了绵估?” 一聲冷哼從身側(cè)響起炎疆,我...
    開封第一講書人閱讀 38,910評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎壹士,沒想到半個月后磷雇,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,324評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡躏救,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,542評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了螟蒸。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片盒使。...
    茶點故事閱讀 39,711評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖七嫌,靈堂內(nèi)的尸體忽然破棺而出少办,到底是詐尸還是另有隱情,我是刑警寧澤诵原,帶...
    沈念sama閱讀 35,424評論 5 343
  • 正文 年R本政府宣布英妓,位于F島的核電站,受9級特大地震影響绍赛,放射性物質(zhì)發(fā)生泄漏蔓纠。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,017評論 3 326
  • 文/蒙蒙 一吗蚌、第九天 我趴在偏房一處隱蔽的房頂上張望腿倚。 院中可真熱鬧,春花似錦蚯妇、人聲如沸敷燎。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽硬贯。三九已至,卻和暖如春陨收,著一層夾襖步出監(jiān)牢的瞬間饭豹,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留墨状,地道東北人卫漫。 一個月前我還...
    沈念sama閱讀 47,722評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像肾砂,于是被迫代替她去往敵國和親列赎。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,611評論 2 353

推薦閱讀更多精彩內(nèi)容