A.下拉刷新微博
1.需求
- 在“首页”界面,下拉到一定距离的时候刷新微博数据
- 刷新数据的时候使用控件提示
- 新数据要加在旧数据的前面
- 刷新完毕隐藏刷新控件
- 刷新数据完毕,导航栏下方弹出一个提示框,提示刷新微博数量
2.思路
- 直接使用系统自带的UIRefreshControl就可以做出动画效果
- 使用微博的获取微博API参数since_id可以控制加载的微博从哪个id开始
- 使用可变数组来拼接新旧微博数据
- 创建一个UILabel放在导航控制器view上来提示刷新数据(放在TableView上会被滚走)
3.实现
(1)每条微博都有一个id,这个id是随时间递进叠加的,id越大越新
(2)获取微博API参数
(3)在“首页”控制器加上下拉刷新代码
以前的加载微博数据方法"loadWeiboData",也用刷新方法代替
1 // HVWHomeViewController.m 2 - (void)viewDidLoad { 3 [super viewDidLoad]; 4 5 self.tableView.delegate = self; 6 7 // 设置导航栏 8 [self setupNavigationBar]; 9 10 // 添加刷新器 11 [self addRefresh]; 12 } 13 14 /** 初始化status */ 15 - (NSMutableArray *)statuses { 16 if (nil == _statuses) { 17 _statuses = [NSMutableArray array]; 18 } 19 return _statuses; 20 } 21 22 /** 添加刷新器 */ 23 - (void) addRefresh { 24 // 下拉刷新最新微博 25 // 添加刷新控件 26 UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init]; 27 self.refreshControl = refreshControl; 28 [self.view addSubview:refreshControl]; 29 30 // 刷新控件下拉事件 31 [refreshControl addTarget:self action:@selector(refreshLatestWeibo:) forControlEvents:UIControlEventValueChanged]; 32 33 // 开启的时候自动进入刷新状态 34 [refreshControl beginRefreshing]; 35 // 加载微博数据 36 [self refreshLatestWeibo:refreshControl]; 37 } 38 39 /** 刷新最新微博数据 */ 40 - (void) refreshLatestWeibo:(UIRefreshControl *) refreshControl { 41 // 把最新的微博数据加到原来的微博前面 42 43 // 创建AFNetworking的http操作中管理器 44 AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager]; 45 46 // 设置参数 47 NSMutableDictionary *param = [NSMutableDictionary dictionary]; 48 param[@"access_token"] = [HVWAccountInfoTool accountInfo].access_token; 49 50 /** 若指定此参数,则返回ID比since_id大的微博(即比since_id时间晚的微博),默认为0。*/ 51 HVWStatus *firstStatus = [self.statuses firstObject]; 52 if (firstStatus) { 53 param[@"since_id"] = firstStatus.idstr; 54 } 55 56 // 发送请求 57 [manager GET:@"https://api.weibo.com/2/statuses/home_timeline.json" parameters:param success:^(AFHTTPRequestOperation *operation, NSDictionary *responseObject) { 58 // HVWLog(@"获取微博数据成功-------%@", responseObject); 59 60 // 保存数据到内存 61 NSArray *dataArray = responseObject[@"statuses"]; 62 63 // 得到新微博数据 64 // 使用MJExtension直接进行字典-模型转换 65 NSArray *newStatus = [HVWStatus objectArrayWithKeyValuesArray:dataArray]; 66 67 // 插入到微博数据数组的最前面 68 NSRange newWeiboRange = NSMakeRange(0, newStatus.count); 69 NSIndexSet *newWeiboIndexSet = [NSIndexSet indexSetWithIndexesInRange:newWeiboRange]; 70 [self.statuses insertObjects:newStatus atIndexes:newWeiboIndexSet]; 71 72 // 刷新数据 73 [self.tableView reloadData]; 74 } failure:^(AFHTTPRequestOperation *operation, NSError *error) { 75 HVWLog(@"获取微博数据失败------%@", error); 76 }]; 77 78 // 缩回刷新器 79 [refreshControl endRefreshing]; 80 }
(4)添加一个UILabel提示更新微博数量,在请求微博数据成功后显示
1 /** 弹出微博更新提示框 */ 2 - (void) showRefreshIndicator:(int) refreshCount { 3 // 创建UILabel 4 UILabel *refreshIndicatorLabel = [[UILabel alloc] init]; 5 refreshIndicatorLabel.textAlignment = NSTextAlignmentCenter; 6 7 // 设置文本 8 refreshIndicatorLabel.text = [NSString stringWithFormat:@"更新了%d条微博", refreshCount]; 9 10 // 设置背景 11 refreshIndicatorLabel.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageWithNamed:@"timeline_new_status_background"]]; 12 13 // 设置位置尺寸 14 refreshIndicatorLabel.width = self.navigationController.view.width; 15 refreshIndicatorLabel.height = 35; 16 refreshIndicatorLabel.x = 0; 17 // 因为一开始是藏在导航栏上的,所以要减去自身的高度 18 refreshIndicatorLabel.y = [UIApplication sharedApplication].statusBarFrame.size.height + self.navigationController.navigationBar.height - refreshIndicatorLabel.height; 19 20 // 添加到导航控制器view,要加载导航器的下面 21 [self.navigationController.view insertSubview:refreshIndicatorLabel belowSubview:self.navigationController.navigationBar]; 22 23 // 使用动画弹出 24 [UIView animateWithDuration:1.0 animations:^{ 25 // 使用更改transform来实现 26 refreshIndicatorLabel.transform = CGAffineTransformMakeTranslation(0, refreshIndicatorLabel.height); 27 } completion:^(BOOL finished) { 28 // 弹出完毕后,再使用动画缩回 29 [UIView animateWithDuration:1.0 delay:1.0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ 30 // 恢复位置 31 refreshIndicatorLabel.transform = CGAffineTransformIdentity; 32 } completion:^(BOOL finished) { 33 // 从导航view删除 34 [refreshIndicatorLabel removeFromSuperview]; 35 }]; 36 }]; 37 }
B.上拉加载旧微博数据
1.需求
当浏览到了缓存的所有微博数据底部的时候,上拉加载更多的旧微博数据
也具有一个加载提示器
2.思路
跟下拉加载新微博一样,使用获取微博API中的“max_id”参数
如果需要加载等待动画图标(菊花图标),可以使用代码或xib创建一个UIView
加载在tableView的footerView上
3.实现
(1)设计一个“加载更多”控件
1 // 2 // HVWLoadMoreWeiboFooterView.m 3 // HVWWeibo 4 // 5 // Created by hellovoidworld on 15/2/6. 6 // Copyright (c) 2015年 hellovoidworld. All rights reserved. 7 // 8 9 #import "HVWLoadMoreWeiboFooterView.h" 10 11 @interface HVWLoadMoreWeiboFooterView() 12 13 /** 加载更多微博文本 */ 14 @property(nonatomic, strong) UILabel *label; 15 16 /** 加载中活动指示器 */ 17 @property(nonatomic, strong) UIActivityIndicatorView *actIndicator; 18 19 @end 20 21 @implementation HVWLoadMoreWeiboFooterView 22 23 - (instancetype)initWithFrame:(CGRect)frame { 24 self = [super initWithFrame:frame]; 25 26 self.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageWithNamed:@"timeline_new_status_background"]]; 27 28 // 设置加载文本 29 UILabel *label = [[UILabel alloc] init]; 30 label.textAlignment = NSTextAlignmentCenter; 31 label.text = @"上拉加载更多微博"; 32 self.label = label; 33 [self addSubview:label]; 34 35 // 设置加载活动指示器 36 // 不同类型的活动指示器大小是不一样的,要注意 37 UIActivityIndicatorView *actIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; 38 self.actIndicator = actIndicator; 39 [self addSubview:actIndicator]; 40 41 return self; 42 } 43 44 /** 设置位置尺寸 */ 45 - (void)layoutSubviews { 46 [super layoutSubviews]; 47 48 // 设置本身frame 49 self.width = [UIScreen mainScreen].bounds.size.width; 50 self.height = 35; 51 52 // 设置文本frame 53 self.label.frame = self.bounds; 54 55 // 设置活动指示器frame 56 CGFloat marginX = 50; 57 self.actIndicator.x = self.width - self.actIndicator.width - marginX; 58 self.actIndicator.y = (self.height - self.actIndicator.height) * 0.5; 59 } 60 61 @end
加在tableView的footerView上,没有微博数据的时候不需要显示(app启动的时候)
1 // HVWHomeViewController.m 2 /** 添加刷新器 */ 3 - (void) addRefresh { 4 // 下拉刷新最新微博 5 // 添加刷新控件 6 UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init]; 7 self.refreshControl = refreshControl; 8 [self.view addSubview:refreshControl]; 9 10 // 刷新控件下拉事件 11 [refreshControl addTarget:self action:@selector(refreshLatestWeibo:) forControlEvents:UIControlEventValueChanged]; 12 13 // 开启的时候自动进入刷新状态 14 [refreshControl beginRefreshing]; 15 // 加载微博数据 16 [self refreshLatestWeibo:refreshControl]; 17 18 // 添加上拉刷新器 19 HVWLoadMoreWeiboFooterView *loadMoreFooter = [[HVWLoadMoreWeiboFooterView alloc] init]; 20 self.loadMoreFooter = loadMoreFooter; 21 self.tableView.tableFooterView = loadMoreFooter; 22 23 } 24 25 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 26 // 没有微博数据的时候,不需要显示“加载更多微博”控件 27 self.loadMoreFooter.hidden = self.statuses.count==0?YES:NO; 28 29 return self.statuses.count; 30 }
(2)上拉刷新动作监听
a.给“上拉刷新”控件增加状态管理属性和方法
1 // 2 // HVWLoadMoreWeiboFooterView.h 3 // HVWWeibo 4 // 5 // Created by hellovoidworld on 15/2/6. 6 // Copyright (c) 2015年 hellovoidworld. All rights reserved. 7 // 8 9 #import <UIKit/UIKit.h> 10 11 @interface HVWLoadMoreWeiboFooterView : UIView 12 13 /** 是否正在刷新 */ 14 @property(nonatomic, assign, getter=isRefreshing) BOOL refreshing; 15 16 /** 开始刷新 */ 17 - (void) beginRefresh; 18 /** 停止刷新 */ 19 - (void) endRefresh; 20 21 @end 22 23 // 24 // HVWLoadMoreWeiboFooterView.m 25 // HVWWeibo 26 // 27 // Created by hellovoidworld on 15/2/6. 28 // Copyright (c) 2015年 hellovoidworld. All rights reserved. 29 // 30 31 #import "HVWLoadMoreWeiboFooterView.h" 32 33 @interface HVWLoadMoreWeiboFooterView() 34 35 /** 加载更多微博文本 */ 36 @property(nonatomic, strong) UILabel *label; 37 38 /** 加载中活动指示器 */ 39 @property(nonatomic, strong) UIActivityIndicatorView *actIndicator; 40 41 @end 42 43 @implementation HVWLoadMoreWeiboFooterView 44 45 - (instancetype)initWithFrame:(CGRect)frame { 46 self = [super initWithFrame:frame]; 47 48 self.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageWithNamed:@"timeline_new_status_background"]]; 49 50 // 设置加载文本 51 UILabel *label = [[UILabel alloc] init]; 52 label.textAlignment = NSTextAlignmentCenter; 53 label.text = @"上拉加载更多微博"; 54 self.label = label; 55 [self addSubview:label]; 56 57 // 设置加载活动指示器 58 // 不同类型的活动指示器大小是不一样的,要注意 59 UIActivityIndicatorView *actIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; 60 self.actIndicator = actIndicator; 61 [self addSubview:actIndicator]; 62 63 return self; 64 } 65 66 /** 设置位置尺寸 */ 67 - (void)layoutSubviews { 68 [super layoutSubviews]; 69 70 // 设置本身frame 71 self.width = [UIScreen mainScreen].bounds.size.width; 72 self.height = 35; 73 74 // 设置文本frame 75 self.label.frame = self.bounds; 76 77 // 设置活动指示器frame 78 CGFloat marginX = 50; 79 self.actIndicator.x = self.width - self.actIndicator.width - marginX; 80 self.actIndicator.y = (self.height - self.actIndicator.height) * 0.5; 81 } 82 83 /** 开始刷新 */ 84 - (void) beginRefresh { 85 self.label.text = @"正在努力加载更多微博..."; 86 [self.actIndicator startAnimating]; 87 self.refreshing = YES; 88 } 89 90 /** 停止刷新 */ 91 - (void) endRefresh { 92 self.label.text = @"上拉加载更多微博"; 93 [self.actIndicator stopAnimating]; 94 self.refreshing = NO; 95 } 96 97 @end
b.在“首页”控制器中,监听滚动操作,当“上拉刷新”控件完全露出的时候启动刷新
1 // HVWHomeViewController.m 2 /** 加载更多(旧)微博 */ 3 - (void) loadMoreWeiboData { 4 // 把更多的微博数据加到原来的微博后面 5 6 // 创建AFNetworking的http操作中管理器 7 AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager]; 8 9 // 设置参数 10 NSMutableDictionary *param = [NSMutableDictionary dictionary]; 11 param[@"access_token"] = [HVWAccountInfoTool accountInfo].access_token; 12 13 /** 若指定此参数,则返回ID小于或等于max_id的微博,默认为0。*/ 14 HVWStatus *lastStatus = [self.statuses lastObject]; 15 if (lastStatus) { 16 param[@"max_id"] = @([lastStatus.idstr longLongValue] - 1); 17 } 18 19 // 发送请求 20 [manager GET:@"https://api.weibo.com/2/statuses/home_timeline.json" parameters:param success:^(AFHTTPRequestOperation *operation, NSDictionary *responseObject) { 21 // HVWLog(@"获取微博数据成功-------%@", responseObject); 22 23 // 保存数据到内存 24 NSArray *dataArray = responseObject[@"statuses"]; 25 26 // 得到新微博数据 27 // 使用MJExtension直接进行字典-模型转换 28 NSArray *newStatus = [HVWStatus objectArrayWithKeyValuesArray:dataArray]; 29 30 // 插入到微博数据数组的后面 31 [self.statuses addObjectsFromArray:newStatus]; 32 33 // 刷新数据 34 [self.tableView reloadData]; 35 } failure:^(AFHTTPRequestOperation *operation, NSError *error) { 36 HVWLog(@"获取微博数据失败------%@", error); 37 }]; 38 39 [self.loadMoreFooter endRefresh]; 40 } 41 42 #pragma mark - UIScrollViewDelegate 43 - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate { 44 // 如果正在加载中,不用重复加载 45 if (self.loadMoreFooter.isRefreshing) return; 46 47 // 滚动时,scrollView处于屏幕顶部下方的内容长度 48 CGFloat scrollingDelta = scrollView.contentSize.height - scrollView.contentOffset.y; 49 // 当scrollView向上滚栋到刚好露出“上拉刷新”控件时,scrollView处于屏幕下方的内容长度 50 CGFloat scrollViewHeighWithFooter = self.tableView.height - self.tabBarController.tabBar.height - self.loadMoreFooter.height; 51 52 // 当向上滚动至scrollView能够显示的内容少于刚好露出“上拉刷新”控件时显示的内容,证明“上拉刷新”控件已经完全露出,可以刷新 53 if (scrollingDelta < scrollViewHeighWithFooter) { 54 [self.loadMoreFooter beginRefresh]; 55 [self loadMoreWeiboData]; 56 } 57 }