<<高仿MONO>>項(xiàng)目知識(shí)點(diǎn)整理

由于一直做公司項(xiàng)目,所以有些技能沒有去實(shí)踐過,所以一直想做一個(gè)項(xiàng)目練練手,然后找到了MONO這個(gè)軟件,里面的內(nèi)容界面都做的很精致,用charles抓了一下,發(fā)現(xiàn)接口都是可以獲取的,于是就開始做了.目前只做了一部分,記錄了過程中一些覺得值得記錄的問題,然后分享給大家.

如果大家覺得這篇文章對(duì)你有幫助,希望大家能給個(gè)star,你們的鼓勵(lì)是我前進(jìn)的動(dòng)力 --項(xiàng)目地址.

注意這里只是給出個(gè)簡單思路,詳細(xì)過程還請(qǐng)看源碼.

一.全屏拖拽效果

全屏拖拽

首先導(dǎo)入FDFullscreenPopGestureRTRootNavigationController這兩個(gè)庫,然后在tabbar中將RTRootNavigationController設(shè)為你每個(gè)視圖控制器的根視圖就可以實(shí)現(xiàn)這種push效果了.FDFullscreenPopGesture是實(shí)現(xiàn)全屏拖拽手勢(shì),RTRootNavigationController是改變導(dǎo)航欄的動(dòng)畫效果.#

二.導(dǎo)航欄視圖填充滿


本身導(dǎo)航欄左側(cè)是始終有一個(gè)返回按鈕的位置的,如果直接設(shè)置view為titleview的話并不能填充滿,我的做法是在view上放一個(gè)backview再在backview上放控件,backview的x設(shè)為-25,這樣的話就可以將導(dǎo)航欄填充滿了.

三.簡化UITableViewDelegate,UITableViewDataSource代理方法

首先注冊(cè)cell

 [self.tableView registerClass:[RecommendImageBgCell class] forCellReuseIdentifier:NSStringFromClass([RecommendImageBgCell class])];
     [self.tableView registerClass:[RecommendReadCell class] forCellReuseIdentifier:NSStringFromClass([RecommendReadCell class])];
     [self.tableView registerClass:[RecommendImagesCell class] forCellReuseIdentifier:NSStringFromClass([RecommendImagesCell class])];
    [self.tableView registerClass:[RecommendMusicCell class] forCellReuseIdentifier:NSStringFromClass([RecommendMusicCell class])];
     [self.tableView registerClass:[RecommendVideoCell class] forCellReuseIdentifier:NSStringFromClass([RecommendVideoCell class])];
    [self.tableView registerClass:[RecommendPicturesCell class] forCellReuseIdentifier:NSStringFromClass([RecommendPicturesCell class])];
    [self.tableView registerClass:[RecommendTeaCell class] forCellReuseIdentifier:NSStringFromClass([RecommendTeaCell class])];

高度的計(jì)算因?yàn)槲矣玫氖?a target="_blank" rel="nofollow">SDAutolayout進(jìn)行布局,所以只用一行代碼就可以將所有的cell的高度計(jì)算下來.

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    RecommendModel *model = _dataArray[indexPath.row];
    return [self.tableView cellHeightForIndexPath:indexPath model:model keyPath:@"recommendModel" cellClass:NSClassFromString(model.cellIdentifier) contentViewWidth:SCREEN_WIDTH];
}

這里注意所有cell的model名字需要一直,而且他們都是可以共用同樣的model.
接下來就是設(shè)置cell了,這里我給出了詳細(xì)的注釋

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    RecommendModel *model = _dataArray[indexPath.row];//獲取model
    //MNBaseTableViewCell為所有cell的父類
    MNBaseTableViewCell *cell;
    NSString *cellIdentifier;
    //后臺(tái)會(huì)根據(jù)內(nèi)容的不同給出不同的object_type,根據(jù)這個(gè)來設(shè)置不同cell的identifier.
    cellIdentifier = model.cellIdentifier;
    //因?yàn)榻o每個(gè)cell注冊(cè)過了,所以這里拿到identifier就可以找到具體的cell
    cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
    //這里用kvc給cell賦值
    [cell setValue:_dataArray[indexPath.row] forKey:@"recommendModel"];
    return cell;
}

四.文字閃爍出現(xiàn)

效果是下面這樣的,當(dāng)拖動(dòng)到一定位置的時(shí)候圖片上面的文字閃爍出現(xiàn),之后就不再閃爍了.


這上面的label用了第三方RQShineLabel,其實(shí)原理就是先讓所有文字字體顏色透明度為0,再加個(gè)定時(shí)器,隨機(jī)讓文字字體顏色透明度變?yōu)?.
那么如何在拖拽到一定位置的時(shí)候再執(zhí)行閃爍方法而不是剛加載這個(gè)cell的時(shí)候就執(zhí)行呢.我的做法是這樣的.

//cell將要被加載
-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    //判斷是否是需要閃爍文字的cell
    if ([cell isKindOfClass:[RecommendImageBgCell class]]) {
        RecommendImageBgCell *bgCell = (RecommendImageBgCell *)cell;
        _bgCell = bgCell;
        //如果tableview剛刷新出來,這個(gè)cell就在界面上的話就執(zhí)行閃爍方法
        if (tableView.contentOffset.y <= 0 && bgCell.y <= 0) {
            [_bgCell shineText];
            return;
        }
        //給一個(gè)全局變量來監(jiān)視cell滑動(dòng)情況
        _bgCellY = bgCell.y;
    }
}

-(void)scrollViewDidScroll:(UIScrollView *)scrollView{
    //當(dāng)cell滑動(dòng)到一定位置的時(shí)候就閃爍
    if ((_bgCellY - scrollView.contentOffset.y <= (SCREEN_HEIGHT / 4 + KTabBarHeight)) && _bgCellY > 0) {
        [_bgCell shineText];
        _bgCellY = -10;
    }
}

五.音樂播放效果

效果如下所示,當(dāng)點(diǎn)擊cell播放音樂的時(shí)候,CD會(huì)轉(zhuǎn)起來,導(dǎo)航欄最右側(cè)的CD按鈕也會(huì)轉(zhuǎn)起來.



[圖片上傳中...(13.gif-7a2593-1528170837139-0)]

首先音頻播放這塊我用的是FreeStreamer,寫一個(gè)單例類MNMusicPlayer繼承自FSAudioStream,里面除了初始化和單獨(dú)的一些方法外還為音樂播放的各種狀態(tài)添加了通知.通過通知來決定動(dòng)畫的顯示或消失.
好,接下來就在cell上自定義2個(gè)view,一個(gè)是旋轉(zhuǎn)的MusicCDView,一個(gè)是下面歌曲進(jìn)度的MusicProgressView.
在MusicCDView中,先創(chuàng)建一個(gè)CABasicAnimation,再通過給self.layer添加或移除動(dòng)畫來實(shí)現(xiàn)CD旋轉(zhuǎn)和隱藏效果.

 //創(chuàng)建一個(gè)全局的動(dòng)畫
    _anim = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
    _anim.fromValue = [NSNumber numberWithFloat:0.f];
    _anim.toValue = [NSNumber numberWithFloat: M_PI *2];
    _anim.duration = 10;
    _anim.autoreverses = NO;
    _anim.fillMode = kCAFillModeForwards;
    _anim.repeatCount = MAXFLOAT;

動(dòng)畫效果

//播放音樂
-(void)playMusic
{
    if (self.alpha != 1) {
        [UIView animateWithDuration:0.5 animations:^{
            self.alpha = 1;
        }];
    }
    [self.layer addAnimation:_anim forKey:@"rotaion"];
}
//暫停音樂
-(void)stopMusic
{
    if (self.alpha != 0) {
        [UIView animateWithDuration:0.5 animations:^{
            self.alpha = 0;
        }];
    }
    [self.layer removeAnimationForKey:@"rotaion"];
}

最后在收到通知的時(shí)候執(zhí)行就行了.

 @weakify(self)
    [[[NSNotificationCenter defaultCenter] rac_addObserverForName:@"stopMusic" object:nil] subscribeNext:^(NSNotification *notification) {
        @strongify(self)
        [self stopMusic];
    }];
    [[[NSNotificationCenter defaultCenter] rac_addObserverForName:@"playMusic" object:nil] subscribeNext:^(NSNotification *notification) {
        @strongify(self)
        //播放音樂的URL和此URL地址相同時(shí)才播放
        if ([notification.object isEqualToString:self.model.music_url]) {
            [self playMusic];
        }
    }];

同時(shí)別忘了給他的父視圖設(shè)置.clipsToBounds = YES屬性,不然CD盤就全部顯示出來了.

六.圖片裁剪

在圖片瀏覽中,小圖的ImageView的寬高比都是1:1的比例,而原圖的比例并不是,所以需要截取圖片正中間1:1的部分,這樣點(diǎn)擊瀏覽圖片效果就會(huì)很舒服,效果如下:



這里用到了imageView.layer.contentsRect這個(gè)屬性來截取需要顯示的圖片部分,點(diǎn)擊查看contentsRect.(這里服務(wù)器給出了原圖的寬和高了)
這里再解釋一下.
比如一張圖片如下所示,它的寬高比是2:1.
d0c8a786c9177f3e2fb5a1987ccf3bc79e3d56a5.jpg

如果要截取左半部分,則這樣寫:imageView.layer.contentsRect = CGRectMake(0, 0, 0.5, 1);前2個(gè)參數(shù)表示x和y的錨點(diǎn),如果用(0,0)的話表示從最左上角開始切割,如果用(0,0.5)表示從最左邊高度的一半那里開始切割.后面2個(gè)參數(shù)表示截取的寬高比.所以這里(0, 0, 0.5, 1)后就成了這樣:

要截取正中間這部分1:1的圖片只需要設(shè)置成這樣就可以了:

imageView.layer.contentsRect = CGRectMake((1- 0.5)/2, 0, 0.5, 1);

好了,現(xiàn)在我們假設(shè)一張圖片它的寬和高分別是width和height,且width > height.那么我們要截取正中間1:1的部分就可以寫成這樣了:

imageView.layer.contentsRect = CGRectMake((1 -(float)height / width) / 2, 0, (float)height / width, 1);

同理,高圖就寫成這樣:

imageView.layer.contentsRect = CGRectMake(0, (1- (float)width / height) / 2, 1, (float)width / height);

在代碼中判斷是寬圖還是高圖再用具體的方法來截取就可以了.

七.收藏動(dòng)畫


做這個(gè)的時(shí)候走了些彎路,最后的做法是在收藏按鈕上面放兩個(gè)imageview,再設(shè)置imageview的animationImages.

八.網(wǎng)頁滑動(dòng)隱藏導(dǎo)航欄和狀態(tài)欄.


這里的做法也很簡單,如下:

-(BOOL)prefersStatusBarHidden
{
    return hiddenStatusBar;
}

hiddenStatusBar是一個(gè)全局Bool變量,在滑動(dòng)的時(shí)候判斷滑動(dòng)方向后來改變hiddenStatusBar的值,再調(diào)用[self setNeedsStatusBarAppearanceUpdate]方法來刷新狀態(tài)欄的顯示或隱藏.導(dǎo)航欄的隱藏和顯示就用[self.navigationController setNavigationBarHidden:BOOL animated:YES];因?yàn)樽铋_始不知道setNeedsStatusBarAppearanceUpdate方法,所以繞了些彎路.

九.網(wǎng)頁閱讀模式


最開始看到這個(gè)閱讀模式的時(shí)候,我誤以為是safari閱讀模式,經(jīng)過仔細(xì)分析發(fā)現(xiàn)不是,他這個(gè)兩個(gè)不同的數(shù)據(jù)源而已.他們針對(duì)第三方來源的閱讀網(wǎng)頁給出來兩個(gè)數(shù)據(jù).一個(gè)是網(wǎng)址url(非閱讀模式),一個(gè)是返回html字段(閱讀模式),只需要添加2個(gè)WKWebView,轉(zhuǎn)換閱讀模式的時(shí)候只需要改變具體的WKWebView的hidden就行了.

十.加載失敗與重新加載


在視圖控制器的基類中寫兩個(gè)方法就可以,一個(gè)是加載失敗的方法.如下:

//加載失敗顯示失敗按鈕與文字,參數(shù)為點(diǎn)擊按鈕執(zhí)行方法
-(void)showPageLoadingFailedWithReloadTarget:(id)target action:(SEL)action
{
    if (!pageLoadingView) {
         pageLoadingView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT - NaviH  - KTabBarHeight)];
        pageLoadingView.backgroundColor = [UIColor colorWithRed:0.86 green:0.89 blue:0.91 alpha:1];
    }
    [pageLoadingView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
    [self.view addSubview:pageLoadingView];
    
    UIButton *reloadImageBtn = [UIButton buttonWithType:UIButtonTypeCustom];
    reloadImageBtn.frame = CGRectMake(0, 0, 40, 40);
    reloadImageBtn.center = CGPointMake(pageLoadingView.width/2, pageLoadingView.height/2);
    [pageLoadingView addSubview:reloadImageBtn];
    [reloadImageBtn setImage:[UIImage imageNamed:@"refresh_btn"] forState:UIControlStateNormal];
    
    UIButton *reloadBtn = [UIButton buttonWithType:UIButtonTypeCustom];
    reloadBtn.frame = CGRectMake(0, reloadImageBtn.bottom + 20, 200, 30);
    reloadBtn.centerX = pageLoadingView.width/2;
    [pageLoadingView addSubview:reloadBtn];
    reloadBtn.titleLabel.font = [UIFont systemFontOfSize:12];
    [reloadBtn setTitleColor:[UIColor colorWithRed:0.66 green:0.66 blue:0.66 alpha:1] forState:UIControlStateNormal];
    [reloadBtn setTitle:@"加載失敗,請(qǐng)點(diǎn)擊重試" forState:UIControlStateNormal];
    
    if (target){
        [reloadImageBtn addTarget:target action:action forControlEvents:UIControlEventTouchUpInside];
        [reloadBtn addTarget:target action:action forControlEvents:UIControlEventTouchUpInside];
    }
}
//顯示正在加載背景圖片
#pragma mark - 正在加載動(dòng)畫
-(void)showPageLoadingProgress
{
    if (!pageLoadingView) {
        pageLoadingView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT - NaviH  - KTabBarHeight)];
        pageLoadingView.backgroundColor = [UIColor colorWithRed:0.86 green:0.89 blue:0.91 alpha:1];
    }
    [pageLoadingView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
    [self.view addSubview:pageLoadingView];
    
    UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(100, 100, 25, 25)];
    imageView.center = CGPointMake(pageLoadingView.width/2, pageLoadingView.height/2);
    [pageLoadingView addSubview:imageView];
    imageView.image = [UIImage imageNamed:@"head-mask-bg"];
    CAKeyframeAnimation* animation = [CAKeyframeAnimation animationWithKeyPath:@"transform"];
    animation.duration = 1;// 動(dòng)畫時(shí)間
    NSMutableArray *values = [NSMutableArray array];
    [values addObject:[NSValue valueWithCATransform3D:CATransform3DMakeScale(0.8, 0.8, 1.0)]];
    [values addObject:[NSValue valueWithCATransform3D:CATransform3DMakeScale(1.2, 1.2, 1.0)]];
    [values addObject:[NSValue valueWithCATransform3D:CATransform3DMakeScale(0.8, 0.8, 1.0)]];
    animation.values = values;
    animation.repeatCount = FLT_MAX;
    [imageView.layer addAnimation:animation forKey:nil];
}

十一.狀態(tài)欄與導(dǎo)航欄的隱藏與顯示


先說狀態(tài)欄,這里先創(chuàng)建一個(gè)BOOL值的成員變量 hiddenStatusBar,再使用方法

-(BOOL)prefersStatusBarHidden
{
    return hiddenStatusBar;
}

在滑動(dòng)的時(shí)候判斷滑動(dòng)方向,改變hiddenStatusBar的值,再調(diào)用下面這個(gè)方法,這是用來調(diào)用prefersStatusBarHidden方法并刷新狀態(tài)欄狀態(tài)的

[self setNeedsStatusBarAppearanceUpdate];

導(dǎo)航欄很簡單,判斷滑動(dòng)方向然后再調(diào)用

[self.navigationController setNavigationBarHidden:NO animated:YES];
或者
[self.navigationController setNavigationBarHidden:YES animated:YES];

結(jié)尾.

這個(gè)項(xiàng)目也是費(fèi)了一些時(shí)間和精力,現(xiàn)在整理其中有遇到的或?qū)W習(xí)到的一些知識(shí)來分享給大家,希望能夠幫助到大家,目前只做了一部分,剩下的會(huì)慢慢做下去,然后再把過程中的知識(shí)點(diǎn)整理出來分享給大家.希望大家能給個(gè)star,你們的鼓勵(lì)是我前進(jìn)的動(dòng)力,謝謝大家.

github地址,歡迎star

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌叽讳,老刑警劉巖羡洁,帶你破解...
    沈念sama閱讀 216,544評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件牵舱,死亡現(xiàn)場離奇詭異九巡,居然都是意外死亡帅腌,警方通過查閱死者的電腦和手機(jī)倦畅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門遮糖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人叠赐,你說我怎么就攤上這事止吁。” “怎么了燎悍?”我有些...
    開封第一講書人閱讀 162,764評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵敬惦,是天一觀的道長。 經(jīng)常有香客問我谈山,道長俄删,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,193評(píng)論 1 292
  • 正文 為了忘掉前任奏路,我火速辦了婚禮畴椰,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘鸽粉。我一直安慰自己斜脂,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,216評(píng)論 6 388
  • 文/花漫 我一把揭開白布触机。 她就那樣靜靜地躺著帚戳,像睡著了一般玷或。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上片任,一...
    開封第一講書人閱讀 51,182評(píng)論 1 299
  • 那天偏友,我揣著相機(jī)與錄音,去河邊找鬼对供。 笑死位他,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的产场。 我是一名探鬼主播鹅髓,決...
    沈念sama閱讀 40,063評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼京景!你這毒婦竟也來了窿冯?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,917評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤醋粟,失蹤者是張志新(化名)和其女友劉穎靡菇,沒想到半個(gè)月后重归,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體米愿,經(jīng)...
    沈念sama閱讀 45,329評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,543評(píng)論 2 332
  • 正文 我和宋清朗相戀三年鼻吮,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了育苟。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,722評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡椎木,死狀恐怖违柏,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情香椎,我是刑警寧澤漱竖,帶...
    沈念sama閱讀 35,425評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站畜伐,受9級(jí)特大地震影響馍惹,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜玛界,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,019評(píng)論 3 326
  • 文/蒙蒙 一万矾、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧慎框,春花似錦良狈、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽遇西。三九已至,卻和暖如春窥突,著一層夾襖步出監(jiān)牢的瞬間努溃,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評(píng)論 1 269
  • 我被黑心中介騙來泰國打工阻问, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留梧税,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,729評(píng)論 2 368
  • 正文 我出身青樓称近,卻偏偏與公主長得像第队,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子刨秆,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,614評(píng)論 2 353

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

  • 1凳谦、通過CocoaPods安裝項(xiàng)目名稱項(xiàng)目信息 AFNetworking網(wǎng)絡(luò)請(qǐng)求組件 FMDB本地?cái)?shù)據(jù)庫組件 SD...
    陽明先生_X自主閱讀 15,979評(píng)論 3 119
  • 【今早起床】5點(diǎn)20【清晨功課】脈輪靜坐、祈禱與心靈禪舞【家務(wù)檢視】保持干凈衡未,物品及時(shí)歸位【健康運(yùn)動(dòng)】堅(jiān)持6杯水尸执、...
    心靜若水1閱讀 209評(píng)論 0 0
  • 如果你喜歡一個(gè)人,不好意思開口說缓醋,憋在心里又難受如失,你可以在熱戀進(jìn)行時(shí)暗示Ta表達(dá)自己的愛意。當(dāng)然送粱,現(xiàn)在傳遞愛的信息...
    05f3ae22a228閱讀 178評(píng)論 0 0
  • 每天上班其實(shí)也并不累褪贵,但是還是感覺身體被掏空。于是急切的想要來場說走就走的旅行抗俄。但是慫人就是慫人脆丁,找不到小伙伴,又...
    亦塵亦塵閱讀 190評(píng)論 0 1
  • 1.堆內(nèi)存和棧內(nèi)存的區(qū)別是什么动雹? 線程的堆內(nèi)存空間是共享的槽卫,棧內(nèi)存空間才是獨(dú)立的(堆共享,棧獨(dú)立)胰蝠。 2.wait...
    吳國友閱讀 99評(píng)論 0 0