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大師代發,拒絕轉載,轉載需要作者授權


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM