• iOS仿支付宝首页的刷新布局效果


    代码地址如下:
    http://www.demodashi.com/demo/12753.html

    XYAlipayRefreshDemo

    运行效果

    动画效果分析

    1.UI需要变动,向上滑动的时候,顶部部分收缩。

    2.右侧的滚动条的位置是从中间开始的,说明一个现象,这个tableview是从这里开始的。

    3.tableview上面的view,是给tableview一起滑动,做到了无缝衔接。

    4.滑动 tableview 上面那块 view ,直接响应滑动。

    实现思路: 怎么解决以上四个效果问题,是本次的重点。经过多次的尝试分析得出,采用UIScrollView加UITableView的方式实现。从右侧滚动条开始的位置,上部分是个view,下部分是个UITableView。topView和UITableView作为UIScrollView的subView。

    关键点分析

    1.实现scrollView的代理方法scrollViewDidScroll,设置顶部topview的导航栏位置的视图的高度为KTopHeaderViewHeight。当scrollView的y轴偏移量大于0且小于KTopHeaderViewHeight时,计算出透明度的变化。

    CGFloat alpha =  (offsetY*2/KTopHeaderViewHeight>0) ? offsetY*2/KTopHeaderViewHeight:0;
    if (alpha > 0.5) {
        self.navNewView.alpha = alpha*2-1;
        self.navView.alpha = 0;
    } else {
        self.navNewView.alpha = 0;
        self.navView.alpha = 1-alpha*2;
    }
    self.topHeaderView.alpha = 1-alpha;
    
    

    2.滚动条是从中部开始,也是从tableView的位置开始,因此设置scrollView的Indicator的显示位置。其中KTopViewHeight的高度是滚动条开始以上位置的高度,整个topView的高度。

    _scrollView.scrollIndicatorInsets = UIEdgeInsetsMake(KTopViewHeight, 0, 0, 0);
    

    3.scrollView和tableView同时具有滚动效果,当不做处理是,会出现滑动冲突。因此设置tableView的scrollEnabled为NO,解决滑动冲突。

    _tableView.scrollEnabled = NO;
    

    4.tableView作为scrollView的子视图,tableView的内容会随着刷新加载变化,为了正常的显示全部能容,需要监听tableView的contentSize,实时改变scrollView的contentSize

    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
        if ([keyPath isEqualToString:@"contentSize"]) {
            CGRect tFrame = self.tableView.frame;
            tFrame.size.height = self.tableView.contentSize.height;
            self.tableView.frame = tFrame;
            self.scrollView.contentSize = CGSizeMake(0, self.tableView.contentSize.height+KTopViewHeight);
        }
    }
    

    5.在顶部视图收缩时,页面滑动时,topView和tableView的相对ScrollView的位置在发生变化。因此在UIScrollView的代理里面改变topView和tableView的frame值。

    - (void)scrollViewDidScroll:(UIScrollView *)scrollView {
        CGFloat offsetY = self.scrollView.contentOffset.y;
        if (offsetY <= 0.0) {
            CGRect frame = self.topView.frame;
            frame.origin.y = offsetY;
            self.topView.frame = frame;
    
            CGRect tFrame = self.tableView.frame;
            tFrame.origin.y = offsetY + KTopViewHeight;
            self.tableView.frame = tFrame;
    
            if (![self.tableView isRefreshing]) {
                self.tableView.contentOffset = CGPointMake(0, offsetY);
            }
        } else if (offsetY < KTopHeaderViewHeight && offsetY >0) {
            CGFloat alpha =  (offsetY*2/KTopHeaderViewHeight>0) ? offsetY*2/KTopHeaderViewHeight:0;
            if (alpha > 0.5) {
                self.navNewView.alpha = alpha*2-1;
                self.navView.alpha = 0;
            } else {
                self.navNewView.alpha = 0;
                self.navView.alpha = 1-alpha*2;
            }
            self.topHeaderView.alpha = 1-alpha;
        }
    }
    

    注:下拉刷新控件是本人自己写的。可以替换成任意需要的控件,例如:MJRefresh,在相应的位置修改即可。

    6、完整代码如下:

    #import "ViewController.h"
    #import "UIScrollView+XYRefreshView.h"
    
    #define KScreenWidth  [UIScreen mainScreen].bounds.size.width
    #define KScreenHeight [UIScreen mainScreen].bounds.size.height
    #define KTopViewHeight  300
    #define KTopHeaderViewHeight  80
    
    @interface ViewController ()<UITableViewDelegate,UITableViewDataSource,XYPullRefreshViewDelegate,XYPushRefreshViewDelegate>
    @property (nonatomic, strong) UIScrollView *scrollView;
    
    @property (nonatomic, strong) UITableView *tableView;
    
    @property (nonatomic, strong) UIView *topView;
    
    @property (nonatomic, strong) UIView *navBGView;
    
    @property (nonatomic, strong) UIView *navView;
    
    @property (nonatomic, strong) UIView *navNewView;
    
    @property (nonatomic, strong) UIView *topHeaderView;
    
    @property (nonatomic, assign) NSInteger dataCount;
    
    @end
    
    @implementation ViewController
    - (void)dealloc {
        [self removeObserver:self forKeyPath:@"contentSize"];
    }
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        [self.view addSubview:self.navBGView];
        [self.view addSubview:self.navView];
        [self.view addSubview:self.navNewView];
        
        [self.view addSubview:self.scrollView];
        [self.scrollView addSubview:self.topView];
        [self.scrollView addSubview:self.tableView];
        //添加刷新控件
        [self.tableView showPullRefreshViewWithDelegate:self];
        [self.scrollView showPushRefreshViewWithDelegate:self];
        [self.tableView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionNew context:nil];
        self.dataCount = 20;
    }
    //根据tableView的contentSize改变scrollView的contentSize大小
    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
        if ([keyPath isEqualToString:@"contentSize"]) {
            CGRect tFrame = self.tableView.frame;
            tFrame.size.height = self.tableView.contentSize.height;
            self.tableView.frame = tFrame;
            self.scrollView.contentSize = CGSizeMake(0, self.tableView.contentSize.height+KTopViewHeight);
        }
    }
    #pragma mark - XYPullRefreshViewDelegate
    - (void)pullRefreshViewStartLoad:(XYPullRefreshView *)pullView {
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [pullView endRefreshing];
            self.dataCount += 5;
            [self.tableView reloadData];
        });
    }
    
    - (void)pushRefreshViewStartLoad:(XYPushRefreshView *)pushView {
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [pushView endRefreshing];
            self.dataCount += 5;
            [self.tableView reloadData];
        });
    }
    #pragma mark - UIScrollViewDelegate
    - (void)scrollViewDidScroll:(UIScrollView *)scrollView {
        CGFloat offsetY = self.scrollView.contentOffset.y;
        if (offsetY <= 0.0) {
            CGRect frame = self.topView.frame;
            frame.origin.y = offsetY;
            self.topView.frame = frame;
            
            CGRect tFrame = self.tableView.frame;
            tFrame.origin.y = offsetY + KTopViewHeight;
            self.tableView.frame = tFrame;
            
            if (![self.tableView isRefreshing]) {
                self.tableView.contentOffset = CGPointMake(0, offsetY);
            }
        } else if (offsetY < KTopHeaderViewHeight && offsetY >0) {
            CGFloat alpha =  (offsetY*2/KTopHeaderViewHeight>0) ? offsetY*2/KTopHeaderViewHeight:0;
            if (alpha > 0.5) {
                self.navNewView.alpha = alpha*2-1;
                self.navView.alpha = 0;
            } else {
                self.navNewView.alpha = 0;
                self.navView.alpha = 1-alpha*2;
            }
            self.topHeaderView.alpha = 1-alpha;
        }
    }
    
    - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
        CGFloat offsetY = self.scrollView.contentOffset.y;
        if (offsetY < - 60) {
            [self.tableView startPullRefreshing];
        }
    }
    
    #pragma mark - UITableViewDataSource
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
        return self.dataCount;
    }
    
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"CELL"];
        if (cell == nil) {
            cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"CELL"];
        }
        cell.textLabel.text = [NSString stringWithFormat:@"%d",(int)indexPath.row];
        return cell;
    }
    
    #pragma mark - getter && setter
    - (UIScrollView *)scrollView {
        if (_scrollView == nil) {
            _scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 64, KScreenWidth, KScreenHeight-64)];
            _scrollView.delegate = self;
            //Indicator的显示位置
            _scrollView.scrollIndicatorInsets = UIEdgeInsetsMake(KTopViewHeight, 0, 0, 0);
            _scrollView.contentSize = CGSizeMake(0, KScreenHeight*2);
        }
        return _scrollView;
    }
    
    - (UITableView *)tableView {
        if (_tableView == nil) {
            _tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, KTopViewHeight, KScreenWidth, KScreenHeight*2-KTopViewHeight)];
            _tableView.delegate = self;
            _tableView.dataSource = self;
            _tableView.scrollEnabled = NO;
        }
        return _tableView;
    }
    
    - (UIView *)topView {
        if (_topView == nil) {
            _topView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, KScreenWidth, KTopViewHeight)];
            _topView.backgroundColor = [UIColor colorWithRed:66/255.0 green:128/255.0 blue:240/255.0 alpha:1];
            UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, KScreenWidth, KTopHeaderViewHeight)];
            headerView.backgroundColor = [UIColor colorWithRed:66/255.0 green:128/255.0 blue:240/255.0 alpha:1];
            for (int i = 0; i<4; i++) {
                UIButton *button = [[UIButton alloc] init];
                [button setImage:[UIImage imageNamed:[NSString stringWithFormat:@"%d",i+1]] forState:UIControlStateNormal];
                [headerView addSubview:button];
                button.frame = CGRectMake((KScreenWidth/4)*i, 0, KScreenWidth/4, KTopHeaderViewHeight);
            }
            self.topHeaderView = headerView;
            [_topView addSubview:headerView];
            
            UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, KTopHeaderViewHeight, KScreenWidth, KTopViewHeight-KTopHeaderViewHeight)];
            view.backgroundColor = [UIColor brownColor];
            [_topView addSubview:view];
        }
        return _topView;
    }
    
    - (UIView *)navBGView {
        if (_navBGView == nil) {
            _navBGView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, KScreenWidth, 64)];
            _navBGView.backgroundColor = [UIColor colorWithRed:66/255.0 green:128/255.0 blue:240/255.0 alpha:1];
        }
        return _navBGView;
    }
    
    - (UIView *)navView {
        if (_navView == nil) {
            _navView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, KScreenWidth, 64)];
            _navView.backgroundColor = [UIColor clearColor];
            UISearchBar *searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(10, 20, 200, 44)];
            searchBar.backgroundImage = [[UIImage alloc] init];
    
            UITextField *searchField = [searchBar valueForKey:@"searchField"];
            if (searchField) {
                [searchField setBackgroundColor:[UIColor colorWithRed:230/255 green:230/250 blue:230/250 alpha:0.1]];
            }
            [_navView addSubview:searchBar];
            UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(220, 20, 44, 44)];
            [button setImage:[UIImage imageNamed:@"contacts"] forState:UIControlStateNormal];
            [_navView addSubview:button];
        }
        return _navView;
    }
    
    - (UIView *)navNewView {
        if (_navNewView == nil) {
            _navNewView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, KScreenWidth, 64)];
            _navNewView.backgroundColor = [UIColor clearColor];
            UIButton *cameraBtn = [[UIButton alloc] initWithFrame:CGRectMake(10, 20, 44, 44)];
            [cameraBtn setImage:[UIImage imageNamed:@"nav_camera"] forState:UIControlStateNormal];
            [_navNewView addSubview:cameraBtn];
            
            UIButton *payBtn = [[UIButton alloc] initWithFrame:CGRectMake(64, 20, 44, 44)];
            [payBtn setImage:[UIImage imageNamed:@"nav_pay"] forState:UIControlStateNormal];
            [_navNewView addSubview:payBtn];
            
            UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(118, 20, 44, 44)];
            [button setImage:[UIImage imageNamed:@"nav_scan"] forState:UIControlStateNormal];
            [_navNewView addSubview:button];
            _navNewView.alpha = 0;
        }
        return _navNewView;
    }
    
    @end
    
    

    项目结构图


    iOS仿支付宝首页的刷新布局效果

    代码地址如下:
    http://www.demodashi.com/demo/12753.html

    注:本文著作权归作者,由demo大师代发,拒绝转载,转载需要作者授权

  • 相关阅读:
    C语言学习第八章
    C语言学习第七章
    C语言学习第六章
    C语言学习第五章
    ssh的bug
    Oracel 用户管理
    初识Kettle
    IDEA使用MAVEN时自动创建骨架卡的设置
    2017/6/12 JSON
    DDL,DML,DQL
  • 原文地址:https://www.cnblogs.com/demodashi/p/9436586.html
Copyright © 2020-2023  润新知