iOS-高仿優(yōu)雅的好奇心日?qǐng)?bào)

好奇心日?qǐng)?bào)關(guān)于好奇心有這樣一句話:

之所以叫好奇心日?qǐng)?bào),是因?yàn)槲覀冋J(rèn)為好奇心是人類最美好的品質(zhì)之一,我們篩選最有價(jià)值的信息,你能看到全球最有想法,最有關(guān)注的各界動(dòng)態(tài),以及他們背后的故事

正是出于好奇心偶然間下載安裝了這個(gè)好奇心日?qǐng)?bào),打開這個(gè)APP首先吸引我的就是它簡(jiǎn)潔干凈的界面和優(yōu)雅的配色,整個(gè)首頁只有一個(gè)帶有l(wèi)ogo的懸浮按鈕,然后就是帶有高清配圖不同與其他新聞平臺(tái)的新聞文章,圖標(biāo)基本是簡(jiǎn)單的黑、黃、白三種顏色加單線條圖形的設(shè)計(jì)。最后讓我下定決心仿它的是它那簡(jiǎn)單到自然的動(dòng)畫效果。說這么多當(dāng)然不是給好奇心日?qǐng)?bào)打廣告,只是想說我為什么寫這個(gè)項(xiàng)目;額,就這么簡(jiǎn)單!

先看看JFQDaily效果:

JFQDaily效果展示.gif

如果你是一個(gè)iOS開發(fā)入門級(jí)的猿,有興趣話可以下載JFQDaily源碼然后結(jié)合本篇博客來看,相信你會(huì)有所收獲的,代碼寫的接地氣,注釋詳細(xì)!

一、準(zhǔn)備工作

1、高仿,原生圖片圖標(biāo)自然必不可少,利用iOS images Extractor抓取好奇心日?qǐng)?bào)的圖片,如何使用iOS images Extractor抓取APP圖片,我的iOS直播APP-點(diǎn)贊動(dòng)畫的實(shí)現(xiàn)這篇文章下面有介紹。
2、用青花瓷(Charles)提取密碼: kgya抓取好奇心日?qǐng)?bào)數(shù)據(jù),Charles的用法網(wǎng)上有很多文章,可以看看Charles常用的十大功能。
3、篩選數(shù)據(jù):

Paste_Image.png
Paste_Image.png

Paste_Image.png

上面是用chalers所抓取到的數(shù)據(jù),分析并拿到你需要的數(shù)據(jù)就行,上面標(biāo)注的都是項(xiàng)目中需要用到的數(shù)據(jù),具體篩選過程就不再分析了,無非是打開好奇心日?qǐng)?bào)看APP所展示的信息和抓到的數(shù)據(jù)做對(duì)比,找到相應(yīng)的映射關(guān)系。如果你想走的更遠(yuǎn)獨(dú)立行走是必要的。具體數(shù)據(jù)分析里的細(xì)節(jié)問題可以認(rèn)真看源碼Models文件夾類的數(shù)據(jù)模型文件。好啦準(zhǔn)備工作完成啦,開始動(dòng)手建工程碼代碼吧!

二、項(xiàng)目文件結(jié)構(gòu)

Paste_Image.png

1、 AppDeleteggate文件夾

  • 放著AppDelegate .h和.m文件

2、Tools:工具類

  • NSString+JFMessage:NSString的類擴(kuò)展,添加了計(jì)算文本高度和將毫秒轉(zhuǎn)換成日期的類方法

  • JFLoopView:無限循環(huán)圖片輪播器,關(guān)于JFLoopView可以看一行代碼實(shí)現(xiàn)圖片無限輪播器

  • MBProgressHUD+JFProgressHUD:MBProgressHUD的類擴(kuò)展,添加了一個(gè)創(chuàng)建MBProgressHUD類方法,方便調(diào)用。

  • JFTimer:定時(shí)器,在一行代碼實(shí)現(xiàn)圖片無限輪播器中有講到。

  • JFConfigFile:這個(gè)里面是一些高頻的宏定義

3、Models:數(shù)據(jù)模型

  • 這里是根據(jù)之前使用chalers篩選的數(shù)據(jù)建立的數(shù)據(jù)模型

4、DataManager:數(shù)據(jù)管理器

  • 使用第三方框架AFNetworking創(chuàng)建的數(shù)據(jù)管理器,使用GET請(qǐng)求相關(guān)數(shù)據(jù)。

5、ViewControllers:控制器

6、views:界面

  • JFSuspensionView:懸浮按鈕View
  • JFHomeNewsTableViewCell:首頁cell,繼承自UITableViewCell
  • JFMenuView:菜單界面
  • JFNewsClassificationView新聞分類界面繼承自UIView

7、pods:項(xiàng)目所用到的第三方框架

  • Masonry :Masonry是目前最流行的AutoLayout框架。推薦追求Masonry

  • AFNetworking:是一個(gè)非常方便的網(wǎng)絡(luò)請(qǐng)求庫,可以輕松實(shí)現(xiàn)各種網(wǎng)絡(luò)請(qǐng)求,比如經(jīng)常使用的GET請(qǐng)求、POST請(qǐng)求等。

  • MJRefresh:李明杰老師寫的下拉刷新框架,使用方法很簡(jiǎn)單。

  • MJExtension:json數(shù)據(jù)轉(zhuǎn)模型的框架,也是李明杰老師寫的,用法都很簡(jiǎn)單。相關(guān)用法可以看:iOS的學(xué)習(xí)筆記38 MJExtension使用

  • SDWebImage:目前最受歡迎的圖片下載第三方框架,使用率很高。

  • MBProgressHUD:是一個(gè)顯示HUD窗口的第三方類庫,用法簡(jiǎn)單。

各框架的具體用法網(wǎng)上很多資料,不再贅述!

三、代碼

1、搭建數(shù)據(jù)模型

Paste_Image.png

這是我們用chalers抓取的json格式的數(shù)據(jù),根據(jù)MJExtension的使用方法建立數(shù)據(jù)模型,先分別創(chuàng)建JFResponseModel、JFFeedsModel、JFPostModel、JFCategoryModel四個(gè)類,繼承自NSObject。
然后我們慢慢從json數(shù)據(jù)的最里層向外層聲明你所需要的對(duì)應(yīng)參數(shù)(如果你還不了解MJExtension,建議你先看看他的官網(wǎng)說明文檔,或者iOS的學(xué)習(xí)筆記38 MJExtension使用),切記參數(shù)可以自行選擇創(chuàng)建,但是模型的類型一個(gè)不能少,參數(shù)名一定要一樣,如果命名有沖突MJExtension提供的有相應(yīng)的方法進(jìn)行映射。例如:將沖突的參數(shù)description名映射到subhead

/** 設(shè)置模型屬性名和字典key之間的映射關(guān)系 */
+ (NSDictionary *)mj_replacedKeyFromPropertyName {
    /* 返回的字典,key為模型屬性名,value為轉(zhuǎn)化的字典的多級(jí)key */
    return @{@"subhead":@"description"};
}

1.1 JFCategoryModel數(shù)據(jù)模型

#import <Foundation/Foundation.h>

@interface JFCategoryModel : NSObject

/** 新聞?lì)愋停ㄔO(shè)計(jì)、娛樂、智能等)*/
@property (nonatomic, copy) NSString *title;

@end

1.2 JFPostModel數(shù)據(jù)模型

#import <Foundation/Foundation.h>

@class JFCategoryModel;

@interface JFPostModel : NSObject

/** 新聞標(biāo)題*/
@property (nonatomic, copy) NSString *title;
/** 副標(biāo)題*/
@property (nonatomic, copy) NSString *subhead;
/** 出版時(shí)間*/
@property (nonatomic, assign) NSInteger publish_time;
/** 配圖*/
@property (nonatomic, copy) NSString *image;
/** 評(píng)論數(shù)*/
@property (nonatomic, assign) NSInteger comment_count;
/** 點(diǎn)贊數(shù)*/
@property (nonatomic, assign) NSInteger praise_count;
/** 新聞文章鏈接(html格式)*/
@property (nonatomic, copy) NSString *appview;

@property (nonatomic, strong) JFCategoryModel *category;

@end

1.3 JFFeedsModel數(shù)據(jù)模型

#import <Foundation/Foundation.h>

@class JFPostModel;

@interface JFFeedsModel : NSObject

/** 文章類型(以此來判斷cell(文章顯示)的樣式)*/
@property (nonatomic, copy) NSString *type;

/** 文章配圖 */
@property (nonatomic, copy) NSString *image;

@property (nonatomic, strong) JFPostModel *post;

@end
```

上面所提到的參數(shù)名沖突導(dǎo)致的參數(shù)名不一致問題的解決方法:
```
#import "JFPostModel.h"

@implementation JFPostModel

/** 設(shè)置模型屬性名和字典key之間的映射關(guān)系 */
+ (NSDictionary *)mj_replacedKeyFromPropertyName {
    /* 返回的字典,key為模型屬性名,value為轉(zhuǎn)化的字典的多級(jí)key */
    return @{@"subhead":@"description"};
}
@end
```

**1.4 JFResponseModel數(shù)據(jù)模型**

```
#import <Foundation/Foundation.h>

@class JFFeedsModel;

@interface JFResponseModel : NSObject

/** 下拉加載時(shí)判斷是否還有更多文章 false:沒有 true:有*/
@property (nonatomic, copy) NSString *has_more;

/** 下拉加載時(shí)需要拼接到URL中的key*/
@property (nonatomic, copy) NSString *last_key;

@property (nonatomic, strong) JFFeedsModel *feeds;

@end
```

**1.5 JFBannersModel數(shù)據(jù)模型**

JFBannersModel模型與JFFeedsModel參數(shù)一樣,所以繼承自JFFeedsModel就好
```
#import "JFFeedsModel.h"

@interface JFBannersModel : JFFeedsModel

@end
```
看起來模型很麻煩,只要你理清思路,掌握[MJExtension](https://github.com/CoderMJLee/MJExtension)用法,建立模型是很簡(jiǎn)單的,最主要是模型建好后,在后面使用數(shù)據(jù)時(shí)會(huì)非常方便。

####2、DataManager數(shù)據(jù)管理器
JFHomeNewsDataManager.h文件中添加一個(gè)請(qǐng)求新聞數(shù)據(jù)的方法和一個(gè)請(qǐng)求數(shù)據(jù)成功后回調(diào)的block方法。

```
#import <Foundation/Foundation.h>

typedef void(^JFHomeNewsDataManagerBlock)(id data);

@interface JFHomeNewsDataManager : NSObject

//  請(qǐng)求數(shù)據(jù)成功后返回新聞數(shù)據(jù)回調(diào)的block
@property (nonatomic, copy) JFHomeNewsDataManagerBlock newsDataBlock;

//  請(qǐng)求新聞數(shù)據(jù)
- (void)requestHomeNewsDataWithLastKey:(NSString *)lastKey;

- (void)newsDataBlock:(JFHomeNewsDataManagerBlock)block;

@end
```

JFHomeNewsDataManager.m

```
#import "JFHomeNewsDataManager.h"

#import <AFNetworking.h>
#import "JFConfigFile.h"

#define kTimeOutInterval 10

@implementation JFHomeNewsDataManager

#pragma mark - 創(chuàng)建請(qǐng)求者
- (AFHTTPSessionManager *)manager {
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    manager.requestSerializer.timeoutInterval = kTimeOutInterval;
    manager.responseSerializer = [AFHTTPResponseSerializer serializer];
    //設(shè)置相應(yīng)內(nèi)容類(這里根據(jù)所請(qǐng)求的數(shù)據(jù)類型可自行選擇)
    manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json",
                                                         @"text/html",
                                                         @"image/jpeg",
                                                         @"image/png",
                                                         @"application/octet-stream",
                                                         @"text/json",
                                                         nil];
    return manager;
}

#pragma mark - GET方式請(qǐng)求新聞數(shù)據(jù)
- (void)requestHomeNewsDataWithLastKey:(NSString *)lastKey {
    AFHTTPSessionManager *manager = [self manager];
    //拼接URL
    NSString *urlString = [NSString stringWithFormat:@"http://app3.qdaily.com/app3/homes/index/%@.json?",lastKey];
    
    [manager GET:urlString parameters:nil progress:^(NSProgress * _Nonnull downloadProgress) {
        
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {

       //  JSON數(shù)據(jù)轉(zhuǎn)字典
        NSDictionary *dataDictionary = [NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingMutableContainers error:nil];
        
        if (self.newsDataBlock) {
            self.newsDataBlock([dataDictionary valueForKey:@"response"]);
        }
        
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        
    }];
}

- (void)newsDataBlock:(JFHomeNewsDataManagerBlock)block {
    self.newsDataBlock = block;
}

@end
```

使用GET方法請(qǐng)求數(shù)據(jù),將last_key參數(shù)拼接到URL中:

```
//拼接URL NSString *urlString = [NSString stringWithFormat:@"http://app3.qdaily.com/app3/homes/index/%@.json?",lastKey];
```

打斷點(diǎn)看我們請(qǐng)求到的JSON數(shù)據(jù)轉(zhuǎn)換成字典dataDictionary里的內(nèi)容:
![Paste_Image.png](http://upload-images.jianshu.io/upload_images/1707533-efed74831eb90760.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
response里的數(shù)據(jù)是我們需要處理的,所以用`valueForKey:`方法拿到其數(shù)據(jù)返回給JFHomeViewController:
```
[dataDictionary valueForKey:@"response"]
```
數(shù)據(jù)處理部分到此算是告一段落,接下來就是要把數(shù)據(jù)展示到界面上,然后實(shí)現(xiàn)好奇心日?qǐng)?bào)的交互動(dòng)畫。

####3、UI布局
**3.1 項(xiàng)目中實(shí)現(xiàn)的三種不同的cell樣式**

**cellType對(duì)應(yīng)的就是數(shù)據(jù)模型JFFeedsModel中的type**

*  cellType = 0,UITableViewCell的樣式是上方新聞配圖、然后是新聞標(biāo)題,最下面是副標(biāo)題。


![Paste_Image.png](http://upload-images.jianshu.io/upload_images/1707533-6087c4e69830994a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

*  cellType = 1,UITableViewCell的樣式是新聞配圖在右側(cè),左側(cè)是新聞標(biāo)題,在其下面是新聞種類、評(píng)論數(shù)和點(diǎn)贊數(shù)。

![Paste_Image.png](http://upload-images.jianshu.io/upload_images/1707533-e46475c4a7e0bb11.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

cellType = 2,UITableViewCell的樣式和cellType = 0時(shí)基本一致,就多了最下面的新聞種類、評(píng)論數(shù)和點(diǎn)贊數(shù)。

![Paste_Image.png](http://upload-images.jianshu.io/upload_images/1707533-e1f48cba97427b66.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

顯然用蘋果提供的cell是不行的,所以創(chuàng)建JFHomeNewsTableViewCell繼承自UITableViewCell,然后我們來自定義cell。

JFHomeNewsTableViewCell.h文件中聲明屬性:
```
#import <UIKit/UIKit.h>

@interface JFHomeNewsTableViewCell : UITableViewCell

/** cell的類型(0、1、2)*/
@property (nonatomic, copy) NSString *cellType;
/** 配圖*/
@property (nonatomic, copy) NSString *newsImageName;
/** 標(biāo)題*/
@property (nonatomic, copy) NSString *newsTitle;
/** 副標(biāo)題*/
@property (nonatomic, copy) NSString *subhead;

/**
 *  新聞?lì)愋停ㄔO(shè)計(jì)、智能、娛樂等)
 */
@property (nonatomic, copy) NSString *newsType;
/** 該條新聞的評(píng)論數(shù)*/
@property (nonatomic, copy) NSString *commentCount;
/** 點(diǎn)贊數(shù)*/
@property (nonatomic, copy) NSString *praiseCount;
/** 新聞發(fā)布時(shí)間*/
@property (nonatomic, assign) NSInteger time;

@end
```
動(dòng)態(tài)的設(shè)置cell的樣式(frame)是在`- (void)layoutSubviews;`方法中,這里我把相關(guān)代碼都放在了`- (void)customUI;`方法中,這里使用了[Masonry](https://github.com/SnapKit/Masonry)自動(dòng)布局,具體代碼不在上了,可以下載**[JFQDaily源碼](https://github.com/zhifenx/JFQDaily)**看`JFHomeNewsTableViewCell`類文件。
 ```
- (void)layoutSubviews {
    [super layoutSubviews];
    [self customUI];
}
```
使用[Masonry](https://github.com/SnapKit/Masonry)時(shí)有一點(diǎn)一定要**注意**,必須先把子控件添加到父控件上才能用[Masonry](https://github.com/SnapKit/Masonry)去自動(dòng)布局,否則父控件上沒有相應(yīng)的子控件何談布局呢。

在JFHomeViewController.m文件中重寫UITableView的`- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;`代理方法來動(dòng)態(tài)設(shè)置cell的高度;同樣是根據(jù)類型判斷。

```
/// 根據(jù)cell類型返回cell高度
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    JFHomeNewsTableViewCell *cell = self.cell;
    if ([cell.cellType isEqualToString:@"0"]) {
        return 330;
    }else if ([cell.cellType isEqualToString:@"2"]) {
        return 360;
    }else {
        return 130;
    }
}
```

**3.2 懸浮按鈕(JFSuspensionView)**

3.2.1 懸浮按鈕實(shí)現(xiàn)的原理:
* 其實(shí)很簡(jiǎn)單,就是在JFHomeViewController控制器的View上添加一個(gè)JFSuspensionView,只是要在homeNewsTableView之上,使用下面方法或者使用`- (void)insertSubview:(UIView *)view aboveSubview:(UIView *)siblingSubview;`方法,此時(shí)當(dāng)你滑動(dòng)UITableView的時(shí)候按鈕就是懸浮不動(dòng)的。

```
- (void)loadView {
    [super loadView];
    
    [self.view addSubview:self.homeNewsTableView];
    [self.view addSubview:self.jfSuspensionView];
}
```
3.2.2 在JFSuspension.h文件中用枚舉定義了懸浮按鈕的四種Tag類型和四種block回調(diào)方法,其實(shí)四種Tag類型一一對(duì)應(yīng)四個(gè)回調(diào)函數(shù),通過判斷Tag類型來執(zhí)行相應(yīng)的block函數(shù)。

```
#import <UIKit/UIKit.h>

/// 懸浮按鈕種類(tag)枚舉
typedef NS_ENUM(NSInteger, JFSuspensionButtonStyle) {
    JFSuspensionButtonStyleQType = 1,   //  Qlogo樣式 (彈出JFMenuView)
    JFSuspensionButtonStyleCloseType,   //  關(guān)閉樣式(關(guān)閉JFMenuView)
    JFSuspensionButtonStyleBackType,    //  返回樣式(返回到JFHomeViewController根View)
    JFSuspensionButtonStyleBackType2    //  返回樣式2(返回到JFMenuView)
};

typedef void(^JFSuspensionViewBlock)();

@interface JFSuspensionView : UIView

/** 懸浮按鈕,設(shè)置按鈕樣式(tag)*/
@property (nonatomic, assign) NSInteger JFSuspensionButtonStyle;

/** 彈出菜單界面*/
@property (nonatomic, copy) JFSuspensionViewBlock popupMenuBlock;

/** 關(guān)閉菜單界面*/
@property (nonatomic, copy) JFSuspensionViewBlock closeMenuBlock;

/** 返回到homeNewsViewController*/
@property (nonatomic, copy) JFSuspensionViewBlock backBlock;

/** 返回到JFMenuView*/
@property (nonatomic, copy) JFSuspensionViewBlock backToMenuViewBlock;

- (void)popupMenuBlock:(JFSuspensionViewBlock)block;

- (void)closeMenuBlock:(JFSuspensionViewBlock)block;

- (void)backBlock:(JFSuspensionViewBlock)block;

- (void)backToMenuViewBlock:(JFSuspensionViewBlock)block;

@end
```

懸浮按鈕綁定的`- (void)clickSuspensionButton:(UIButton *)sender`點(diǎn)擊事件處理方法,通過tag判斷需執(zhí)行的事件。

```
- (void)clickSuspensionButton:(UIButton *)sender {
    if (_suspensionButton.tag == JFSuspensionButtonStyleQType || _suspensionButton.tag == JFSuspensionButtonStyleCloseType) {
          //需要做的事情...
    }
    
    //彈出菜單界面
    if (_suspensionButton.tag == JFSuspensionButtonStyleQType) {
          //需要做的事情...
    }
    
    //關(guān)閉菜單界面
    if (_suspensionButton.tag == JFSuspensionButtonStyleCloseType) {
       //需要做的事情...
    }
    
    //返回到homeNewsViewController
    if (_suspensionButton.tag == JFSuspensionButtonStyleBackType) {
          //需要做的事情...
    }
    
    //返回到JFMenuView
    if (_suspensionButton.tag == JFSuspensionButtonStyleBackType2) {
          //需要做的事情...
    }
}
```
3.3.3  上滑隱藏懸浮按鈕,下滑顯示懸浮按鈕。
在JFHomeViewController中實(shí)現(xiàn)UIScrollDelegate代理方法
```
#pragma mark --- UIScrollDelegate
/// 滾動(dòng)時(shí)調(diào)用
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    if (scrollView.contentOffset.y > _contentOffset_Y + 80) {
        [self suspensionWithAlpha:0];
    } else if (scrollView.contentOffset.y < _contentOffset_Y) {
        [self suspensionWithAlpha:1];
    }
}

/// 停止?jié)L動(dòng)時(shí)調(diào)用
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
    _contentOffset_Y = scrollView.contentOffset.y;
}

/// 設(shè)置懸浮按鈕view透明度,以此顯示和隱藏懸浮按鈕
- (void)suspensionWithAlpha:(CGFloat)alpha {
    [UIView animateWithDuration:0.3 animations:^{
        [self.jfSuspensionView setAlpha:alpha];
    }];
}
```
**3.3 菜單(JFMenuView)界面布局**
下圖層級(jí)關(guān)系對(duì)照源碼看,清晰明了?。↗FNewsClassificationView層級(jí)關(guān)系和JFMenuView一樣)
![Paste_Image.png](http://upload-images.jianshu.io/upload_images/1707533-78e998496135b76c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

懶加載模糊層:
```
- (UIVisualEffectView *)blurEffectView {
    if (!_blurEffectView) {
        UIBlurEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark];
        _blurEffectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];
        _blurEffectView.frame = self.frame;
    }
    return _blurEffectView;
}
```
想了解設(shè)置模糊效果可以看[iOS效果---模糊效果匯總](http://www.itdecent.cn/p/6a1489c1e549)

###四、彈簧動(dòng)畫效果
彈簧動(dòng)畫效果是用**Facebook**開源的[pop動(dòng)畫引擎](https://github.com/facebook/pop),簡(jiǎn)單使用的話推薦看:[POP介紹與使用實(shí)踐(快速上手動(dòng)畫)](http://www.itdecent.cn/p/a138a8832452?utm_campaign=hugo&utm_medium=reader_share&utm_content=note&utm_source=weibo#%E5%AE%98%E6%96%B9%E4%BB%A3%E7%A0%81%E7%A4%BA%E4%BE%8B),下面這段代碼就是實(shí)例化了一個(gè)彈簧動(dòng)畫(POPPropertyAnimation),用來實(shí)現(xiàn)菜單界面的彈出效果。

```
/** pop動(dòng)畫
 *  POPPropertyAnimation    動(dòng)畫屬性
 *  view                    動(dòng)畫對(duì)象
 *  offset                  偏移量
 *  speed                   動(dòng)畫速度
 */
- (void)popAnimationWithView:(UIView *)view Offset:(CGFloat)offset speed:(CGFloat)speed {
    POPSpringAnimation *popSpring = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerPositionY];
    popSpring.toValue = @(view.center.y + offset);
    popSpring.beginTime = CACurrentMediaTime();
    popSpring.springBounciness = 11.0f;
    popSpring.springSpeed = speed;
    [view pop_addAnimation:popSpring forKey:@"positionY"];
}
```

菜單的隱藏動(dòng)畫使用的是蘋果提供的UIView的動(dòng)畫,如下隱藏菜單的頂部View和底部View。
```
/// 動(dòng)畫隱藏headerView和footerView
- (void)hideMenuViewAnimation {
    [UIView animateWithDuration:0.1 animations:^{
        [self headerViewOffsetY:-KHeaderViewH];
        [self footerViewOffsetY:JFSCREENH_HEIGHT];
    } completion:^(BOOL finished) {
        //隱藏JFMenuView
        [self setHidden:YES];
    }];
}
```
如上用原生的UIView動(dòng)畫加[pop動(dòng)畫引擎](https://github.com/facebook/pop)就可以實(shí)現(xiàn)懸浮按鈕和菜單view的彈簧效果,若想動(dòng)畫效果更加自然,是需要耐心的調(diào)整[pop動(dòng)畫引擎](https://github.com/facebook/pop)屬性。

**總結(jié):**這篇文章不是一個(gè)細(xì)致講解這個(gè)項(xiàng)目的文檔,結(jié)合這篇文章去看**[JFQDaily源碼](https://github.com/zhifenx/JFQDaily)**相信你會(huì)有所收獲的,畢竟是三天寫出來的東西,代碼可能有不規(guī)范的地方,歡迎指出糾正,出于好奇心和喜歡,一氣呵成的寫完了主要功能,還有一些細(xì)節(jié)需要優(yōu)化和完善,如果你喜歡,歡迎留言、點(diǎn)贊加關(guān)注,方便我們學(xué)習(xí)交流,也是給我前進(jìn)增加一份動(dòng)力。感謝你的耐心閱讀!

####個(gè)人項(xiàng)目:[iOS-(仿美團(tuán))城市選擇器+自動(dòng)定位+字母索引](http://www.itdecent.cn/p/40bc4b6ddceb)
最后編輯于
?著作權(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 第三方庫、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,037評(píng)論 4 61
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,733評(píng)論 25 709
  • 01 第十次,我把閨蜜夏季和我的準(zhǔn)男友堵在床上。 六月的太陽炙烤著大地,我卻渾身發(fā)抖...
    木薇清閱讀 1,670評(píng)論 38 38
  • 2016.9.16 最近總覺得能量不夠,一直在調(diào)整自己。當(dāng)自己感覺不是很好的時(shí)候就用學(xué)習(xí)來調(diào)整自己的心態(tài),黎明前的...
    施以諾閱讀 399評(píng)論 0 0
  • 今天吃完晚飯,吃得飽飽的,然后躺在床上看了會(huì)電視劇。一時(shí)興起,想騎車出去逛逛。從門口的下坡騎車沖下去,感覺像飛起來...
    dadadasim閱讀 192評(píng)論 0 0

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