iOS項(xiàng)目-網(wǎng)易新聞項(xiàng)目筆記

在項(xiàng)目之前,最好下載該App或者GitHub源碼跑一下看一下效果枕面,該項(xiàng)目旨在練習(xí)UI及網(wǎng)絡(luò)數(shù)據(jù)的處理愿卒,推薦初學(xué)者邊參考筆記邊進(jìn)行代碼的編寫

分析項(xiàng)目,確定 UI 框架

  • 導(dǎo)航欄可以左右拖動(dòng)潮秘,可以點(diǎn)擊琼开,優(yōu)先考慮 UICollectionView,cell重用方面可以減小內(nèi)存枕荞,點(diǎn)擊對(duì)應(yīng)的項(xiàng)目的時(shí)候字體放大柜候,變?yōu)榧t色
  • 新聞信息欄既可以上下拖動(dòng)來查看該類別不同新聞(顯然是UITableView)搞动,也可以左右拖動(dòng)來切換不同新聞?lì)l道(UICollectionView),則需要把 N 個(gè)tableView 放到一個(gè) collectionView
  • 數(shù)據(jù)方面渣刷,先獲取新聞?lì)l道的json數(shù)據(jù)鹦肿,根據(jù)其tid值獲取對(duì)應(yīng)頻道的新聞數(shù)據(jù)網(wǎng)址,網(wǎng)址內(nèi)包括新聞的圖片辅柴、標(biāo)題等信息

一. 新聞?lì)l道

  • WPFChannelView: 承載整個(gè)新聞?lì)l道的collectionView

  • WPFChannelCell: 每個(gè)新聞?lì)l道的collectionViewCell

  • WPFChannel: 每個(gè)新聞?lì)l道對(duì)象

1. 創(chuàng)建WPFChannel

  • 新聞?lì)l道名稱-->tname
  • 新聞?lì)l道的標(biāo)識(shí)符箩溃,用來加載對(duì)應(yīng)新聞?lì)悇e的欄目-->tid
  • 快速創(chuàng)建方法-->字典轉(zhuǎn)模型
    + (instancetype)channalWithDict:(NSDictionary *)dict {

        WPFChannal *channal = [[WPFChannal alloc] init];

        [channal setValuesForKeysWithDictionary:dict];

        return channal;
    }

    #warning 當(dāng)只使用字典中部分鍵值對(duì)的時(shí)候,最好加上這個(gè)方法
    // kvc碌嘀,防止找不到對(duì)應(yīng)的key值而崩潰
    - (void)setValue:(id)value forUndefinedKey:(NSString *)key {
        // 什么都不用寫
    }

2. 創(chuàng)建 WPFChannalCell 類涣旨,繼承UICollectionCell

  • 每一個(gè)頻道cell 都綁定一個(gè)WPFChannel對(duì)象
    @property (nonatomic, strong) WPFChannal *channal;
  • 有一個(gè) label 顯示對(duì)應(yīng)頻道文字
  • 重寫構(gòu)造方法的時(shí)候?qū)嵗痩abel控件
    - (instancetype)initWithFrame:(CGRect)frame {
        if (self = [super initWithFrame:frame]) {

            // 初始化label
            self.lblName = [[UILabel alloc] init];

            // 設(shè)置文本框字號(hào)
            self.lblName.font = [UIFont systemFontOfSize:16];

            // 設(shè)置文本框文字居中
            self.lblName.textAlignment = NSTextAlignmentCenter;

            // 將label 添加到cell中
            [self.contentView addSubview:self.lblName];
        }
        return self;
    }
  • 重寫 WPFChannel 對(duì)象的 set 方法進(jìn)行數(shù)據(jù)的傳遞,通過判斷:在選擇狀態(tài)下顯示紅字大字號(hào)筏餐,非選擇狀態(tài)下顯示黑色普通字號(hào)
    - (void)setChannal:(WPFChannal *)channal {
        _channal = channal;
        // 進(jìn)行名稱的賦值
        self.lblName.text = channal.tname;

        // 如果當(dāng)前cell 處于被選狀態(tài)开泽,放大字號(hào)(20)牡拇,紅色
        if (self.isSelected) {

            // 獲取當(dāng)前view 的父view
            UICollectionView *collectionView = (UICollectionView *)self.superview;

            self.lblName.font = [UIFont systemFontOfSize:20];
            self.lblName.textColor = [UIColor redColor];

        // 如果不是被選狀態(tài)魁瞪,正常字號(hào)(16),黑色
        } else {
            self.lblName.font = [UIFont systemFontOfSize:16];
            self.lblName.textColor = [UIColor blackColor];
        }

        // 在這句代碼之后惠呼,lblName 才有frame
        [self.lblName sizeToFit];

        // 改變文本框中心點(diǎn)
        self.lblName.center = CGPointMake(self.bounds.size.width/2, self.bounds.size.height/2);
    }

sizeToFit方法快速計(jì)算label 的長(zhǎng)度(也可以通過字?jǐn)?shù)及字號(hào)確定导俘,但是略麻煩)

3. 創(chuàng)建 WPFChannalView 類,繼承UICollectionView

  • 重寫其構(gòu)造方法:除了常規(guī)的設(shè)置數(shù)據(jù)源和代理對(duì)象剔蹋,取消滾動(dòng)條旅薄,注冊(cè)cell,還要在這里進(jìn)行數(shù)據(jù)的加載泣崩,采用異步+主隊(duì)列的方式來保證加載完 UI 界面后再進(jìn)行網(wǎng)絡(luò)數(shù)據(jù)的加載
    - (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(nonnull UICollectionViewLayout *)layout {

        // 首先要執(zhí)行父類的構(gòu)造方法
        if (self = [super initWithFrame:frame collectionViewLayout:layout]) {

            // 設(shè)置導(dǎo)航欄背景顏色
            self.backgroundColor = [UIColor grayColor];

            // 設(shè)置數(shù)據(jù)源對(duì)象和代理對(duì)象
            self.dataSource = self;
            self.delegate = self;

            // 取消橫向滾動(dòng)條
            self.showsHorizontalScrollIndicator = NO;

            // 注冊(cè)cell
            [self registerClass:[WPFChannalCell class] forCellWithReuseIdentifier:kIdentifier];

            // 異步+主隊(duì)列:保證執(zhí)行順序少梁,在加載完畢UI界面后再加載數(shù)據(jù)
            dispatch_async(dispatch_get_main_queue(), ^{
                [self loadServerDataWithUrlString:@"http://localhost/topic_news.json"]; // 自定義方法
            });
        }
        return self;
    }
  • 加載服務(wù)器數(shù)據(jù),使用第三方框架(AFNetworking)矫付,NSURLSession也可以凯沪,在這里將獲取到的網(wǎng)絡(luò)數(shù)據(jù)轉(zhuǎn)化為模型對(duì)象,再放到模型數(shù)組中
    - (void)loadServerDataWithUrlString:(NSString *)urlString {

        // 利用第三方框架請(qǐng)求服務(wù)器數(shù)據(jù)
        [[AFHTTPSessionManager manager] GET:urlString parameters:nil progress:^(NSProgress * _Nonnull downloadProgress) {
            // 不需要寫東西
        } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {

        #wanring 在這里需要打印一下买优,確定數(shù)據(jù)具體形式7谅怼!I庇烘跺!
    //        NSLog(@"responseObject-->%@", responseObject);
            /*
             打印結(jié)果--》是一個(gè)字典,里面包含一個(gè)名為tList的數(shù)組脂崔,數(shù)組內(nèi)部是一個(gè)個(gè)字典滤淳,打印頭部分如下:
             {
             tList = (
             {
             */

            // 接受獲取的網(wǎng)絡(luò)數(shù)據(jù)
            NSDictionary *channalDict = responseObject;
            NSArray *channalArray = channalDict[@"tList"];

            // 遍歷數(shù)組
            [channalArray enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {

                // 數(shù)組元素是字典類型
                NSDictionary *dict = obj;

                // 進(jìn)行字典轉(zhuǎn)模型
                WPFChannal *channal = [WPFChannal channalWithDict:dict];

                // 將模型對(duì)象添加到模型數(shù)組中
                // 注意該數(shù)組的懶加載
                [self.channals addObject:channal];
            }];

            // 刷新數(shù)據(jù),先加載UICollectionViewDelegate砌左,再加載viewDidLoad
            [self reloadData];

            // 必須有數(shù)據(jù)之后脖咐,選中第一個(gè)cell 才有意義
            NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];

            [self selectItemAtIndexPath:indexPath animated:NO scrollPosition:UICollectionViewScrollPositionNone];

        } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {

            NSLog(@"channalView: error-->%@", error);
        }];
    }

注意先打印一遍數(shù)據(jù)伤柄,再根據(jù)數(shù)據(jù)類型的層級(jí)關(guān)系轉(zhuǎn)化為具體對(duì)象

  • 動(dòng)態(tài)改變 UIlabel 大小的方法.
    // 一旦實(shí)現(xiàn)了下面的代理方法, layout.itemSize 就是失效.
    - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(nonnull NSIndexPath *)indexPath {

        // 1. 獲取當(dāng)前行的模型對(duì)象的文字
        WPFChannal *channal = self.channals[indexPath.row];
        NSString *name = channal.tname;

        // 2. 返回對(duì)應(yīng)文字的label的尺寸
        return [self getLabelSizeWithTname:name];
    }

    // 獲取對(duì)應(yīng)文字的label的尺寸
    - (CGSize)getLabelSizeWithTname:(NSString *)name {

        UILabel *label = [[UILabel alloc] init];

        label.text = name;

        label.font = [UIFont systemFontOfSize:16];

        [label sizeToFit];

        return label.frame.size;
    }
  • 每組有幾個(gè)cell,每個(gè)cell 具體內(nèi)容文搂,在這里就不贅述了

二. 具體新聞信息

  • WPFMainData: 每一條具體新聞的對(duì)象

  • WPFMainTableViewCell: 存放每個(gè)新聞的tableViewCell

  • WPFMainTableView: 存放一個(gè)頻道所有新聞消息的tableView

  • WPFMainCollectionViewCell: 存放一個(gè)頻道的tableView 的collectionViewCell

  • WPFMainCollectionView: 存放所有頻道新聞消息的collectionView

1. 創(chuàng)建 WPFMainData适刀,每個(gè)新聞信息對(duì)象

  • 需要綁定的屬性

    • title --> 新聞標(biāo)題
    • digest --> 新聞?wù)睒?biāo)題
    • imgsrc --> 新聞配圖
    • replyCount --> 回帖數(shù)(使用NSNumber煤蹭,如果是null可以識(shí)別笔喉,NSInteger則不可以,會(huì)報(bào)錯(cuò))
  • 快速進(jìn)行字典轉(zhuǎn)模型的創(chuàng)建硝皂,方法同WPFChannel 新聞?lì)l道對(duì)象的創(chuàng)建

    + (instancetype)mainDataWithDict:(NSDictionary *)dict {

        WPFMainData *data = [[WPFMainData alloc] init];

        [data setValuesForKeysWithDictionary:dict];

        return data;
    }

    // 有些變量名沒有定義常挚,防止崩潰
    - (void)setValue:(id)value forUndefinedKey:(NSString *)key {
        // 什么都不用寫
    }

2. 創(chuàng)建 WPFMainTableViewCell

重寫構(gòu)造方法中實(shí)例化UI控件

重寫綁定對(duì)象的set方法中進(jìn)行數(shù)據(jù)的添加

layoutSubViews 中進(jìn)行控件frame的布局

  • 外部綁定:一個(gè)WPFMainData 對(duì)象
    @property (nonatomic, strong) WPFMainData *data;
  • 內(nèi)部綁定:一個(gè)圖片框、三個(gè)label(標(biāo)題/副標(biāo)題/跟帖數(shù))
    /** 圖片框 */
    @property (nonatomic, strong) UIImageView *imgViewIcon;

    /** 標(biāo)題label */
    @property (nonatomic, strong) UILabel *lblTitle;

    /** 副標(biāo)題(摘要)label */
    @property (nonatomic, strong) UILabel *lblDigest;

    /** 跟帖數(shù)label */
    @property (nonatomic, strong) UILabel *lblReplyCount;
  • 重寫cell構(gòu)造方法稽物,實(shí)例化UI控件及分割線奄毡,注意:重寫tableViewCell 的構(gòu)造方法一定要用 -initWithStyle reuseIdentifier:!贝或!
    - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {

    #warning 重寫cell 的構(gòu)造方法一定要用這個(gè):鸸!
        if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {

            // 實(shí)例化UI控件
            self.imgViewIcon = [[UIImageView alloc] init];
            self.imgViewIcon.backgroundColor = [UIColor orangeColor];

            self.lblDigest = [[UILabel alloc] init];
            self.lblDigest.font = [UIFont systemFontOfSize:13];
            self.lblDigest.numberOfLines = 2;

            self.lblReplyCount = [[UILabel alloc] init];
            self.lblReplyCount.backgroundColor = [UIColor lightGrayColor];
            self.lblReplyCount.font = [UIFont systemFontOfSize:12];

            self.lblTitle = [[UILabel alloc] init];
            self.lblTitle.font = [UIFont systemFontOfSize:16];

            // 將UI控件添加到當(dāng)前cell 中
            [self.contentView addSubview:self.imgViewIcon];
            [self.contentView addSubview:self.lblTitle];
            [self.contentView addSubview:self.lblReplyCount];
            [self.contentView addSubview:self.lblDigest];

            // cell 分割線
            UIView *separateLine = [[UIView alloc] initWithFrame:CGRectMake(0, 79, self.frame.size.width, 1)];

            separateLine.backgroundColor = [UIColor blackColor];

            [self.contentView addSubview:separateLine];
        }
        return self;
    }
  • 對(duì)控件進(jìn)行布局咪奖,一定在layoutsubviews方法
    - (void)layoutSubviews {
        // 一定要記得調(diào)用父類的該方法
        [super layoutSubviews];

        CGFloat imgX = 8;
        CGFloat imgY = 8;
        CGFloat imgW = 100;
        CGFloat imgH = 64;

        self.imgViewIcon.frame = CGRectMake(imgX, imgY, imgW, imgH);

        self.lblTitle.frame = CGRectMake(imgW + 2*imgX, imgY, self.frame.size.width - 3*imgX - imgW, 15);

        self.lblDigest.frame = CGRectMake(self.lblTitle.frame.origin.x, CGRectGetMaxY(self.lblTitle.frame) + 3, self.lblTitle.frame.size.width, 40);

        // sizeToFit快速得出label實(shí)際大小
        [self.lblReplyCount sizeToFit];
        // 即 label 右下角位置不變
        CGFloat replyX = self.frame.size.width - self.lblReplyCount.frame.size.width - imgX;
        CGFloat replyY = self.frame.size.height - self.lblReplyCount.frame.size.height - imgY;

        self.lblReplyCount.frame = CGRectMake(replyX, replyY, self.lblReplyCount.bounds.size.width, self.lblReplyCount.bounds.size.height);
    }
  • 重寫 data 對(duì)象的 set 方法盗忱,進(jìn)行數(shù)據(jù)的賦值,下載圖片需要用到第三方框架(SDWebImage)并導(dǎo)入頭文件UIImageView+WebCache.h
    - (void)setData:(WPFMainData *)data {
        _data = data;

        // 設(shè)置數(shù)據(jù)
        self.lblTitle.text = data.title;
        self.lblDigest.text = data.digest;
        self.lblReplyCount.text = [NSString stringWithFormat:@"回帖數(shù):%@", data.replyCount];

        // 自動(dòng)下載并顯示圖片
        [self.imgViewIcon sd_setImageWithURL:[NSURL URLWithString:data.imgsrc]];
    }

3. 創(chuàng)建 WPFMainTableView

  • 重寫該類 構(gòu)造方法
    - (instancetype)initWithFrame:(CGRect)frame {
        if (self = [super initWithFrame:frame]) {

            // 設(shè)置數(shù)據(jù)源和代理對(duì)象
            self.delegate = self;
            self.dataSource = self;

            // 注冊(cè)cell
            [self registerClass:[WPFMainTableViewCell class] forCellReuseIdentifier:kMainTableViewCell];

            // 隱藏cell 分割線
            self.separatorStyle = UITableViewCellSeparatorStyleNone;
        }
        return self;
    }
  • 重寫channal對(duì)象的set方法
    - (void)setChannal:(WPFChannal *)channal {
        _channal = channal;

        // 初始值為10羊赵,表示滾動(dòng)到第十條新聞的時(shí)候趟佃,開始加載第二十條信息
        self.index = 10;

        // 清空數(shù)據(jù)源
        [self.newsData removeAllObjects];

        // 刷新數(shù)據(jù)
        [self reloadData];

        // 根據(jù)tid 值獲取當(dāng)前頁面的數(shù)據(jù)
        [self getMainDataWithTid:channal.tid];
    }
  • 根據(jù)tid 值獲取當(dāng)前頁面的數(shù)據(jù)
    - (void)getMainDataWithTid:(NSString *)tid {
        // 數(shù)據(jù)加載原則:
        // 1. 單詞加載的數(shù)據(jù)量能夠鋪滿一個(gè)屏幕
        // 2. 給用戶預(yù)留一個(gè)屏幕的數(shù)據(jù)量作為滾動(dòng)使用

        // 小菊花媽媽課堂開課了!
        [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;

        // 1. 拼接網(wǎng)址字符串
        NSString *urlString = [NSString stringWithFormat:@"http://c.m.163.com/nc/article/headline/%@/0-20.html", tid];

        // 2. 發(fā)送請(qǐng)求
        [[AFHTTPSessionManager manager] GET:urlString parameters:nil progress:^(NSProgress * _Nonnull downloadProgress) {
            //
        } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {

    //        NSLog(@"responseObject-->%@", responseObject);
            /*
             打印結(jié)果:返回的整體是一個(gè)字典昧捷,下面是以tid值為名稱的數(shù)組闲昭,數(shù)組內(nèi)部是一個(gè)個(gè)字典,則根據(jù)其類型進(jìn)行字典轉(zhuǎn)模型

             tid-->T1370583240249
             responseObject-->{
             T1370583240249 = (
             {
             */

            // 1. 獲取整體的字典
            NSDictionary *mainDict = responseObject;

            // 2. 獲取字典下面的數(shù)組
            NSArray *mainArray = mainDict[tid];

            // 3. 遍歷數(shù)組元素
            [mainArray enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {

                // 3.0 轉(zhuǎn)化為正確的類型
                NSDictionary *dict = obj;

                // 3.1 進(jìn)行字典轉(zhuǎn)模型
                WPFMainData *data = [WPFMainData mainDataWithDict:dict];

                // 3.2 將模型添加到模型數(shù)組中
                [self.newsData addObject:data];
            }];

            dispatch_async(dispatch_get_main_queue(), ^{

                // 小菊花隱藏
                [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;

                [self reloadData];
            });

        } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {

            NSLog(@"mainTableView: error-->%@", error);
        }];
    }
  • 每行有幾個(gè)靡挥、每個(gè)cell的具體內(nèi)容序矩、cell單元格高度,在此不一一贅述

3. 創(chuàng)建 WPFMainCollectionViewCell

  • 重寫其構(gòu)造方法:實(shí)例化 WPFMainTableView芹血,并添加到contentView
    - (instancetype)initWithFrame:(CGRect)frame {
        if (self = [super initWithFrame:frame]) {

            WPFMainTableView *tableView = [[WPFMainTableView alloc] initWithFrame:self.bounds];

            self.tableView = tableView;
            [self.contentView addSubview:tableView];
        }
        return self;
    }

3. 創(chuàng)建 WPFMainCollectionView

    - (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout {

        if (self = [super initWithFrame:frame collectionViewLayout:layout]) {

            // 注冊(cè)cell
            [self registerClass:[WPFMainCollectionViewCell class] forCellWithReuseIdentifier:kMainCollectionViewCell];

            // 設(shè)置其代理對(duì)象和數(shù)據(jù)源對(duì)象
            self.delegate = self;
            self.dataSource = self;

            // 去向橫向滾動(dòng)條
            self.showsHorizontalScrollIndicator = NO;

            // 設(shè)置翻頁效果
            self.pagingEnabled = YES;

            // 取消彈簧效果
            self.bounces = NO;
        }
        return self;
    }

三. 數(shù)據(jù)的傳遞

不同類之間進(jìn)行信息的傳遞最好用通知

注意添加監(jiān)聽者的代碼執(zhí)行越早越好贮泞,一般都是重寫類的創(chuàng)建方法的時(shí)候就添加了,還有不要忘記在dealloc 方法中移除監(jiān)聽者

1. 顯示數(shù)據(jù):將channelView 中的channels數(shù)組傳遞給mainCollectionView

  • 在WPFChannalView 中加載服務(wù)器數(shù)據(jù)的方法 loadServerDataWithUrlString 中加載數(shù)據(jù)并成功轉(zhuǎn)化為模型對(duì)象后
    // 將加載到的新聞數(shù)據(jù)傳遞給主界面
    [[NSNotificationCenter defaultCenter] postNotificationName:@"NewsChannelDataLoadSuccess" object:self.channals];
  • 在WPFMainCollectionView 中重寫該類的構(gòu)建方法中接受通知:接受頻道數(shù)據(jù)加載完畢的通知
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(loadChannalDataWithNoti:) name:@"NewsChannelDataLoadSuccess" object:nil];
  • 在WPFMainCollectionView接受到通知加載完畢后實(shí)現(xiàn)的方法,刷新數(shù)據(jù)后就可以加載數(shù)據(jù)了
    - (void)loadChannalDataWithNoti:(NSNotification *)noti {

        self.channals = noti.object;

        [self reloadData];
    }

2. 實(shí)現(xiàn)點(diǎn)擊新聞?lì)l道幔烛,就會(huì)切換到對(duì)應(yīng)的新聞信息板塊

點(diǎn)擊上面的小collectionView啃擦,自動(dòng)切換下面的大collectionView

  • 在WPFChannalView 中,cell被選擇的方法中進(jìn)行信息的傳遞
    - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
        // 1. 獲取被選中的cell
        WPFChannalCell *cell = (WPFChannalCell *)[collectionView cellForItemAtIndexPath:indexPath];

        // 2. 重新設(shè)置模型對(duì)象饿悬,在其set 方法會(huì)自動(dòng)調(diào)整文字格式
        cell.channal = self.channals[indexPath.row];

        // 3. 發(fā)送通知令蛉,改變新聞控制器
        [[NSNotificationCenter defaultCenter] postNotificationName:@"MainCollectionViewChangeToIndexPath" object:indexPath];
    }
  • 同理:cell 的未被選擇方法,調(diào)整文字模式恢復(fù)為黑色正常字號(hào)
    - (void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath {

        // 獲取被選中的cell
        WPFChannalCell *cell = (WPFChannalCell *)[collectionView cellForItemAtIndexPath:indexPath];

        // 重新設(shè)置模型對(duì)象,在其set 方法會(huì)自動(dòng)調(diào)整文字格式
        cell.channal = self.channals[indexPath.row];
    }
  • 在MainCollectionView中珠叔,重寫該類的構(gòu)建方法添加監(jiān)聽者
    // 接受改變新聞?lì)l道的方法
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(changeToIndexPathWithNoti:) name:@"MainCollectionViewChangeToIndexPath" object:nil];
  • 在MainCollectionView中,接受到新聞?lì)l道改變后執(zhí)行的方法
    - (void)changeToIndexPathWithNoti:(NSNotification *)noti {

        // animated: 表面上是是否以動(dòng)畫方式顯現(xiàn)
        // YES: 滾動(dòng)經(jīng)過的所有界面都會(huì)被加載
        // NO: 只加載最后停留的界面
        // 一般為了節(jié)省客戶的流量蝎宇,都使用 NO
        [self scrollToItemAtIndexPath:noti.object atScrollPosition:UICollectionViewScrollPositionNone animated:NO];
    }

3. 拖動(dòng)新聞信息板塊,上面的新聞?lì)l道索引也會(huì)自動(dòng)切換

滑動(dòng)下面的大collectionView祷安,自動(dòng)切換上面的小collectionView

  • 在WPFMainCollectionView 中監(jiān)聽減速方法
    // 減速結(jié)束的代理方法
    - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {

        // 算出頁數(shù):注意這里需要手動(dòng)計(jì)算姥芥,不能直接獲取,因?yàn)楫?dāng)前頁面大多情況下只被拖動(dòng)沒被選擇
        // 道理同新聞?lì)l道的collectionView汇鞭,拖動(dòng)但是沒有選擇
        NSIndexPath *indexPath = [NSIndexPath indexPathForItem:self.contentOffset.x / self.frame.size.width inSection:0];

        [[NSNotificationCenter defaultCenter] postNotificationName:@"changeChannalToIndexPath" object:indexPath];
    }
  • 在WPFChannelView 中重寫該類構(gòu)建方法的時(shí)候添加監(jiān)聽者
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(changeToIndexWithNoti:) name:@"changeChannalToIndexPath" object:nil];
  • 在WPFChannelView 監(jiān)聽到該消息執(zhí)行的方法
    • UICollectionViewScrollPositionCenteredHorizontally 可以自動(dòng)將備選的新聞?lì)l道跳轉(zhuǎn)到界面中央
    - (void)changeToIndexWithNoti:(NSNotification *)noti {
        [self reloadData];

        // 獲取當(dāng)前頁數(shù)并選擇
        [self selectItemAtIndexPath:noti.object animated:YES scrollPosition:UICollectionViewScrollPositionCenteredHorizontally];
    }

補(bǔ)充凉唐,如果想聯(lián)系編程數(shù)學(xué),加深對(duì)collectionView理解的同仁霍骄,可以參考下面的代碼

  • 如果不用UICollectionViewScrollPositionCenteredHorizontally,就在WPFChannelCell的setChannal方法中台囱,如果該cell被選擇代碼塊中,添加以下代碼
    // 中間部分
    if (self.center.x < collectionView.contentSize.width - kWidth/2  &&  self.center.x > kWidth / 2) {

        offsetX = self.center.x - kWidth / 2;

    // 前半屏幕
    } else if(self.center.x < kWidth/2) {

        offsetX = 0;

    // 最后半屏幕
    } else {
        offsetX = collectionView.contentSize.width - kWidth;
    }

    [UIView animateWithDuration:0.5 animations:^{
        collectionView.contentOffset = CGPointMake(offsetX, 0);
    }];

4. 加載更多信息

  • 添加一個(gè)屬性
    @property (nonatomic, assign) NSInteger index;
  • 重寫channal對(duì)象的set方法的時(shí)候?qū)υ搶傩赃M(jìn)行初始賦值
    // 初始值為10读整,表示滾動(dòng)到第十條新聞的時(shí)候簿训,開始加載第二十條信息
    self.index = 10;
  • 在代理方法 tableView: cellForRowAtIndexPath: 即每行的具體內(nèi)容中
    // 如果當(dāng)前加載的行 = 需要加載數(shù)據(jù)的行索引,就加載更多數(shù)據(jù)
    if (indexPath.row == self.index) {

        // 表示再往下拖十條數(shù)據(jù)米间,再次加載
        self.index += 10;

        [self loadMoreDataWithTid:self.channal.tid startIndex:self.index];
    }
  • 加載更多數(shù)據(jù)的方法(可以和第一次加載數(shù)據(jù)的方法進(jìn)行合并)
    - (void)loadMoreDataWithTid:(NSString *)tid startIndex:(NSInteger)index {

        // 小菊花轉(zhuǎn)起來
        [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;

        // 1. 拼接網(wǎng)址字符串强品,%ld-10表示從index 開始往后加載10條數(shù)據(jù)
        NSString *urlString = [NSString stringWithFormat:@"http://c.m.163.com/nc/article/headline/%@/%ld-10.html", tid, index];

        // 2. 發(fā)送請(qǐng)求
        [[AFHTTPSessionManager manager] GET:urlString parameters:nil progress:^(NSProgress * _Nonnull downloadProgress) {
            //
        } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {

            // 1. 獲取整體的字典
            NSDictionary *mainDict = responseObject;

            // 2. 獲取字典下面的數(shù)組
            NSArray *mainArray = mainDict[tid];

            // 3. 遍歷數(shù)組元素
            [mainArray enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {

                // 3.0 轉(zhuǎn)化為正確的類型
                NSDictionary *dict = obj;

                // 3.1 進(jìn)行字典轉(zhuǎn)模型
                WPFMainData *data = [WPFMainData mainDataWithDict:dict];

                // 3.2 將模型添加到模型數(shù)組中
                [self.newsData addObject:data];
            }];

            dispatch_async(dispatch_get_main_queue(), ^{

                // 小菊花不轉(zhuǎn)
                [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;

                [self reloadData];
            });
        } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {

            NSLog(@"mainTableView: error-->%@", error);
        }];
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市车伞,隨后出現(xiàn)的幾起案子择懂,更是在濱河造成了極大的恐慌,老刑警劉巖另玖,帶你破解...
    沈念sama閱讀 211,194評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異表伦,居然都是意外死亡谦去,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門蹦哼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來鳄哭,“玉大人,你說我怎么就攤上這事纲熏∽鼻穑” “怎么了?”我有些...
    開封第一講書人閱讀 156,780評(píng)論 0 346
  • 文/不壞的土叔 我叫張陵局劲,是天一觀的道長(zhǎng)勺拣。 經(jīng)常有香客問我,道長(zhǎng)鱼填,這世上最難降的妖魔是什么药有? 我笑而不...
    開封第一講書人閱讀 56,388評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上愤惰,老公的妹妹穿的比我還像新娘苇经。我一直安慰自己,他們只是感情好宦言,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評(píng)論 5 384
  • 文/花漫 我一把揭開白布扇单。 她就那樣靜靜地躺著,像睡著了一般奠旺。 火紅的嫁衣襯著肌膚如雪令花。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,764評(píng)論 1 290
  • 那天凉倚,我揣著相機(jī)與錄音兼都,去河邊找鬼。 笑死稽寒,一個(gè)胖子當(dāng)著我的面吹牛扮碧,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播杏糙,決...
    沈念sama閱讀 38,907評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼慎王,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了宏侍?” 一聲冷哼從身側(cè)響起赖淤,我...
    開封第一講書人閱讀 37,679評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎谅河,沒想到半個(gè)月后咱旱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,122評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡绷耍,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評(píng)論 2 325
  • 正文 我和宋清朗相戀三年吐限,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片褂始。...
    茶點(diǎn)故事閱讀 38,605評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡诸典,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出崎苗,到底是詐尸還是另有隱情狐粱,我是刑警寧澤,帶...
    沈念sama閱讀 34,270評(píng)論 4 329
  • 正文 年R本政府宣布胆数,位于F島的核電站肌蜻,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏幅慌。R本人自食惡果不足惜宋欺,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評(píng)論 3 312
  • 文/蒙蒙 一齿诞、第九天 我趴在偏房一處隱蔽的房頂上張望祷杈。 院中可真熱鬧宿刮,春花似錦私蕾、人聲如沸踩叭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至焕参,卻和暖如春悔耘,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背我擂。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評(píng)論 1 265
  • 我被黑心中介騙來泰國打工衙吩, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留澈蚌,地道東北人宛瞄。 一個(gè)月前我還...
    沈念sama閱讀 46,297評(píng)論 2 360
  • 正文 我出身青樓杯活,卻偏偏與公主長(zhǎng)得像旁钧,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子或衡,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評(píng)論 2 348

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