github: https://github.com/hellovoidworld/HVWWeibo
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 }