好奇心日?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效果:

如果你是一個(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ù):
- GET請(qǐng)求,拼接url路徑,第一次獲取數(shù)據(jù)url是:
http://app3.qdaily.com/app3/homes/index/0.json? - 獲取last_key后上拉加載時(shí)GET的URL
http://app3.qdaily.com/app3/homes/index/1478819276_1478777270.json?



上面是用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)

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:控制器
- JFHomeViewController:首頁控制器
- JFReaderViewController:文章閱讀器控制器,使用WXWebView搭建。關(guān)于WXWebView推薦iOS (一) - UIWebView 與 WKWebView . 基本使用
6、views:界面
- JFSuspensionView:懸浮按鈕View
- JFHomeNewsTableViewCell:首頁cell,繼承自UITableViewCell
- JFMenuView:菜單界面
- JFNewsClassificationView新聞分類界面繼承自UIView
7、pods:項(xiàng)目所用到的第三方框架
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ù)模型

這是我們用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)容:

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)題。

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

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

顯然用蘋果提供的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一樣)

懶加載模糊層:
```
- (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)