百思不得姐之"我的"模块功能(六)
一 功能图和知识点
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
百思不得姐之"我的"模块功能(六)的更多相关文章
- 基于Metronic的Bootstrap开发框架--工作流模块功能介绍(2)
本篇继续<基于Metronic的Bootstrap开发框架--工作流模块功能介绍>,继续介绍基于Metronic的Bootstrap开发框架的工作模块功能,介绍工作流模块中相关业务表单的界 ...
- 基于Metronic的Bootstrap开发框架--工作流模块功能介绍
在很早之前的随笔里面,已经介绍了WInform框架中工作流模块的功能,不过由于工作流模块中界面处理部分比较麻烦,一直没有在Bootstrap框架中进行集成,最近由于项目的关系,花了不少精力,把工作流模 ...
- Winform开发框架中的内容及文档管理模块功能介绍
在开发项目的时候,我们有一些场景需要编辑一些HTML文档,作为内容发布系统的一部分,有时候也需要对一些文档如WORD文档进行编辑管理,这样需要我们对这些内容及文档进行合适的管理.本文主要介绍在WInf ...
- (转)关于ES6的 模块功能 Module 中export import的用法和注意之处
关于ES6的 模块功能 Module 中export import的用法和注意之处 export default 的用法 export default命令用于指定模块的默认输出.显然,一个模块只能有一 ...
- Android图片加载框架最全解析(六),探究Glide的自定义模块功能
不知不觉中,我们的Glide系列教程已经到了第六篇了,距离第一篇Glide的基本用法发布已经过去了半年的时间.在这半年中,我们通过用法讲解和源码分析配合学习的方式,将Glide的方方面面都研究了个遍, ...
- phalcon:整合官方多模块功能,方便多表查询
phalcon:整合官方多模块功能,方便多表查询 项目分为: namespace Multiple\Backend; namespace Multiple\Frontend; 目录结构如下: publ ...
- [Err] 1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''<h1 style="text-align: center;">php
[Err] 1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL s ...
- 【python库模块】Python subprocess模块功能与常见用法实例详解
前言 这篇文章主要介绍了Python subprocess模块功能与常见用法,结合实例形式详细分析了subprocess模块功能.常用函数相关使用技巧. 参考 1. Python subprocess ...
- Spring框架各模块功能介绍
一. Spring是什么? Spring由Rod johnson开发: 是一个非常活跃的开源框架: 它帮助分离项目组件(对象)之间的依赖关系: 它的主要目的是简化企业开发 二. Spring的核心概念 ...
随机推荐
- 搞定vim的窗口操作
最近在给学生演示数据结构代码时,发现用一般的方法总会有不方便,如果使用ide又觉得太浪费了,后来觉得用vim就够了,使用buffer总会需要页面调来跳出,学生看起来容易迷糊.所以就研究了下vim的窗口 ...
- Spring Boot学习——Spring Boot简介
最近工作中需要使用到Spring Boot,但是以前工作中没有用到过Spring Boot,所以需要学习下Spring Boot.本系列笔记是笔者学习Spring Boot的笔记,有错误和不足之处,请 ...
- C#TreeView读取Xml,TreeView导出到Xml
实现功能有1.根据Xml生成TreeView2.双击修改节点3.右键添加子节点或添加要节点4.右键删除当前选择的节点5.将修改后的TreeView重新生成Xml文档 其实这个主要是实现 了Xml生成T ...
- /* Dr黄的技术博客开通啦 */
以前懒得写技术日志, 现在终于发现重要性.. mark一下这个里程碑.
- AC日记——通往奥格瑞玛的道路 洛谷 P1462
通往奥格瑞玛的道路 思路: 二分+spfa: 二分最大费用,然后判断只走小于等于二分答案的点是否可以花费小于体力上限的血量: 来,上代码: #include <cstdio> #inclu ...
- react 使用antd导航组件实现事件传递并局部刷新DOM
我们要实现一个通过点击顶部导航来查询左侧菜单的一个功能 在这个功能中,我们要应用到onClick={this.headNavMenuList.bind(this)}方法来传递点击 不同按钮来传递不同的 ...
- Wannafly交流赛1 B 硬币[数学思维/贪心]
链接:https://www.nowcoder.com/acm/contest/69/B来源:牛客网 蜥蜴的生日快到了,就在这个月底! 今年,蜥蜴的快乐伙伴之一壁虎想要送好多个1元硬币来恶整蜥蜴. 壁 ...
- HDFS写文件过程分析
转自http://shiyanjun.cn/archives/942.html HDFS是一个分布式文件系统,在HDFS上写文件的过程与我们平时使用的单机文件系统非常不同,从宏观上来看,在HDFS文件 ...
- iphone/iOS 访问本地数据库sqlite3
Phone也支持访问本地数据库Sqlite 3.这里简单的介绍一下iPhone上Sqlite 3的使用方法. 首先需要在项目中引用Sqlite 3的开发包,下面是在iPhone SDK 3.0下的目录 ...
- implement-stack-using-queues(easy,但也有思考价值)
https://leetcode.com/problems/implement-stack-using-queues/ 还有种方法,就是利用同一个队列,知道队列长度前提下,把内容从头到尾,再向尾部依次 ...