基于MJRefresh模仿美團(tuán)外賣的下拉刷新動畫

相較于彈出加載框式的加載方式佩迟,下拉刷新式加載方式所帶來的用戶體驗(yàn)要好很多蚁鳖,當(dāng)前主流APP的下拉刷新動畫也是越來越絢麗,最近因?yàn)轫?xiàng)目需要婴噩,模仿美團(tuán)外賣的下拉刷新,對項(xiàng)目中的下拉刷新進(jìn)行了修改羽德。(其實(shí)是萬惡的設(shè)計(jì)師几莽,非要模仿人家的設(shè)計(jì),做為程序員只好費(fèi)盡腦細(xì)胞了宅静。)
dome我已經(jīng)上傳到GitHub上了章蚣,有需要的可朋友可以下載看看。

refresh.gif

因?yàn)樵陧?xiàng)目中使用MJRefresh做為下拉刷新框架姨夹,因此所有的設(shè)計(jì)都是基于MJRefresh進(jìn)行的修改纤垂。而MJRefresh也算是當(dāng)前iOS開發(fā)使用的比較多的下拉刷新框架。

一磷账、普通動態(tài)效果

首先加載動態(tài)圖片在MJRefresh提供是提供的有現(xiàn)成的方法的峭沦,在MJRefreshGifHeader中,提供的就是加載動態(tài)圖片的方法逃糟,使用起來也比較簡單吼鱼。
我一般的做法是繼承MJRefreshGifHeader,重新創(chuàng)建一個(gè)類绰咽,用來設(shè)置動態(tài)圖片加載的一些基本屬性蛉抓。

1、 重寫下拉刷新的父類的方法

- (void)prepare{
    [super prepare];
}

2剃诅、 更換動畫圖片

// 設(shè)置即將刷新狀態(tài)的動畫圖片(一松開就會刷新的狀態(tài))
NSMutableArray *refreshingImages = [NSMutableArray array];
for (int i = 1; i<=22; i++) {
    UIImage *image = [UIImage imageNamed:[NSString stringWithFormat:@"gif_header_%d", i]];
    [refreshingImages addObject:image];
}
// 設(shè)置正在刷新狀態(tài)的動畫圖片
[self setImages:refreshingImages forState:MJRefreshStateRefreshing];

3巷送、設(shè)計(jì)一些基本屬性

// 隱藏時(shí)間
self.lastUpdatedTimeLabel.hidden = YES;
// 隱藏狀態(tài)
self.stateLabel.hidden = YES;
// 下拉試圖高度
self.mj_h = 70;

二、模仿美團(tuán)外賣效果

如果只是實(shí)現(xiàn)加載動畫矛辕,那么上面的做法其實(shí)已經(jīng)能夠?qū)崿F(xiàn)了笑跛,可是如何才能實(shí)現(xiàn)上面那種隨著下拉距離付魔,圖片不斷放大的效果呢!
仔細(xì)分析MJRefreshGifHeader里面的效果不難發(fā)現(xiàn)飞蹂,如果是繼承于MJRefreshGifHeader是無法做到這樣的效果的几苍,那么很自然的就能想到,從MJRefreshGifHeader的父級來看看能否實(shí)現(xiàn)陈哑。
MJRefreshGifHeader的父級是MJRefreshStateHeader妻坝。
MJRefreshStateHeader里面的方法其實(shí)同MJRefreshGifHeader比較相似,比較重要的幾個(gè)方法分別是:

// 初始化方法
- (void)prepare{
    [super prepare];
}
// 布局子視圖 
- (void)placeSubviews {

}
// 拉拽的百分比
- (void)setPullingPercent:(CGFloat)pullingPercent {
    [super setPullingPercent:pullingPercent];
}
// 下拉狀態(tài)
- (void)setState:(MJRefreshState)state {
    MJRefreshCheckState
}

搞清楚了這幾個(gè)方法惊窖,接下來就比較簡單了

1刽宪、在初始方法中,設(shè)置下拉刷新的基礎(chǔ)屬性

// 初始化方法
- (void)prepare{
    [super prepare];
    // 隱藏時(shí)間
    self.lastUpdatedTimeLabel.hidden = YES;
    // 隱藏狀態(tài)
    self.stateLabel.hidden = YES;
    // 下拉試圖高度
    self.mj_h = 70;
}

2界酒、在布局方法中創(chuàng)建imageView圣拄,用來展示動態(tài)圖片

// 布局子視圖
- (void)placeSubviews {
    [super placeSubviews];
    if (self.refreshImg.constraints.count) return;
    // 刷新狀態(tài)狀態(tài)圖片
    self.refreshImg.frame = self.bounds;
    self.refreshImg.contentMode = UIViewContentModeCenter;
    // 普通狀態(tài)狀態(tài)圖片
    self.idleImg.x = 0;
    self.idleImg.width = self.width;
    self.idleImg.contentMode = UIViewContentModeCenter;
}

這里我分別創(chuàng)建了兩個(gè)imageView,分別用在下拉階段的放大縮小和加載階段的動畫展示毁欣,這主要是因?yàn)樵陂_發(fā)過程中庇谆,我發(fā)現(xiàn)如果使用一個(gè)imageView,就會造成在加載階段的動畫圖片尺寸變大的現(xiàn)象凭疮,具體是因?yàn)槭裁次乙矝]有找到原因饭耳。

3、在拖拽方法中执解,對普通狀態(tài)的圖片信息縮放

// 拉拽的百分比
- (void)setPullingPercent:(CGFloat)pullingPercent {
    [super setPullingPercent:pullingPercent];
    // 視圖正在下拉
    if (0 < pullingPercent && pullingPercent <= 1) {
        // 普通狀態(tài)圖片高度
        self.idleImg.height = self.height - 70.0 * (1 - pullingPercent);
        // 普通狀態(tài)圖片y值
        self.idleImg.y = 70.0 * (1-pullingPercent);
        // 普通狀態(tài)圖片
        self.idleIm = [UIImage imageNamed:@"header"];
        self.idleIm = [self scaleToSize:self.idleIm size:CGSizeMake(self.idleIm.size.width * pullingPercent, self.idleIm.size.height * pullingPercent)];
        self.idleImg.image = self.idleIm;
    }
}

在初始化方法中曾經(jīng)設(shè)置過一個(gè)屬性

// 下拉試圖高度
self.mj_h = 70;

這個(gè)屬性的意思就是當(dāng)下拉高度在070之間寞肖,拉拽的百分比屬性pullingPercent,就在01之間材鹦。也就是說我們在pullingPercent為0~1的時(shí)候逝淹,對圖片進(jìn)行縮放耕姊。為了保證無論下拉高度在什么位置桶唐,圖片都處在下拉區(qū)域的正中心,所有需要不停的改變圖片的位置

// 普通狀態(tài)圖片高度
self.idleImg.height = self.height - 70.0 * (1 - pullingPercent);
// 普通狀態(tài)圖片y值
self.idleImg.y = 70.0 * (1-pullingPercent);

圖片尺寸的修改方法茉兰,我進(jìn)行了一個(gè)封裝尤泽,

// 圖片縮放到指定大小尺寸
- (UIImage *)scaleToSize:(UIImage *)img size:(CGSize)size{
    // 創(chuàng)建一個(gè)bitmap的context
    // 并把它設(shè)置成為當(dāng)前正在使用的context
    UIGraphicsBeginImageContext(size);
    // 繪制改變大小的圖片
    [img drawInRect:CGRectMake(0, 0, size.width, size.height)];
    // 從當(dāng)前context中創(chuàng)建一個(gè)改變大小后的圖片
    UIImage* scaledImage = UIGraphicsGetImageFromCurrentImageContext();
    // 使當(dāng)前的context出堆棧
    UIGraphicsEndImageContext();
    // 返回新的改變大小后的圖片
    return scaledImage;
}

4、最后一步规脸,就是在不同的刷新狀態(tài)進(jìn)行判斷坯约,然后對所需要展示的imageView進(jìn)行切換。

// 下拉狀態(tài) 
- (void)setState:(MJRefreshState)state {
    MJRefreshCheckState
    switch (state) {
        case MJRefreshStateIdle: { // 普通閑置狀態(tài)
            // 停止刷新動畫
            [self.refreshImg stopAnimating];
            // 隱藏刷新狀態(tài)圖片
            [self.refreshImg setHidden:YES];
            // 展示普通狀態(tài)圖片
            [self.idleImg setHidden:NO];
            break;
        }
        case MJRefreshStateRefreshing: { // 正在刷新中的狀態(tài)
            // 隱藏普通狀態(tài)圖片
            [self.idleImg setHidden:YES];
            // 展示刷新狀態(tài)圖片
            [self.refreshImg setHidden:NO];
            // 刷新狀態(tài)圖片
            self.refreshImg.animationImages = @[[UIImage imageNamed:@"gif_header_1"], [UIImage imageNamed:@"gif_header_2"], [UIImage imageNamed:@"gif_header_3"], [UIImage imageNamed:@"gif_header_4"]];
            self.refreshImg.animationDuration = 0.4;
            // 開始刷新動畫
            [self.refreshImg startAnimating];
            break;
        }
        default:
            break;
    }
}

這里我只判斷了兩個(gè)狀態(tài)莫鸭,在MJRefresh中總共為我們5個(gè)不同的狀態(tài)

/** 普通閑置狀態(tài) */
MJRefreshStateIdle = 1,
/** 松開就可以進(jìn)行刷新的狀態(tài) */
MJRefreshStatePulling,
/** 正在刷新中的狀態(tài) */
MJRefreshStateRefreshing,
/** 即將刷新的狀態(tài) */
MJRefreshStateWillRefresh,
/** 所有數(shù)據(jù)加載完畢闹丐,沒有更多的數(shù)據(jù)了 */
MJRefreshStateNoMoreData

好了,到這里基本上就能實(shí)現(xiàn)上面圖片的功能了被因,不過有一個(gè)問題卿拴,我一直沒有解決衫仑,在進(jìn)行圖片大小縮放的時(shí)候,圖片會出現(xiàn)模糊的情況堕花,如果各位有人有解決方案的話文狱,在此先謝謝了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末缘挽,一起剝皮案震驚了整個(gè)濱河市瞄崇,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌壕曼,老刑警劉巖苏研,帶你破解...
    沈念sama閱讀 221,430評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異窝稿,居然都是意外死亡楣富,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,406評論 3 398
  • 文/潘曉璐 我一進(jìn)店門伴榔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來纹蝴,“玉大人,你說我怎么就攤上這事踪少√涟玻” “怎么了?”我有些...
    開封第一講書人閱讀 167,834評論 0 360
  • 文/不壞的土叔 我叫張陵援奢,是天一觀的道長兼犯。 經(jīng)常有香客問我,道長集漾,這世上最難降的妖魔是什么切黔? 我笑而不...
    開封第一講書人閱讀 59,543評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮具篇,結(jié)果婚禮上纬霞,老公的妹妹穿的比我還像新娘。我一直安慰自己驱显,他們只是感情好诗芜,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,547評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著埃疫,像睡著了一般伏恐。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上栓霜,一...
    開封第一講書人閱讀 52,196評論 1 308
  • 那天翠桦,我揣著相機(jī)與錄音,去河邊找鬼胳蛮。 笑死销凑,一個(gè)胖子當(dāng)著我的面吹牛愁铺,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播闻鉴,決...
    沈念sama閱讀 40,776評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼茵乱,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了孟岛?” 一聲冷哼從身側(cè)響起瓶竭,我...
    開封第一講書人閱讀 39,671評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎渠羞,沒想到半個(gè)月后斤贰,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,221評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡次询,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,303評論 3 340
  • 正文 我和宋清朗相戀三年荧恍,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片屯吊。...
    茶點(diǎn)故事閱讀 40,444評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡送巡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出盒卸,到底是詐尸還是另有隱情骗爆,我是刑警寧澤,帶...
    沈念sama閱讀 36,134評論 5 350
  • 正文 年R本政府宣布蔽介,位于F島的核電站摘投,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏虹蓄。R本人自食惡果不足惜犀呼,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,810評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望薇组。 院中可真熱鬧外臂,春花似錦、人聲如沸体箕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,285評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽累铅。三九已至,卻和暖如春站叼,著一層夾襖步出監(jiān)牢的瞬間娃兽,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,399評論 1 272
  • 我被黑心中介騙來泰國打工尽楔, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留投储,地道東北人第练。 一個(gè)月前我還...
    沈念sama閱讀 48,837評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像玛荞,于是被迫代替她去往敵國和親娇掏。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,455評論 2 359

推薦閱讀更多精彩內(nèi)容