美文网首页Android笔记本优秀案例
仿支付宝首页的交互动画

仿支付宝首页的交互动画

作者: NSNil | 来源:发表于2018-08-23 15:18 被阅读313次

禁止转载,原因是源码不完整也并不耐看

前言

在某论坛看到一个置顶帖子,说是仿支付宝首页,手段大概是这样的

scrollview里放一个超长的tableview,长到整个tableview内容全部都一次展示出来,不让它滑动,然后在tableview上面塞一个view,里面做动画。。。。

问题大概看出来了:性能“爆表”

文章中用到的tableview中的cell都是空的,没有文字没有图片,顺畅是应该的,如果像支付宝一样放点内容进去呢?不说多了,20行就足够它内存爆炸了。

我的建议:菜鸟就不要在论坛发表“教程帖”了,论坛的大手们不要置顶这种帖子好不好?

那么应该怎么实现支付宝的首页效果,让内存占用廉价一点,代码优雅一点?

1.scrollview不嵌套

2.tableview/collectionview复用cell

正文-解决方案

整体解读

先上效果图

完整动画效果(动图很大,慎点)

1.除去顶部的导航栏,其它应该只用一个scrollview(tableview/collectionview)来解决

2.动画是根据scrollview的contentoffset.y来控制的,通过notification或者scrollview.delegate来监听,我这里用的delegate

3.将动画分解为两部分:导航栏动画和header动画

4.下拉刷新控件要放在header下面(解决方案是设置scrollview.contentinset.top,让MJRefreshHeader放到header下面,这个方案collectionview和tableview通用,如果用tableview.tableheaderview,是实现不了这个效果的)

5.小细节:支付宝为了防止渐变过程中用户点击按钮出错,将滑动停止在动画的两个分界点,实现类似于scrollview.pagingenabled的效果,实现方式用的是scrollview.delegate中的-(void)scrollViewWillEndDragging:(UIScrollView*)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inoutCGPoint*)targetContentOffset方法

分解动画解读

1.导航栏动画根据contentoffset.y从小到大,分为4部分:无动画,带输入框的bar透明度从1到0,只有按钮的bar透明度从0到1,无动画

分解动画-导航栏

2.header动画根据contentoffset.y从小到大,分为3部分:无动画,大按钮透明度从1到0+大按钮父控件时间差移动,无动画

分解动画-header

核心思想

1.原生导航栏隐藏,使用自定义view创建3个导航栏,父控件是controller.view,根据层级从下到上:背景色view(无交互),带文本输入框的bar(透明度动画),小按钮bar(透明度动画)

2.设置scrollview.contentinset.top,预留出header的位置,将header放置到scrollview上(主要作用是将刷新控件顶到下面去)

3.大按钮的时间差移动动画用autoresizingMask(UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin)+ 父控件高度变化来实现,至于原理请自行搜索引擎


小白分割线


源码

由于只是一时兴起,单纯的diss某论坛的置顶帖,所以代码可读性一般,不打算发github更不打算直接交给伸手党,代码发出来,看得懂就看,看不懂就查,查不出来就问,不要伸手!

如果这都看不懂又不自己研究的话,请留言,我看心情更新注释或者优化可读性,如果真的火了,我会优化到可以放到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

相关文章

网友评论

  • SanriXIN:还会有人想到用scrollView嵌套tableView,真是奇特的想法
  • 莫语莫雨:你好,如果感兴趣的话,可以加入专题《Android笔记本》,助力更多中国开发者

本文标题:仿支付宝首页的交互动画

本文链接:https://www.haomeiwen.com/subject/uukpdftx.html