ios開發(fā)中,刷新數(shù)據(jù)很常見.但是系統(tǒng)tableView提供的如果不符合我們的要求,那就需要自己自定義控件刷新.像MJRefresh就很有名. 這里我們可以仿照系統(tǒng)自己寫一個(gè)。
(原理效果圖)自定義一個(gè)refreshControl控件,繼承自 UIControl
1.在refreshControl中獲取將要加載到的父類視圖,強(qiáng)轉(zhuǎn)為scrollView, 一般添加到tableView上,也轉(zhuǎn)為scrollView
/**
* 獲取將要加載到的父類視圖
*
* @param newSuperview 父View
*/
-(void)willMoveToSuperview:(UIView *)newSuperview{
//通過kvo,監(jiān)聽滾動
if (newSuperview) {
// 獲取View進(jìn)行強(qiáng)轉(zhuǎn), 通過kvo監(jiān)聽滾動
self.scrollView = (UIScrollView *)newSuperview;
// 監(jiān)聽scrollView的contentOffset
[self.scrollView addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew context:nil];
}
}
2. 通過kvo,監(jiān)聽scrollView偏移量, 對其內(nèi)部進(jìn)行改變
/**
* 監(jiān)聽方法
*/
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context{
[self refreshChangeState];
}
/**
* 通過監(jiān)聽當(dāng)前scrollView的狀態(tài),來改變r(jià)efreshControl控件的狀態(tài)
*/
- (void)refreshChangeState{
CGFloat offsetY = self.scrollView.contentOffset.y;
// 用戶是否在拖動
if (self.scrollView.dragging) {
if (offsetY > -128) {//這里的數(shù)值是根據(jù)frame來的
self.label.text = @"正常";
}else if(offsetY <= -128){
self.label.text = @"下拉中";
}
}
}
原理效果圖
具體效果圖
具體效果思路實(shí)現(xiàn):細(xì)節(jié)以及源碼(只是用來說明原理的,備注很詳細(xì))
- 1.在監(jiān)聽滾動后,定義一個(gè)屬性,記錄其狀態(tài)
typedef NS_ENUM(NSInteger,YYRrefreshControlState) {
Normal = 0,
Pulling = 1,
Rrefreshing = 2,
};
@property (nonatomic, assign) YYRrefreshControlState refreshState;
- 2.重寫狀態(tài)的setter方法,
/**
* 刷新狀態(tài)發(fā)生改變,進(jìn)行對應(yīng)的修改
*
* @param refreshState 刷新狀態(tài)
*/
-(void)setRefreshState:(YYRrefreshControlState)refreshState{
// 這句話千萬不能少,
_refreshState = refreshState;
UIEdgeInsets inset = self.scrollView.contentInset;
switch (refreshState) {
case Normal:
{
self.label.text = @"正常";
if (self.oldState == Rrefreshing) {//======= 這里要做判斷, 不然會有bug
[UIView animateWithDuration:0.5 animations:^{
self.scrollView.contentInset = UIEdgeInsetsMake(inset.top - 64, inset.left, inset.bottom, inset.right);
} completion:^(BOOL finished) {
}];
}
}
break;
case Pulling:
self.label.text = @"下拉中";
break;
case Rrefreshing:
{
// 告知外界刷新了,相當(dāng)于發(fā)送通知
[self sendActionsForControlEvents:UIControlEventValueChanged];
// 動畫效果
[UIView animateWithDuration:0.5 animations:^{
self.scrollView.contentInset = UIEdgeInsetsMake(inset.top + 64, inset.left, inset.bottom, inset.right);
} completion:^(BOOL finished) {
}];
}
break;
default:
break;
}
self.oldState = refreshState;//======用來做判斷的
}
- 3.YYRrefreshControl提供一個(gè)可供外界調(diào)用的endRefreshing方法(為什么提供,仿照系統(tǒng)寫的)
.h
@interface YYRrefreshControl : UIControl
/**
* 提供給外界調(diào)用的方法
*/
- (void)endRefreshing;
@end
.m
/**
* 提供給外界調(diào)用的方法, .h文件里面聲明這個(gè)方法
*/
- (void)endRefreshing{
// 1.把狀態(tài)改為正常
self.refreshState = Normal;
// 2.恢復(fù)contentInset
// 2.1在setter方法里面修改
// -(void)setRefreshState:(YYRrefreshControlState)refreshState
}
- 4.在外界接收通知
- (void)viewDidLoad {
[super viewDidLoad];
// 相當(dāng)于接收通知
[self.refreshControl addTarget:self action:@selector(did) forControlEvents:UIControlEventValueChanged];
[self.tableView addSubview:self.refreshControl];
}
// 接收通知監(jiān)聽的方法
- (void)did{
[self.refreshControl endRefreshing];
}