zoukankan      html  css  js  c++  java
  • 百思不得姐之"我的"模块功能(六)

    一 功能图和知识点

    1 功能图部分:(因为网速的原因,网页部分没有载入出来,可是功能完善)

    这里写图片描写叙述

    2 该部分能学到的知识点概括:

    >1 UITableView的使用(简单)
    >2 UICollectionView的使用
    >3 请求数据
    >4 模型
    >5 自己定义cell
    >6 清除缓存
    >7 细节处理

    二 确定搭建方式

    1 思考: 由整个app运行的效果图来看,是一个tableView,而且须要分组.界面的下半部分能够通过设置footerView来载入collectionView
    2 结论: 直接用storyboard来载入,在storyboard中设置分组样式,静态表格.用代码和storyboard结合的方式达到总体的效果.

    三 storyboard

    1 创建一个storyboard,注意storyboard中的设置.注意勾选选项,否则会出不了结果.

    图一:

    这里写图片描写叙述

    2 在Main文件里的创建控制器的方法,採用storyboard载入

    代码:

    UIStoryboard *storyBoard = [UIStoryboard storyboardWithName:@"XFJMeViewController" bundle:nil];
        //载入箭头指向的控制器
        XFJMeViewController *meVC = [storyBoard instantiateInitialViewController];
        XFJNavigationController *nav4 = [[XFJNavigationController alloc] initWithRootViewController:meVC];
        [self addChildViewController:nav4];
    3 可能会出现的现象: 假设发现载入不出storyboard.那么原因是因为创建类的时候,系统默认的让组和行数为0,所以载入不出来.

    四 设置tableView的尾部视图—->是一个UICollectionViewCell

    1 注意点: collectionView必须有的步骤

    —-> 1> 必须设置流水布局
    —-> 2> 必须注冊
    —-> 3> 必须自己定义cell

    2 想法: 因为创建collectionView和设置有关数据代码比較多,那么我们採取抽出一个方法,用来设置collectionView.

    五 collectionView代码部分

    #pragma mark - 加入尾部视图
    - (void)setUpFooterView
    {
        //流水布局
        UICollectionViewFlowLayout *flowLayout = ({
            UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
            //设置尺寸
            flowLayout.itemSize = CGSizeMake(XFJ_itemsWH ,XFJ_itemsWH);
            //设置垂直间距和水平间距
            flowLayout.minimumInteritemSpacing = margin;
            flowLayout.minimumLineSpacing = margin;
            flowLayout;
        });
    
        //创建collectionView
        UICollectionView *collectionView = ({
            UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 0, 0, 0) collectionViewLayout:flowLayout];
            //设置背景颜色
            collectionView.backgroundColor = XFJ_globeColor;
            //设置尾部视图为collectionView
            self.tableView.tableFooterView = collectionView;
            //设置数据源代理
            collectionView.dataSource = self;
            //设置代理
            collectionView.delegate = self;
            //赋值
            self.collectionView = collectionView;
            //设置collectionView不能滚动
            collectionView.scrollEnabled = NO;
            collectionView;
        });
        //载入xib的时候注冊用
        [collectionView registerNib:[UINib nibWithNibName:@"XFJMeCollectionViewCell" bundle:nil] forCellWithReuseIdentifier:ID];
    }

    六 模型

    1 经过查看接口文档,模型中仅仅须要以下的数据

    //icon(头像);name(姓名);url(网址)
    @property (nonatomic, strong) NSString *icon;
    
    @property (nonatomic, strong) NSString *name;
    
    @property (nonatomic, strong) NSString *url;

    2 模型的处理方式,採用MJ框架字典转模型

    七 载入数据

    框架部分採用: MJ;AFN框架

    1 三大步:

    —-> 1> 创建会话管理者;
    —-> 2> 设置请求參数(包含:包装请求參数)
    —-> 3> 发送请求(包含:字典转模型;计算cell的相关数据)

    2 须要书写的代码量比較大,我们单独抽出一个方法来写该部分的功能

    #pragma mark - 载入数据
    - (void)setUpData
    {
        //查看接口文档:请求方式:GET 请求地址:http://api.budejie.com/api/api_open.php
        //请求參数:a = square ; c = topic
        //模型參数:icon;name;url
        //创建会话管理者
        AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
        //设置请求參数
        NSMutableDictionary *dict = [NSMutableDictionary dictionary];
        //包装请求參数
        dict[@"a"] = @"square";
        dict[@"c"] = @"topic";
        //发送请求
        [manager GET:@"http://api.budejie.com/api/api_open.php" parameters:dict progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
            //因为是字典数组.那么取出数组来转
            NSArray *array = responseObject[@"square_list"];
            //运用mj框架字典转模型
            self.meItems = [XFJMeItem mj_objectArrayWithKeyValuesArray:array];
            //写入plist文件,方便阅读
            [responseObject writeToFile:@"/Users/xiaofeng/Desktop/BuDeJie/Me.plist" atomically:YES];
            //调用处理数据的方法
            [self sloveData];
            //刷新表格
            [self.collectionView reloadData];
            //计算collectionView的高度
            //取出模型数组中的元素
            NSInteger count = self.meItems.count;
            //计算行数
            NSInteger rows = (count - margin) / cols + margin;
            //计算collectionView的总高度
            CGFloat cellH = XFJ_itemsWH * rows + (rows - margin) * margin;
            //collectionView的总高度
            self.collectionView.XFJ_Height = cellH;
            //依据内容自适应
            self.tableView.tableFooterView = self.collectionView;
        } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
            NSLog(@"error");
        }];
    }

    八 collectionView的数据源方法

    1 组数(不写默觉得1)

    2 行数(由模型的数量决定)

    3 cell的内容(由相应的模型决定)

    数据源码:

    #pragma mark - collectionView数据源方法(组数)--->能够不写,默觉得1
    - (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
    {
        return 1;
    }
    
    #pragma mark - 行数
    - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
    {
        return self.meItems.count;
    }
    
    #pragma mark - cell的内容
    - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
    {
        XFJMeCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:ID forIndexPath:indexPath];
    
        cell.meItem = self.meItems[indexPath.row];
    
        return cell;
    }

    九 自己定义cell

    1 自己定义cell採用xib的方式进行cell数据的展示

    —-> 採用xib的原因: 通过观察app此模块的样式,cell的样式都是一样的,固定不变的,所以能够採用xib的形式来描写叙述

    2 通过拖线的方式,我们能够通过拿到xib中设置的属性来给xib中属性赋值

    3 在自己定义cell中定义模型属性,重写模型的set方法

    —-> 重写原因: 用来作为设置cell内容的调用,直接通过set方法来设置

    4 代码部分

    #pragma mark - 提供模型的set方法
    - (void)setMeItem:(XFJMeItem *)meItem
    {
        _meItem = meItem;
    
        [self.iconImageView sd_setImageWithURL:[NSURL URLWithString:meItem.icon]];
    
        self.nameLabel.text = meItem.name;
    }

    十 须要用到的部分參数

    1 注意const的书写原因: 不让外界改动变量

    static NSString * const ID = @"cell";
    static NSInteger const cols = 4;
    static CGFloat const margin = 1;
    #define XFJ_itemsWH (XFJ_screenW - (cols - 1) * margin) / cols

    十一 点击cell的业务逻辑

    1 怎样推断点击的cell跳转的是网页还是控制器?

    —-> 思路: 1> 依据点击的反应(网页反应时间过长) 2> 依据服务器的数据

    2 点击cell跳转到safari(第一种)

    —-> 长处:1> 使用方便,实现简单,代码量少

    —-> 缺点:2> 该方法是从ios9開始使用的,无法满足ios9之前的版本号

    —-> 3> 有进度条,可是进度条并不真实,是一种假象,是做给用户看的一种假象.

    —–> 2.1 设置collectionView的代理为控制器
    //设置代理
            collectionView.delegate = self;
    —–> 2.2 点击某行cell就会调用以下代理方法
    #pragma mark - 代理方法(点击某个cell调用)
    - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
    {
        NSLog(@"点击了cell");
        //取出相应的cell
        XFJMeItem *meItem = self.meItems[indexPath.row];
        //推断字符串中是否含有http(假设不含有了就直接return)
        if (![meItem.url containsString:@"http"]) {
            return;
        }
        //含有了在运行
        NSURL *url = [NSURL URLWithString:meItem.url];
        //创建safari控制器(第一种方式)
        SFSafariViewController *safari = [[SFSafariViewController alloc] initWithURL:url];
        //mdel出控制器
    //    [self presentViewController:safari animated:YES completion:nil];
        [self.navigationController pushViewController:safari animated:YES];
        self.navigationController.navigationBarHidden = YES;
        //设置代理
        safari.delegate = self;  
    }
    2.3 通过设置safari的代理为控制器,那么也会运行以下的方法
    #pragma mark - safari的代理方法
    - (void)safariViewControllerDidFinish:(SFSafariViewController *)controller
    {
        [self.navigationController popViewControllerAnimated:YES];
    //    [self dismissViewControllerAnimated:YES completion:nil];
        self.navigationController.navigationBarHidden = NO;
    }

    3 点击cell跳转到WKWebViewcontroller(另外一种)

    —-> 3.1 长处和缺点

    缺点:

    —-> 1> 须要导入WebKit框架
    —-> 2> 须要自己实现进度条读取的功能

    长处:

    —-> 1> 该方法是苹果从ios8開始推出使用的,这样的方法能满足全部ios版本号的开发.总体功能和safari一样,可是进度条的读取更加真实.
    —-> 3.2 使用步骤
    —-> 1> 自定控制器,创建xib文件
    —-> 2> 对进度条自己主动布局
    —-> 3> 在点击某行collectionView的cell中,实现对自己定义WebViewController的跳转
    —-> 4> 在自己定义的控制器中实现对进度条的监听和对观察者的移除
    —-> 3.3 代码块部分:
    代码块一:创建控制器而且push出控制器
    //另外一种方法:(ios8才有)
        //创建控制器
        XFJWebViewController *webViewController = [[XFJWebViewController alloc] init];
        //赋值
        webViewController.url = url;
        //push
        [self.navigationController pushViewController:webViewController animated:YES];
    代码块二:创建WebView加入到自己定义的控制器的view中(该部分是主旨部分,是WebView起到的载入网页的作用)
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        //创建UIWebView对象
        WKWebView *webView = [[WKWebView alloc] init];
        //赋值
        self.webView = webView;
        //设置尺寸
        webView.frame = self.view.bounds;
        //将webView插入到view中
        [self.view insertSubview:webView atIndex:0];
    
        //创建请求
        NSURLRequest *request = [NSURLRequest requestWithURL:self.url];
        //请求
        [webView loadRequest:request];
        //监听web中的进度(KVO)----self去监听webView的estimatedProgress值的变化
        [webView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:nil];
    }
    代码块三:(因为代码块二实现了监听,那么仅仅要有值的变化,就会调用以下的方法)
    //仅仅要监听值的变化,就会调用
    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
    {
        //进度条的变化
        self.progressView.progress = self.webView.estimatedProgress;
        //控制进度条
        self.progressView.hidden = self.progressView.progress >= 1;
    }
    代码块四:移除观察者(一定要移除,否则会出现莫名其妙的错误)
    #pragma mark - 移除监听
    - (void)dealloc
    {
        [self.webView removeObserver:self forKeyPath:@"estimatedProgress"];
    }

    十二 清除缓存业务类

    1 创建一个业务类,用来清除该部分功能的缓存,这里我就不细说了,直接抽取一个业务类,然后附上文件给大家參考

    2 业务类的思路:1> 先获取文件尺寸(caches) 2> 删除目录中全部文件

    十三 细节处理

    十三 细节处理

    1 处理cell之间的距离—>演示样例程序是一样的(设置顶部的额外滚动区域)

    //分组样式默认头部和尾部都有一定的滚动区域
        self.tableView.sectionFooterHeight = 10;
        self.tableView.sectionHeaderHeight = 0;
    
        //设置顶部额外滚动区域
        self.tableView.contentInset = UIEdgeInsetsMake(-25, 0, 0, 0);

    2 处理collectionView最后面几个空格

    思路:往空格处加入空的模型,有多少空格就加入多少个空模型(该方法调用:是在请求数据,字典转模型之后,因为仅仅有知道有多少模型,collectionView才干计算总共cell的位置,才干知道后面有多少个空格,针对的往里面加入空的模型)
    #pragma mark - 处理数据(往最后的空格中加入空的模型)
    - (void)sloveData
    {
        //取出模型中的数据
        NSInteger count = self.meItems.count;
        //计算空格数
        NSInteger exte = count % cols;//9 % 4 = 1;
        //补充模型
        if (exte) {
            exte = cols - exte;
            //创建空的模型
            for (int i = 0; i < exte; i++) {
                XFJMeItem *meItem = [[XFJMeItem alloc] init];
                //加入模型
                [self.meItems addObject:meItem];
            }
        }
    }

    十四 计算collectionView行数的万能公式(不外传的)

    1 count:总的模型个数

    2 cols:cell的列数

    3 rows:行数

    —> 行数: rows = (count - 1) / cols + 1;

    十五 总结

    1 当假设点击cell的时候,选择push出控制器来载入内容,那么要特别的注意push的时候要隐藏顶部的导航条,可是pop的时候,顶部的导航条一定要开启,否则会将内容隐藏.

    2 处理文件内容缓存问题要特别注意将空的文件排除掉,否则会多出内容.可是大家不是必需将代码写一遍,我接下来给大家附上处理该模块的业务类,你们能够自己封装一下,到时候直接拷贝用即可,不是必需写了.

    3 最后,大家有什么问题虽然给我提出来,我一定尽力解答.兴许我还会奉上百思不得姐进一步的完善代码,假设大家觉得写得还可,麻烦关注我的官方博客,谢谢!!!!

    ——————–>业务类

    .h文件里附实使用方法

    .h文件

    //
    //  XFJFileManager.h
    //  BuDeJie
    //
    //  Created by 肖锋 on 12/4/6.
    //  Copyright © 2012年 XFJ. All rights reserved.
    //
    
    /**
     *  专门用于处理文件业务
     *
     *  使用方法:1 先获取目录尺寸
     *
     *  2 删除目录全部的文件
     */
    #import <Foundation/Foundation.h>
    
    @interface XFJFileManager : NSObject
    
    /**
     *  获取目录尺寸
     *
     *  @param directoryPath 目录全路径
     *
     *  @return 目录尺寸
     */
    + (NSInteger)getDirectorySize:(NSString *)directoryPath;
    
    
    /**
     *  删除目录下全部文件
     *
     *  @param directoryPath 目录全路径
     */
    + (void)removeDirectoryPath:(NSString *)directoryPath;
    
    @end
    

    .m文件

    //
    //  XFJFileManager.m
    //  BuDeJie
    //
    //  Created by  on 12/4/6.
    //  Copyright © 2012年 肖锋. All rights reserved.
    //
    
    #import "XFJFileManager.h"
    
    @implementation XFJFileManager
    
    + (void)removeDirectoryPath:(NSString *)directoryPath
    {
        NSFileManager *mgr = [NSFileManager defaultManager];
    
        BOOL isDirectory;
        BOOL isExist = [mgr fileExistsAtPath:directoryPath isDirectory:&isDirectory];
    
        if (!isExist || !isDirectory) {
            // 报错:抛异常
            NSException *excp = [NSException exceptionWithName:@"filePathError" reason:@"传错,必须传目录路径" userInfo:nil];
    
            [excp raise];
    
        }
    
        NSArray *subpaths = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:directoryPath error:nil];
    
        for (NSString *subPath in subpaths) {
    
            NSString *filePath = [directoryPath stringByAppendingPathComponent:subPath];
    
            [[NSFileManager defaultManager] removeItemAtPath:filePath error:nil];
        }
    }
    
    // 获取目录尺寸
    + (NSInteger)getDirectorySize:(NSString *)directoryPath
    {
        // 获取文件管理者
        NSFileManager *mgr = [NSFileManager defaultManager];
    
        BOOL isDirectory;
        BOOL isExist = [mgr fileExistsAtPath:directoryPath isDirectory:&isDirectory];
    
        if (!isExist || !isDirectory) {
            // 报错:抛异常
            NSException *excp = [NSException exceptionWithName:@"filePathError" reason:@"传入文件路径错误.." userInfo:nil];
    
            [excp raise];
    
        }
    
    
        /*
         获取这个目录中全部文件路径,然后累加 = 目录的尺寸
         */
    
        // 获取目录下全部的文件
        NSArray *subpaths = [mgr subpathsAtPath:directoryPath];
        NSInteger totalSize = 0;
    
        for (NSString *subpath in subpaths) {
    
            // 拼接文件全路径
            NSString *filePath = [directoryPath stringByAppendingPathComponent:subpath];
    
            // 排除目录
            BOOL isDirectory;
            BOOL isExist = [mgr fileExistsAtPath:filePath isDirectory:&isDirectory];
            if (!isExist || isDirectory) continue;
    
            // 隐藏文件
            if ([filePath containsString:@".DS"]) continue;
    
            // 指定路径获取这个路径的属性
            // attributesOfItemAtPath:仅仅能获取文件属性
            NSDictionary *attr = [mgr attributesOfItemAtPath:filePath error:nil];
            NSInteger size = [attr fileSize];
    
            totalSize += size;
        }
    
        return totalSize;
    
    }
    
    @end
    
  • 相关阅读:
    yzm10铺瓷砖 yzm10原创系列
    如何统计博客园的个人博客访问量
    Hybrid设计--账号体系的建设
    Hybrid设计--核心交互
    Hybrid设计--H5和Native,收口
    MySQL数据类型--与MySQL零距离接触 3-2 外键约束的要求解析
    MySQL数据类型--与MySQL零距离接触2-14MySQL默认约束
    css3径向渐变
    MySQL数据类型--与MySQL零距离接触2-13MySQL唯一约束
    MySQL数据类型--与MySQL零距离接触2-12主键约束
  • 原文地址:https://www.cnblogs.com/tlnshuju/p/7191037.html
Copyright © 2011-2022 走看看