美文网首页
支付宝首页仿写记录

支付宝首页仿写记录

作者: _顺_1896 | 来源:发表于2018-08-01 20:52 被阅读31次

    花了两天时间写了一个支付宝的首页。
    首先关于最终的首页架构:

    1. 整体使用的一个UITableView和2个HeadView(MenuGroudView(包扣HomeNavi、AdView、MiniNavi)、GridView)来布局。未采用网上2个ScrollView的方式
    2. 单独写了一个VC_A来处理UITableView的滑动事件,另外写一个VC_A1继承VC_A来处理UITableView的DataSource和delegate。目的保证功能独立;
    3. 2个HeadView直接添加到UITableView上,未设置为tableView.tableHeaderView,保证这2个HeadView的位置可控。未采用网上的添加到VC.view上,目的是:HeadView已超出UITableView上边距,手势无法接受。
    4. HeadView在tableView上的显示空间有tableView.contentInset预留出来。
    5. 对iPhone X的适配采用对UITableView进行更多的偏移量来适配;
    6. 对导航栏的处理,选择隐藏掉,对系统对tableView的默认偏移特性也进行关闭;
    7. 对页面上下滑动处理采用KVO监听,参考,在监听中控制MenuGroudView的高度以及2个HeadView的位置。

    最终效果:

    6s iPhone X

    核心代码:

    VC部分:

    //
    //  JYALPHomeSimulateVC.m
    //  MYCCBRegisterSubAccount
    //
    //  Created by  JackYing on 2018/7/31.
    //  Copyright © 2018年 JackYing. All rights reserved.
    //
    
    #import "JYALPHomeSimulateVC.h"
    
    #import "JYHGridView.h"
    #import "JYHMenuGroudView.h"
    
    @interface JYALPHomeSimulateVC () {
        
        /// 表格最顶部到顶部的间隙
        CGFloat _topOffset;
        /// 表格顶部内容顶部到表格顶部的间隙
        CGFloat _topMargin;
        /// 快捷菜单,会被隐藏到导航栏
        JYHMenuGroudView *groudView;
        /// 常用菜单,直接跟随tableview进行滑动
        JYHGridView *gridView;
    }
    
    @property (nonatomic, strong) UITableView *tableView;
    @property (nonatomic, strong) UIScrollView *scrollView;
    
    @end
    
    @implementation JYALPHomeSimulateVC
    @synthesize tableView = _tableView;
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        // Do any additional setup after loading the view.
        self.title = @"支付宝首页";
        [self.navigationController setNavigationBarHidden:YES animated:NO];
        
        // 关闭系统默认偏移
        if (@available(iOS 11.0, *)) {
            self.tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
        } else {
            self.automaticallyAdjustsScrollViewInsets = NO;
        }
        
        [self.tableView addObserver:self forKeyPath:@"contentOffset" options:(NSKeyValueObservingOptionNew) context:nil];
        
        [self addHeadSubViews];
    }
    
    - (void)dealloc {
        [self.tableView removeObserver:self forKeyPath:@"contentOffset"];
    }
    
    - (UITableView *)tableView {
        if (!_tableView) {
            _tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:(UITableViewStyleGrouped)];
            _tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeOnDrag;
            _tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine;
            _tableView.pagingEnabled = YES;
            
            _topMargin = 16;
            // 对iPhone X进行适配
            _topOffset = 300 + kJYALPHomeStatueHeight;
            _tableView.contentInset = UIEdgeInsetsMake(_topOffset + _topMargin, 0, 0, 0); // +16目的是顶部到菜单底部有空隙
            _tableView.scrollIndicatorInsets = _tableView.contentInset;
        }
        return _tableView;
    }
    
    - (void)addHeadSubViews {
        
        // 直接将gridView、groudView放在table上可避免上半部分手势的处理,
        // 不需要控制gridView.frame
        gridView = [[JYHGridView alloc] init];
        //gridView.backgroundColor = [UIColor redColor];
        [self.tableView addSubview:gridView];
    
        groudView = [[JYHMenuGroudView alloc] init];
        groudView.delegate = self;
        [self.tableView addSubview:groudView]; // groudView在上层显示,形成groudView.navi在最上层视觉  
        [self layoutHeadSubViews];
    }
    
    /// 原始状态
    - (void)layoutHeadSubViews {
        
        CGFloat y = -(_topOffset + _topMargin);
        CGFloat height = _topOffset / 2;
        groudView.frame = CGRectMake(0, y, CGRectGetWidth(self.tableView.frame), height);
        gridView.frame = CGRectMake(0, CGRectGetMaxY(groudView.frame), CGRectGetWidth(self.tableView.frame), height);
    }
    
    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
        
        CGFloat offsetY = self.tableView.contentOffset.y;
        // 恢复初始位置
        if (offsetY == -(_topOffset + _topMargin)) {
            
            [self layoutHeadSubViews];
            [groudView setSubViewAlpha:1];
            groudView.adView.hidden = NO;
        }
        else if (offsetY < -(_topOffset + _topMargin)) {// 向下滑动
            
            [groudView setSubViewAlpha:1];
    
            CGRect groudViewFrameNew = groudView.frame;
            groudViewFrameNew.size.height = _topOffset/2;
            groudViewFrameNew.origin.y = offsetY; // table偏移多少就相向移动多少
            groudView.frame = groudViewFrameNew;
            
            CGRect gridViewFrameNew = gridView.frame;
            gridViewFrameNew.origin.y = CGRectGetMaxY(groudViewFrameNew);
            gridView.frame = gridViewFrameNew;
        }
        else { // 向上滑动
            // 直接将gridView、groudView放在table上不需要控制gridView.frame
            CGFloat groudViewHeight = (ABS(offsetY) - _topOffset/2 - _topMargin);
            CGRect groudViewFrameNew = groudView.frame;
            if (groudViewHeight >= 64 && groudViewHeight <= _topOffset / 2) { // 减少视图面积
                groudViewFrameNew.size.height = groudViewHeight;
            }
        
            groudViewFrameNew.origin.y = offsetY; // table偏移多少就相向移动多少
            groudView.frame = groudViewFrameNew;
            
            // 控制alpha值以及隐藏显示
            CGFloat alpha = (-offsetY / (_topOffset + _topMargin));
            [groudView setSubViewAlpha:alpha];
            
        }
    }
    
    - (void)menuView:(UIView *)menuView didSeletedMenu:(id)menu {
        NSAssert(NO, @"叶子子类实现!");
    }
    
    @end
    
    

    设置alpha值及显示隐藏:

    - (void)setSubViewAlpha:(CGFloat)alpha {
        //NSLog(@"1. ---->%lf", alpha);
        if (alpha == 1) { // 回到原始位置
            self.adView.alpha = self.homeNavi.alpha = 1;
            self.adView.hidden = self.homeNavi.hidden = NO;
            self.miniMenu.hidden = YES;
        } else {
            
            if (alpha > 0.8) {
                self.adView.hidden = self.homeNavi.hidden = NO;
            }
            if (alpha < 0.95) {
                self.miniMenu.hidden = NO;
            }
            
            alpha = alpha - (1 - alpha) * 3; // 加速减小
            //NSLog(@"adView: ---->%lf", alpha);
            self.adView.alpha = alpha;
            
            alpha -= alpha * 0.5;
            //NSLog(@"homeNavi: ---->%lf", alpha);
            self.homeNavi.alpha = alpha; // homeNavi比adView先消失
            
            alpha = (1 - alpha + alpha * 0.2); // 加速增大
            //NSLog(@"miniMenu: ---->%lf", alpha);
            self.miniMenu.alpha = alpha;
            
            if (alpha > 0.9) {
                alpha = (alpha + alpha * 0.1);
                alpha = alpha < 1 ? alpha : 1;
                //NSLog(@"2. ---->%lf", alpha);
                self.adView.hidden = self.homeNavi.hidden = YES;
                self.miniMenu.hidden = NO;
                self.miniMenu.alpha = alpha;
            }
        }
    }
    

    对状态栏进行适配:

    CGFloat naviMaxY = 44 + kJYALPHomeStatueHeight;
        self.homeNavi.frame = CGRectMake(0, 0, CGRectGetWidth(self.frame), naviMaxY);
        self.adView.frame = CGRectMake(0, naviMaxY, CGRectGetWidth(self.frame), CGRectGetHeight(self.frame) - naviMaxY);
        self.miniMenu.frame = CGRectMake(0, 0, CGRectGetWidth(self.frame), naviMaxY);
    

    趟过的坑:

    1. miniNavi和AdView的alpha值和显示隐藏的控制;
    2. 计算gridView和groudView在滑动过程中相对于TableView的偏移量;
    3. iPhone X的适配在VC中将statueBar高度进行预留,在groudView中控制各子视图的位置;
    4. 在滑动向下过程中到达下半部分时,groudView、gridView的高度应该是固定的,不需要在进行计算;
      a. 所以处理这里时错以为是因为runloop的mode==tracking时,frame进行计算,但不对UI进行更新,等track转为default时在更新,进而有延迟感。查看offsetY的具体值后发现,在sc进行快速tracking时offsetY的变化跨度很大,所以在计算groudViewHeight时产生的跨度也很大,导致最终tracking结束时直接将groudView设置为初始值而产生的闪屏现象:如从143-->150,有跳跃感。
    5. 关于偏移,因为tableView向上滑动时offset在增大,而groudView.y也需要从最初的-topOffset到到0再到正数,一直保持到tableview的顶端,所以, table偏移多少就相向移动多少,即groudView.y = offsetY。
    6. 为了避免处理手势,所以将2个HeadView直接添加到UITableView上,方便在HeadView上滑动时,tableview也会相应正常滑动,而未将其设置为tableHeaderView,是保证这2个HeadView的位置方便控制。

    相关文章

      网友评论

          本文标题:支付宝首页仿写记录

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