iOS自定義簡(jiǎn)易刷新視圖(仿MJRefresh)

前言:之前在實(shí)現(xiàn)下拉刷新,上拉加載功能時(shí),我一直都是使用MJRefresh進(jìn)行集成。一直想自己寫一個(gè)類似于MJRefresh的刷新控件,方便與自己對(duì)MJRefresh原理的理解,昨天抽出了時(shí)間自己寫了一個(gè)類似的刷新控件,在這做一下記錄與分享。


Github: 看這里




思路整理與代碼實(shí)現(xiàn):

1. 通過(guò)上/下拉頁(yè)面顯示刷新提示文字我們可以判斷出,刷新提示文字的顯示與否是根據(jù)當(dāng)前scrollView的偏移值來(lái)確定的。在這里我們的一切動(dòng)態(tài)顯示和用戶交互跟當(dāng)前scrollView的偏移值存在著聯(lián)系。所以我們給MyRefreshView提供一個(gè)類方法的接口,將scrollView傳進(jìn)去:

+ (MyRefreshView *)refreshViewWithScrollView:(UIScrollView *)scrollView{

MyRefreshView *refreshView = [[MyRefreshView alloc]init];

refreshView.frame = CGRectMake(20, -25, KScreenWidth-20, 18);

refreshView.scrollView = scrollView;

[refreshView setupView];

return refreshView;

}

2. 添加控件,這里我們需要一個(gè)提示文本,一個(gè)顯示偏移進(jìn)度的圓形進(jìn)度條,一個(gè)刷新時(shí)的loading等待圈:

@interface MyRefreshView ()

/**

刷新?tīng)顟B(tài)值

*/

@property (nonatomic, assign) NSInteger refreshFlag;

/**

刷新菊花圈

*/

@property (nonatomic, strong) UIActivityIndicatorView *activityIndicatorView;

/**

偏移動(dòng)畫

*/

@property (nonatomic, strong) CAShapeLayer *scheduleLayer;

/**

監(jiān)聽(tīng)視圖

*/

@property (nonatomic, strong) UIScrollView *scrollView;

/**

刷新文字

*/

@property (nonatomic, strong) UILabel *titleLabel;

@end

3. 在setupView方法中構(gòu)建視圖,將refreshView添加到當(dāng)前的scrollView上。并用KVO將refreshView添加為scrollView的觀察者,實(shí)時(shí)監(jiān)聽(tīng)scrollView的偏移值

刷新提示文字:在refreshView上加上一個(gè)Label;

圓形進(jìn)度條:這里我們用CAShapeLayer實(shí)現(xiàn)。CAShapeLayer有strokeStart和strokeEnd屬性,在繪圖時(shí),這兩個(gè)屬性可以改變path的起始位置和結(jié)束位置。設(shè)置strokeStart和strokeEnd初始值都為0,然后根據(jù)scrollView的偏移值來(lái)改變strokeEnd的值,從而達(dá)到改變進(jìn)度的目的;

loading視圖:這里用系統(tǒng)自由的菊花圈UIActivityIndicatorView,實(shí)際操作中也可以設(shè)置gif動(dòng)畫或者CAAnimation來(lái)實(shí)現(xiàn);

refreshFlag:刷新?tīng)顟B(tài)值(根據(jù)偏移值判斷當(dāng)前是否處于可刷新?tīng)顟B(tài));

- (void)setupView{

self.titleLabel = [[UILabel alloc]initWithFrame:CGRectMake(25, 0, KScreenWidth-20-25, 18)];

[self.titleLabel setAdjustsFontSizeToFitWidth:YES];

[self addSubview:self.titleLabel];

self.scheduleLayer = [[CAShapeLayer alloc]init];

self.scheduleLayer.frame = CGRectMake(0, 0, 18, 18);

self.scheduleLayer.strokeStart = 0;

self.scheduleLayer.fillColor = [UIColor clearColor].CGColor;

self.scheduleLayer.strokeColor = [UIColor whiteColor].CGColor;

self.scheduleLayer.backgroundColor = [UIColor clearColor].CGColor;

self.scheduleLayer.lineWidth = 2.0;

self.scheduleLayer.strokeEnd = 0.0;

[self.scheduleLayer setTransform:CATransform3DMakeRotation(-M_PI_2, 0, 0, 1)];

self.scheduleLayer.path = [UIBezierPath bezierPathWithOvalInRect:CGRectInset(CGRectMake(0, 0, 18, 18), 2, 2)].CGPath;

[self.layer addSublayer:self.scheduleLayer];

self.activityIndicatorView = [[UIActivityIndicatorView alloc]initWithFrame:CGRectMake(0, 0, 18, 18)];

[self addSubview:self.activityIndicatorView];

[self.scrollView addSubview:self];

[self.scrollView addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:nil];

}

4. 動(dòng)態(tài)監(jiān)聽(tīng)

在observeValueForKeyPath方法中獲取到當(dāng)前的偏移值,并進(jìn)行相關(guān)的邏輯判斷

這里我們?cè)O(shè)置的刷新臨界點(diǎn)為-80;而strokeStar和strokeEnd的取值范圍為0-1之間。當(dāng)scrollView被拖拽時(shí),顯示refreshView,根據(jù)偏移值動(dòng)態(tài)改變相關(guān)屬性的值。

結(jié)束拖拽時(shí),根據(jù)當(dāng)前的偏移值判斷refreshView是否進(jìn)入刷新?tīng)顟B(tài)。

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void *)context{

if (self.refreshing) {

return;

}

if ([keyPath isEqualToString:@"contentOffset"]) {

CGFloat height = [change[@"new"] CGPointValue].y;

if (height > 0) {

height = 0;

}else if (height > -80){

height = height/-80.0;

}else{

height = 1.0;

}

if (self.scrollView.isDragging) {

self.hidden = NO;

if (height == 1.0) {

self.title = @"釋放刷新";

}else{

self.title = @"下拉刷新";

}

[self.activityIndicatorView stopAnimating];

self.scheduleLayer.strokeEnd = height;

self.scheduleLayer.hidden = NO;

self.refreshFlag = height;

}else{

if (self.refreshFlag == 1.0){

self.refreshing = YES;

[self.scrollView setContentOffset:CGPointMake(0, -80) animated:YES];

[self.activityIndicatorView startAnimating];

self.title = @"正在刷新";

self.scheduleLayer.hidden = YES;

self.scheduleLayer.strokeEnd = 0;

}else{

[self.activityIndicatorView stopAnimating];

self.scheduleLayer.hidden = NO;

self.scheduleLayer.strokeEnd = height;

}

}

}

}

在title的set方法中改變當(dāng)前的刷新文字

- (void)setTitle:(NSString *)title{
    _title = title;
    self.titleLabel.text = title;
}

5. 數(shù)據(jù)請(qǐng)求成功后,設(shè)置結(jié)束刷新接口,結(jié)束刷新動(dòng)畫,并改變刷新?tīng)顟B(tài),將scrollView的偏移值設(shè)置為最初狀態(tài)

- (void)endRefresh{
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)1.0*NSEC_PER_SEC), dispatch_get_main_queue(), ^{
        self.refreshing = NO;
        self.refreshFlag = 0;
        self.scheduleLayer.strokeEnd = 0;
        [self.activityIndicatorView stopAnimating];
        [self.scrollView setContentOffset:CGPointMake(0, 0) animated:YES];
        self.hidden = YES;
    });
    
   
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,142評(píng)論 4 61
  • 從標(biāo)題就可以看出,我今天要寫的是那個(gè)大名鼎鼎的史玉柱,曾經(jīng)是那么一個(gè)大學(xué)生,建立起自己的軟件王國(guó),又有保健品后花園...
    風(fēng)狼志閱讀 256評(píng)論 0 0
  • 面朝大海春暖花開,在這個(gè)美麗的時(shí)光遇到最美的你。讓這個(gè)充滿著愛(ài)的冬季因?yàn)橛心愣?,你出現(xiàn)在這個(gè)美麗的熒幕上,不...
    鐘情于小丸子閱讀 368評(píng)論 6 2
  • 小程序1月9號(hào)正式發(fā)布,在發(fā)布之前,跟很多人交流過(guò)?,F(xiàn)在大家疑問(wèn)基本上是,小程序沒(méi)有入口,用戶每次打開都需要的重新...
    三磊閱讀 933評(píng)論 1 1
  • 寫在前面 好幾天前,我看完了劇版《致青春》,沒(méi)有急著去找原著和幾年前的電影,亦不想吐槽劇中的那些漏洞,只想靜下心來(lái)...
    驛路奇奇閱讀 993評(píng)論 8 13

友情鏈接更多精彩內(nèi)容