文章目录
- 一. 代码生成控件
- 1. 创建设置项目
- ( 1 ) 创建项目 ( ① 选择 Create a new Xcode project | ② 创建 Single View Application 项目 | ③ 设置项目信息 | ④ 设置代码路径并创建 )
- ( 2 ) 界面设置 ( ① 选中 ViewController | ② 属性查看器 -> Simulated Metrics -> Size | ③ 设置 iPhone 4.7-inch )
- 2. 设置按钮及添加事件
- ( 1 ) 添加按钮事件 ( Control + 左键 拖动到 代码中 生成按钮方法 )
- ( 2 ) 修改按钮文字 ( ① 双击控件 | ② 修改 Tittle 属性 )
- 3. 生成 UIView 控件 并 查看 View 层级
- ( 1 ) 代码 生成 UIView 控件 ( ① 创建控件 | ② 设置 frame | ③ 设置颜色 | ④ 添加控件 )
- ( 2 ) 运行并查看效果 ( 查看 View 层次 )
- 4. 代码生成按钮 并 绑定事件
- ( 1 ) 代码生成 按钮 ( ① 创建按钮控件 | ② 设置 frame | ③ 设置文字( 颜色 ) | ④ 设置背景( 前景 )图片 | ⑤ 绑定事件 | ⑥ 添加控件 )
- 二. UIView 属性 和 子控件操作
- ( 1 ) 创建 设置 应用 ( ① 创建应用 | ② 设置界面尺寸 )
- ( 2 ) 设置 Main.storyboard UI 界面 ( ① 背景 )
- ( 3 ) 在 ViewController.m 关联 控件变量 ( ① 按住 Control 拖拽 控件 到 @interface 代码块中 | ② Connect 对话框 设置 名称 类型 )
- ( 4 ) 生成 子组件 代码 ( ① 生成子组件 | ② 设置子组件属性 | ③ 设置子组件 frame 属性 [ 随机位置生成 ] | ④ 添加子组件到父容器中 )
- ( 5 ) 删除 子组件 代码 ( ① 获取子组件数组 | ② 使用 for in 循环删除子组件 | ③ isKindOfClass 判定组件类型 )
- ( 6 ) 删除 指定 Tag 的控件 的 代码 ( ① 调用父控件的 viewWithTag 方法 | ② )
- ( 7 ) UIView 常用方法属性 ( ① tag 属性 | ② removeFromSuperView 方法 | ③ addSubView 方法 | ④ viewWithTag 方法 | ⑤ frame 属性 | ⑥ transform 属性 )
- ( 8 ) 效果展示
- 三. 图片浏览器
- 1. 应用创建 设置
- ( 1 ) 创建 设置 应用 ( ① 创建应用 | ② 设置界面尺寸 )
- 2. UI 控件 设置
- ( 1 ) 设置 Main.storyboard ( 拖入相关控件 )
- ( 2 ) 关联 Main.storyboard 与 ViewController.m ( ① 关联控件变量 | ② 关联方法 | ③ 设置相关的成员变量 )
- 3. 相关知识点
- ( 1 ) UILabel 设置 ( ① 换行设置 | ② 设置行高 | ③ 宽高控制 )
- ( 2 ) UIButton 启用 禁用 ( ① enabled 属性 YES NO )
- ( 3 ) NSArray 和 NSMutableDictionary 存储数据 ( ① NSArray 数组 | ② 字典 )
- 4. 代码逻辑 与 完整代码
- ( 1 ) 代码逻辑 ( ① 边界处理 | ② 按钮处理 | ③ UILabel 文字切换 | ④ UIImageView 图片切换 )
- ( 2 ) 完整代码
- ( 3 ) 效果展示
- 四. Storyboard 添加 配置 及 相关知识点
- 1. 添加 新界面 ( ① 新建 Storyboard | ② 配置 Storyboard | ③ 新建ViewController 代码 )
- ( 1 ) 添加 Storyboard ( ① File -> New -> File | ② iOS -> User Interface -> Storyboard | ③ General -> Deployment -> Main Interface 配置 Storyboard )
- ( 2 ) Storyboard 设置 ( ① 拖动箭头设置启动界面 | ② View Controller 的 Is Initial View Controller 勾选框 设置启动界面 | ③ 关联 ViewController 代码 )
- ( 3 ) 新建 ViewController.m 文件 ( ① File -> New -> File | ② iOS -> Source -> Cocoa Touch Class | ③ Storyboard 中 身份查看器 配置 Class )
- 2. Storyboard 相关知识点 ( ① 删除 Storyboard | ② Storyboard 本质 )
- ( 1 ) 删除 Storyboard ( ① 删除文件及引用 | ② 删除引用 文件保留 )
- ( 2 ) Storyboard 本质 ( XML 文本文件 )
- 3. iOS 应用启动步骤简介
- ( 1 ) iOS 应用启动步骤
- 五. Bundle 简介
- ( 1 ) Bundle 简介
- ( 2 ) 图片放置 位置 ( ① 放在 Assets.xcassets [推荐] | ② 放在根目录[不推荐] )
- ( 3 ) NSBundle 使用 ( ① 获取 NSBundle 对象 | ② 获取 Bundle 目录下 某文件的 全路径 )
- 六. Property List 简介
- ( 1 ) Property List 创建 ( ① New File | ② iOS -> Resource -> Property List | ③ 数据设置 | ④ 类型设置 )
- ( 2 ) 获取 Property List 数据 ( ① 获取 Bundle PList 路径 | ② dictionaryWithContentsOfFile 初始化字典 | ③ 查看数据 )
- ( 3 ) Property List 多种类型 数据 设置 获取 ( ① 设置 Root 类型为 NSArray | ② 设置 多类型 数据 | ③ 获取 PList 的 Bundle 路径 | ④ 初始化 数组 | ⑤ 打断点查看数据 )
- 七. 优化 图片 浏览器 ( ① 使用 PList | ② 懒加载 )
- ( 1 ) 使用 PList 存储 数据 ( ① 创建 PList 文件 | ② 数据准备 | ③ 获取 Bundle 路径 | ④ 获取 PList 的 Bundle 路径 | ⑤ PList -> 数组 )
- ( 2 ) 懒加载 优化 ( ① 在 get 方法中加载数据 | ② 如果为 空 才 加载 )
- 八. UIImageView 播放动画 及 内存优化
- 1. 动画 播放
- ( 1 ) UIImageView 动画 相关属性 ( ① 图片数组 | ② 动画时长 | ③ 重复次数 )
- ( 2 ) UIImageView 动画 相关方法 ( ① 开始播放 | ② 停止播放 | ③ 是否正在播放 )
- ( 3 ) UIImageView 动画 执行流程 ( ① 准备 UIImage 数组 | ② 设置动画参数 UIImage数组 时长 重复次数 | ③ 启动动画 )
- 2. 图片内存 优化
- ( 1 ) UIImageView 动画 内存 查看 ( ① Debug Navigator 查看内存 | ② 查看 动画播放前后的内存变化 | ③ 分析内存不释放的原因 )
- ( 2 ) UIImage 内存分析 ( ① 使用 UIImage imageNamed:图片名称 加载图片 | ② 使用 UIImage imageWithContentsOfFile:Bundle路径名 加载图片 )
- ( 3 ) 内存优化 的 动画 执行 完整流程 ( ① 准备 UIImage 数组 | ② 设置动画参数 UIImage数组 时长 重复次数 | ③ 启动动画 | ④ 异步设置图片数组为 nil )
- ( 4 ) NSBundle pathForResource 为 nil 解决方案 ( ① 拖入目录 选择 Create gropus | ② 查看 Xcode 项目 配置 -> Build phases 的 Bundle 配置 )
- ( 5 ) 效果展示
博客相关资源
一. 代码生成控件
1. 创建设置项目
( 1 ) 创建项目 ( ① 选择 Create a new Xcode project | ② 创建 Single View Application 项目 | ③ 设置项目信息 | ④ 设置代码路径并创建 )
项目创建流程 : ① 选择 Create a new Xcode project , ② 创建 Single View Application 项目 , ③ 设置项目信息 , ④ 设置代码路径并创建 ;
- 1.选择项目创建 : 在 Xcode 欢迎界面中 , 点击
Create a new Xcode project
选项 ; - 2.选择项目类型 : 在
Choose a template for your new project
对话框中 , 选择项目类型 iOS -> Application -> Single View Application 项目 ; - 3.设置项目名称 : 输入 项目 相关的 信息 , 主要是 项目名称 ;
- 4.选择代码存放路径 : 选择代码存放路径 , 点击
Create
按钮, 创建项目 ;
( 2 ) 界面设置 ( ① 选中 ViewController | ② 属性查看器 -> Simulated Metrics -> Size | ③ 设置 iPhone 4.7-inch )
界面设置 : 需要自己手动设定一个 屏幕尺寸 ;
- 1.创建后的默认 UI 设计界面 : 创建项目完成后, Main.storyboard 中显示的是一个正方形的 界面 , 需要将其设置为 一个 手机形状的 UI 界面 ;
- 2.设置成 4.7 寸屏幕大小 : ① 选中 ViewController 图标 , ② 设置 右侧 的 属性查看器 -> Simulated Metrics -> Size , ③ 选择 iPhone 4.7-inch 屏幕大小 ;
- 3.iPhone 尺寸 : ① iPhone 5 , 5S , SE : 4-inch ( 对角线长度 ) , ② iPhone 6 , 6S , 7 : 4.7-inch ( 对角线长度 ) , ③ iPhone 6 Plus , 6s Plus , 7Plus : 5.5-inch ( 对角线长度 ) ;
2. 设置按钮及添加事件
( 1 ) 添加按钮事件 ( Control + 左键 拖动到 代码中 生成按钮方法 )
添加按钮事件 :
- 1.添加按钮 : 向 Main.storyboard 中拖入按钮控件 ;
- 2.生成按钮方法 :
- ① 打开辅助编辑器 : 同时显示 Main.storyboard 和 ViewController.m 代码 ;
- ② 拖动生成方法 : 按住 Control 键 , 左键点击 Button 控件不放 , 然后拖动到 ViewController.m 代码空白处 ;
- ③ 设置方法属性 :
- a . 在 Name 栏 设置 方法名称 ;
- b . 在 Event 栏 设置 方法触发动作 ;
- c . Touch Up Inside 即 点击方法 ;
- d . 在 Arguments 栏 设置需要传入的参数 :
- 1> 如果在方法中需要使用按钮参数 , 则选择 Sender ,
- 2> 如果需要 按钮 和 事件 参数 , 选择 Sender and Event ,
- 3> 如果不需要参数 , 设置 None 即可 ;
- ④ 生成方法 : 点击 上述 对话框中的 Connect 按钮 , 即可生成对应方法 ;
- 5.生成的代码 :
- (IBAction)generateView {
}
( 2 ) 修改按钮文字 ( ① 双击控件 | ② 修改 Tittle 属性 )
修改按钮文字 :
- 1.方法1 : 点击选中 UIButton 控件, 然后再右侧的属性查看器中的 Tittle 属性中修改按钮文字 ;
- 2.方法2 : 在 Main.storyboard 中双击 UIButton 控件 , 修改 按钮文字 ;
- 3.修改后 :
3. 生成 UIView 控件 并 查看 View 层级
( 1 ) 代码 生成 UIView 控件 ( ① 创建控件 | ② 设置 frame | ③ 设置颜色 | ④ 添加控件 )
代码生成 UIView 控件 :
- 1.创建 UIView 控件 : 使用 UIView 的 alloc init 方法 , 创建 UIView 控件 ;
//1. 创建 View 控件 , 使用 alloc init 方法
UIView * newView = [[UIView alloc] init];
- 2.修改 Frame 属性 : 使用 CGRectMake 方法创建 CGRect 结构体变量 , 并设置给 UIView 控件的 frame 属性 ;
//2. 修改 控件 的 Frame 属性
newView.frame = CGRectMake(100, 100, 100, 100);
- 3.设置颜色 : 设置 UIView 的 backgroundColor 属性 , 传递一个 UIColor 对象 ;
//3. 为 控件 设置一个颜色值
newView.backgroundColor = [UIColor redColor];
- 4.添加 UIView 控件 : 获取当前 ViewController 的 根 View 组件 , 然后将 生成的 UIView 控件添加到 该 根 View 控件中 ;
//4. 将 控件 添加到 View 中
[self.view addSubview:newView];
- 5.总体代码 :
//
// ViewController.m
// 1.GenerateUIViewByCode
//
// Created by octopus on 19/2/3.
// Copyright © 2019年 han. All rights reserved.
//
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)generateView {
//1. 创建 View 控件 , 使用 alloc init 方法
UIView * newView = [[UIView alloc] init];
//2. 修改 控件 的 Frame 属性
newView.frame = CGRectMake(100, 100, 100, 100);
//3. 为 控件 设置一个颜色值
newView.backgroundColor = [UIColor redColor];
//4. 将 控件 添加到 View 中
[self.view addSubview:newView];
}
@end
( 2 ) 运行并查看效果 ( 查看 View 层次 )
运行并查看效果 :
1.运行程序 : 点击 Build and then run the current scheme
按钮 , 运行虚拟机 ; 然后点击 10 次 生成 10 个 UIView 控件 ;
2.查看 创建的 View 层次 : 注意 该 步骤 必须在虚拟机运行之后才能操作 , 点击下方的 Debug View Hierarchy
按钮 , 即可查看 View 层次 ;
3.查看 层次 : 鼠标 按住 界面 , 左右拖动 , 即可看到生成的 10 个 UIView 的层次 ;
4. 代码生成按钮 并 绑定事件
( 1 ) 代码生成 按钮 ( ① 创建按钮控件 | ② 设置 frame | ③ 设置文字( 颜色 ) | ④ 设置背景( 前景 )图片 | ⑤ 绑定事件 | ⑥ 添加控件 )
代码生成 按钮 :
- 1.创建按钮控件 : 创建 UIButton 控件时 , 需要制定按钮类型 , 这里创建 Custom 类型的控件 ;
//1. 创建 某种 Type 的 按钮 , 这里创建 UIButtonTypeCustom 类型的 按钮
UIButton * button = [UIButton buttonWithType:UIButtonTypeCustom];
- 2.设置 frame 属性 : 使用
CGRectMake
方法创建 CGRect 结构体变量 , 并赋值给 按钮的 frame
属性 ;
//2. 设置 Frame 属性
button.frame = CGRectMake(100, 100, 100, 100);
- 3.设置按钮文字 : 调用
setTittle
方法 , 设置生成的按钮的文字 ;
//3. 设置 文字 , 这里需要根据不同的状态设置显示的文字 , 这里只设置 UIControlStateNormal 状态的文字
[button setTitle:@"生成按钮" forState:UIControlStateNormal];
- 4.设置文字颜色 : 调用
setTittleColor
方法 , 设置按钮文字的颜色 ;
//4. 设置 文字颜色 , 这里设置普通状态时的 文字 颜色
[button setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
- 5.设置背景图片 :
- ① 添加图片资源 : 选中 Assets.xcassets , 从 Finder 中拖动图片资源 到 其中 ;
- ② 设置背景图片 : 调用
setBackgroundImage
方法 , 设置背景图片 ;
//5. 设置 背景图片
[button setBackgroundImage:[UIImage imageNamed:@"button_bg"] forState:UIControlStateNormal];
- 6.绑定事件 : 创建一个方法 , 然后调用 UIButton 的
addTarget
绑定该方法 ;
//添加按钮事件
//5. 设置 背景图片
[button setBackgroundImage:[UIImage imageNamed:@"button_bg"] forState:UIControlStateNormal];
// 创建的按钮事件
//为 生成的 按钮 绑定 点击事件
- (void) bindMethod{
NSLog(@"绑定事件触发");
}
- 7.添加控件 : 获取父控件
self.view
, 调用父控件的 addView
方法 添加控件 ;
//7. 将 UIButton 添加到 根 View 中
[self.view addSubview:button];
- 8.完整代码示例 :
//
// ViewController.m
// 1.GenerateUIViewByCode
//
// Created by octopus on 19/2/3.
// Copyright © 2019年 han. All rights reserved.
//
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
//该方法在 UIViewController 创建完成 , 并开始加载到内存中时 , 在这个时刻执行该 viewDidLoad 方法
//一般情况下 是 在该方法中 执行 初始化数据 , 创建控件 等操作 ;
- (void)viewDidLoad {
[super viewDidLoad];
//1. 创建 某种 Type 的 按钮 , 这里创建 UIButtonTypeCustom 类型的 按钮
UIButton * button = [UIButton buttonWithType:UIButtonTypeCustom];
//2. 设置 Frame 属性
button.frame = CGRectMake(100, 100, 100, 100);
//3. 设置 文字 , 这里需要根据不同的状态设置显示的文字 , 这里只设置 UIControlStateNormal 状态的文字
[button setTitle:@"生成按钮" forState:UIControlStateNormal];
//4. 设置 文字颜色 , 这里设置普通状态时的 文字 颜色
[button setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
//5. 设置 背景图片
[button setBackgroundImage:[UIImage imageNamed:@"button_bg"] forState:UIControlStateNormal];
//6. 绑定 事件
[button addTarget:self action:@selector(bindMethod) forControlEvents:UIControlEventTouchUpInside];
//7. 将 UIButton 添加到 根 View 中
[self.view addSubview:button];
}
//为 生成的 按钮 绑定 点击事件
- (void) bindMethod{
NSLog(@"绑定事件触发");
}
- (IBAction)generateView {
//1. 创建 View 控件 , 使用 alloc init 方法
UIView * newView = [[UIView alloc] init];
//2. 修改 控件 的 Frame 属性
newView.frame = CGRectMake(100, 100, 100, 100);
//3. 为 控件 设置一个颜色值
newView.backgroundColor = [UIColor redColor];
//4. 将 控件 添加到 View 中
[self.view addSubview:newView];
}
@end
二. UIView 属性 和 子控件操作
( 1 ) 创建 设置 应用 ( ① 创建应用 | ② 设置界面尺寸 )
创建 设置 应用 :
- 1.创建应用 : ① 点击 Create a new Xcode project 应用 ; ② 创建 Single View Application 项目 ; ③ 设置 项目名称 , 组织标识 等信息 ; ④ 设置代码路径 ; 参考 一 . 1 . ( 1 ) 章节内容 ;
- 2.设置界面尺寸 : ① Main.storyboard 界面中 选中 ViewController ; ② 在 属性查看器中设置 Size 属性为 iPhone 4.7-inch ; ③ 在 文件查看器 中取消 Use Auto Layout 选项 ;
( 2 ) 设置 Main.storyboard UI 界面 ( ① 背景 )
设置 Main.storyboard 界面 :
- 1.设置背景颜色 : 选中 ViewController 下的 根 View 控件 , 在 属性查看其中 设置 Background 属性 , 设置一个颜色 ;
- 2.向界面中添加一个 View 控件 : 添加 View 控件 当做容器 , 设置尺寸 300 x 300 , 居中显示 , 之后将生成的 UIView 控件放在该 容器 中 ;
- 3.添加按钮 : 添加两个按钮 , 两个按钮的功能分别是 生成 UIView 控件 和 清空 UIView 控件 ;
( 3 ) 在 ViewController.m 关联 控件变量 ( ① 按住 Control 拖拽 控件 到 @interface 代码块中 | ② Connect 对话框 设置 名称 类型 )
关联 ViewController.m 变量 :
1.拖线关联 : 按住 Control 键 不放 , 然后拖线到 ViewController.m 中的 @interface 代码块中 , 之后会弹出 Connect 对话框 ;
2.设置变量信息 : 在 Connect 对话框中 设置 名称 和 类型 , 然后点击 Connect 按钮 , 然后生成代码 ;
3.查看生成的代码 : 点击 Connect 按钮后 , 会自动根据 类型 和 变量名 生成 对应的 代码 ;
( 4 ) 生成 子组件 代码 ( ① 生成子组件 | ② 设置子组件属性 | ③ 设置子组件 frame 属性 [ 随机位置生成 ] | ④ 添加子组件到父容器中 )
生成子组件代码 :
- 1.创建子组件 : 调用 UILabel 的 alloc init 方法 , 生成子组件 ;
//1. 创建 UILabel 类型子组件
UILabel * label = [[UILabel alloc] init];
- 2.设置子组件 : 设置子组件信息 , 为 UILabel 设置文字 ;
//2. 设置 子组件 信息
label.text = @"生成的子组件";
- 3.设置 frame 属性 : 设置随机的位置 , 使用 arc4random_uniform 函数生成随机数 , x 坐标 和 y 坐标要使用不同的 随机值 , 之后设置一个 宽高 即可 ;
//3. 设置 frame 属性 , 主要是设置 位置 和 大小 , 这里针对位置 设置一个随机位置
// 随机数使用 arc4random_uniform 是用于生成随机数的函数
label.frame = CGRectMake(arc4random_uniform(200), arc4random_uniform(280), 150, 20);
- 4.添加到父容器 : 将代码添加到 父容器 中 ;
//4. 添加到 Container 中
[self.Container addSubview:label];
- 5.整体代码 :
// 添加 子组件
// ① 添加组件 : 调用 父容器组件 的 addSubview 方法添加子组件
- (IBAction)generateView:(UIButton *)sender {
//1. 创建 UILabel 类型子组件
UILabel * label = [[UILabel alloc] init];
//2. 设置 子组件 信息
label.text = @"生成的子组件";
//3. 设置 frame 属性 , 主要是设置 位置 和 大小 , 这里针对位置 设置一个随机位置
// 随机数使用 arc4random_uniform 是用于生成随机数的函数
label.frame = CGRectMake(arc4random_uniform(200), arc4random_uniform(280), 150, 20);
//4. 添加到 Container 中
[self.Container addSubview:label];
}
( 5 ) 删除 子组件 代码 ( ① 获取子组件数组 | ② 使用 for in 循环删除子组件 | ③ isKindOfClass 判定组件类型 )
删除子组件代码 :
- 1.获取子组件数组 : 访问 父容器的 subViews 属性 即可获取 父容器所有的子组件, 该属性在 UIView 中定义 ;
self.Container.subviews
- 2.删除子组件 : 使用 removeFromSuperView 方法 来 删除控件 ;
[view removeFromSuperview];
- 3.控件类型准备 : 父容器中添加 UIButton 组件 , 用于区分 UILabel 和 UIButton , 这里只删除 UILabel 控件 ;
- 4.判定组件类型 : 使用 isKindOfClass 判断 对象 类型 ;
[view isKindOfClass:[UIButton class]]
- 5.删除所有 UILabel 控件 : 使用 for in 循环 删除所有的 UILabel 控件 ;
//1. 获取所有的子组件数组 , 直接遍历删除每个子组件即可 , 注意不删除 UIButton 类型的组件
for(UIView * view in self.Container.subviews){
[view removeFromSuperview];
}
- 6.完整代码 :
// 删除 子组件
// ① 删除方法 : 使用 removeFromSuperView 方法 来 删除控件
// ② 获取子组件 : 访问 父容器的 subViews 属性 即可获取 父容器所有的子组件, 该属性在 UIView 中定义
// ③ 判定组件类型 : 通过调用 [uiView isKindOfClass:[UIButton class]] 方法可以判断 uiView 是否是 UIButton 类型的组件
- (IBAction)clearView:(UIButton *)sender {
//1. 获取所有的子组件数组 , 直接遍历删除每个子组件即可 , 注意不删除 UIButton 类型的组件
for(UIView * view in self.Container.subviews){
[view removeFromSuperview];
}
}
( 6 ) 删除 指定 Tag 的控件 的 代码 ( ① 调用父控件的 viewWithTag 方法 | ② )
删除指定 Tag 的控件 :
- 1.生成方法 : 按住 Control 拖线关联 , 在 Connect 对话框 设置方法参数 , 生成方法 ;
- 2.控件准备 : 拖入 3 个 Label 控件 , 分别设置 Tag 属性 1 , 2, 3 ;
- 3.获取子控件方法 : 调用父控件的 viewWithTag 方法 获取指定 Tag 属性的子组件 , 如果 父控件 的 Tag 与 子控件的 Tag 相同 , 也能获取到 , 并且优先获取父控件 ; 如果删除父控件 , 那么其子控件也会被全部删除 ;
- 4.删除控件 : 调用获取的子控件的
removeFromSuperview
方法 , 删除控件 ; - 5.代码示例 :
- (IBAction)clearTag:(UIButton *)sender {
//1. 获取指定 Tag 的控件
UILabel * label1 = [self.Container viewWithTag:1];
UILabel * label2 = [self.Container viewWithTag:2];
UILabel * label3 = [self.Container viewWithTag:3];
//2. 删除 子控件
[label1 removeFromSuperview];
[label2 removeFromSuperview];
[label3 removeFromSuperview];
}
( 7 ) UIView 常用方法属性 ( ① tag 属性 | ② removeFromSuperView 方法 | ③ addSubView 方法 | ④ viewWithTag 方法 | ⑤ frame 属性 | ⑥ transform 属性 )
UIView 常用方法属性 :
- 1.tag 属性 : 用于标示控件 , 不能改变控件外观 ;
- 2.removeFromSuperView 方法 : 将 子控件 从 父控件 删除 ;
- 3.addSubView 方法 : 向 父控件 中 添加子控件 , 还需要设置 Frame属性 才能显示 ;
- 4.viewWithTag 方法 : 获取 指定 Tag 属性的 子控件 , 如果 父控件 也是这个 Tag , 那么优先获取自己 ;
- 5.frame 属性 : 定义控件的位置 和 尺寸 ;
- 6.transform 属性 : 改变 位置 , 大小 , 旋转角度 属性 ; 有两种使用方式 , 一种是 直接创建指定所有参数 ; 第二种 可以在之前的基础上进行增量修改 ;
( 8 ) 效果展示
效果展示 :
三. 图片浏览器
1. 应用创建 设置
( 1 ) 创建 设置 应用 ( ① 创建应用 | ② 设置界面尺寸 )
创建 设置 应用 :
- 1.创建应用 : ① 点击 Create a new Xcode project 应用 ; ② 创建 Single View Application 项目 ; ③ 设置 项目名称 , 组织标识 等信息 ; ④ 设置代码路径 ; 参考 一 . 1 . ( 1 ) 章节内容 ;
- 2.设置界面尺寸 : ① Main.storyboard 界面中 选中 ViewController ; ② 在 属性查看器中设置 Size 属性为 iPhone 4.7-inch ; ③ 在 文件查看器 中取消 Use Auto Layout 选项 ;
2. UI 控件 设置
( 1 ) 设置 Main.storyboard ( 拖入相关控件 )
设置 Main.storyboard 界面 :
- 1.准备对应控件 : 根据需求 拖入 对应的控件 , 并设置相关属性 ; 这里就不再详细介绍 , 贴一张 设置好的控件 和 默认文字 图片 展示图 ;
- 2.准备素材 : 拖入 显示的图片 和 箭头 等 图片资源 ;
( 2 ) 关联 Main.storyboard 与 ViewController.m ( ① 关联控件变量 | ② 关联方法 | ③ 设置相关的成员变量 )
关联 Main.storyboard 与 ViewController.m :
- 1.关联控件变量 : 按住 Control 键 , 将控件拖动到
@interface
代码区域 , 在弹出的对话框中输入控件命令 和 选择控件类型 , 即可生成控件关联的变量 ;
// 显示图片的索引
@property (weak, nonatomic) IBOutlet UILabel *indexLabel;
// 显示图片
@property (weak, nonatomic) IBOutlet UIImageView *Image;
// 左箭头按钮
@property (weak, nonatomic) IBOutlet UIButton *lastButton;
// 右箭头按钮
@property (weak, nonatomic) IBOutlet UIButton *nextButton;
// 图片介绍
@property (weak, nonatomic) IBOutlet UILabel *imageDescription;
- 2.关联 UIButton 点击方法 : 按住 Control 键 , 将控件拖动到
@implementation
代码区域 , 在弹出的对话框中 输入方法名称 , 选择控件类型 , 选择触发操作 , 选择传入的参数 即可生成点击方法 ;
// 上一张 图片
- (IBAction)lastImage:(UIButton *)sender {
}
// 下一张 图片
- (IBAction)nextImage:(UIButton *)sender {
}
3. 相关知识点
( 1 ) UILabel 设置 ( ① 换行设置 | ② 设置行高 | ③ 宽高控制 )
UILabel 设置 :
- 1.设置自动换行 : 在 UILabel 中有
Lines
属性 , 可以设置显示 几行 文字 , Lines 属性 设置 0 就会自动进行换行 ; - 2.UILabel 行高设置 : 自动换行的前提是 , UILabel 有对应的多行的行高 , 如果 UILabel 高度很小只能显示 1 行 , 那么 UILabel 自动换行 也只是显示 1 行 , 因此 如果需要自动换行的话 , 需要给 UILabel 设置足够的行高 ;
- 3.宽高控制 : UILabel 的 宽度 和 高度 都需要把握好 , 宽度如果不够 , 后面会出现 … 的 省略情况 , 同理 高度不足 也会出现这种情况 ;
( 2 ) UIButton 启用 禁用 ( ① enabled 属性 YES NO )
UIButton 的启用 禁用 :
- 1.enabled 属性 ( 可视化修改 ) : 在 UIButton 的 属性查看器中 Control 模块下 , Enabled 属性用来设置 按钮是否可用 , 如果 勾选 按钮可用 , 反之 按钮 会变灰 不可用 ;
- 2.源码中查看 enabled 属性 : 默认是 YES 可用 , 如果设置为 NO 不可用 ;
@property(nonatomic,getter=isEnabled) BOOL enabled; // default is YES. if NO, ignores touch events and subclasses may draw differently
- 3.代码修改 enabled 属性 : 方法中 直接修改 sender.enabled 属性值 为 YES 或 NO , 即可修改 UIButton 是否可用 ;
( 3 ) NSArray 和 NSMutableDictionary 存储数据 ( ① NSArray 数组 | ② 字典 )
NSArray 和 NSMutableDictionary 存储数据 :
- 1.使用方法 : 定义一个 NSArray 成员变量 , 其每个元素都是一个 NSMutableDictionary 字典 , 字典中存放 两个 键值对 , 分别是 图片名称 和 图片描述 ;
- 2.定义 NSArray 成员变量 : 使用 @property 定义 , 注意
// 用于保存所有图片数据的数组 , 每个数组元素存放字典数据
@property (strong, nonatomic) NSArray * pics;
- 3.初始化 NSArray 成员变量 : 先逐个创建对应的
NSMutableDictionary
字典 , 然后将字典 当做元素 放入 NSArray
数组中 , 数组中的每个元素都是一个 字典 ;
// 1. 初始化图片名称数组
NSMutableDictionary * d1 = [NSMutableDictionary dictionary];
d1[@"pic"]=@"1_Mustang";
d1[@"des"]=@"Mustang(福特野马)是美国福特汽车公司推出的2005款野马汽车,最高时速232.2公里,设计源自2003 年汽车巡回展上的概念车,野马的诞生标志着美国仅存的大马力轿车获得了重生。";
NSMutableDictionary * d2 = [NSMutableDictionary dictionary];
d2[@"pic"]=@"2_Prado";
d2[@"des"]=@"普拉多是一款进口ORV,源于丰田享誉全球的LAND CRUISER车系,1996年丰田正式将LAND CRUISER FJ90命名为PRADO普拉多,即真正意义上的第一代普拉多。";
NSMutableDictionary * d3 = [NSMutableDictionary dictionary];
d3[@"pic"]=@"3_Camaro";
d3[@"des"]=@"雪佛兰 科迈罗(英文名:Chevrolet Camaro)设计于1960年,目前共发展了六代。1966年9月26日发布的1967款Camaro是以雪佛兰Nova为原型而设计的。";
NSMutableDictionary * d4 = [NSMutableDictionary dictionary];
d4[@"pic"]=@"4_LandCru";
d4[@"des"]=@"兰德酷路泽【陆地巡洋舰】是丰田汽车出品的LAND CRUISER 200,是丰田公司生产的一款进口ORV越野车(Off Road Vehicle) [1] ,它的外观在继承原有设计DNA的同时向具备新时代的“新鲜感·先进性”风格进化。是四轮驱动,轴距2850毫米,四轮碟刹的硬派越野车。";
NSMutableDictionary * d5 = [NSMutableDictionary dictionary];
d5[@"pic"]=@"5_Mondeo";
d5[@"des"]=@"福特蒙迪欧(Mondeo)是一款长安福特旗舰车型,不仅搭载多项创新科技,并在至臻品质、动力系统以及安全性能等方面实现全面提升。";
// 将字典放入数组中
self.pics = @[d1, d2, d3, d4, d5];
- 4.获取 NSArray 中的元素 : 根据数组下标 [int] 获取数组中的元素 ;
// ① 获取对应的数据 字典
NSMutableDictionary * d = self.pics[self.index - 1];
- 5.从 NSMutableDictionary 字典 中获取对应元素 : 获取
NSMutableDictionary * d
字典中的 “pic” 键 对应的值 d[@"pic"]
, 获取 字典 中 “des” 键 对应的值 d[@"des"]
4. 代码逻辑 与 完整代码
( 1 ) 代码逻辑 ( ① 边界处理 | ② 按钮处理 | ③ UILabel 文字切换 | ④ UIImageView 图片切换 )
代码逻辑 :
- 1.索引边界处理 : 索引范围 1 ~ 5 , 不能 小于 1 或者 大于 5 , 这里需要进行限制 ; 点击 向左 切换时 索引自减 , 当 小于等于 1 时 , 索引值 仍为 1 ; 点击向右切换时 , 索引 自增 , 当 大于等于 5 时 , 索引值 仍为 5 ;
// 设置图片索引 , 注意不能 小于 1 , 边界控制
self.index -- ;
if(self.index <= 1){
self.index = 1;
}
...
// 设置图片索引 , 注意不能 超过 5 , 边界控制
self.index ++ ;
if(self.index >= self.pics.count){
self.index = (int)self.pics.count;
}
- 2.按钮处理 : UIButton 的 enabled 属性 设置 YES NO 值 来 设置 可用 禁用 属性 ; 显示第一张图片时 , 左 按钮 禁用 , 显示 最后一张图片时 , 右 按钮 禁用 ; 其它情况 左右按钮 都可用 ;
// 1. 设置按钮 禁用 启用 , index 为 1 和 5 时 分别启用 和 禁用 指定的按钮 , 其它情况下可以使用两个按钮
if(self.index == 1){
self.lastButton.enabled = NO;
self.nextButton.enabled = YES;
}else if(self.index == self.pics.count){
self.lastButton.enabled = YES;
self.nextButton.enabled = NO;
}else{
self.lastButton.enabled = YES;
self.nextButton.enabled = YES;
}
- 3.UILabel 文字切换 : 直接 修改 UILabel 的 text 属性 ;
// ④ 设置 文字 描述
self.imageDescription.text = d[@"des"];
- 4.文字生成格式 : 使用 NSString 的
stringWithFormat
方法 , 设置一个 字符串格式 , 使用 通配符 进行 数据替换 ; 注意 NSArray 的 count 的通配符是 %lu ;
// ② 设置提示 UILabel 文字 , 拼接字符串 , 1/5
self.indexLabel.text = [NSString stringWithFormat:@"%d/%lu", self.index, self.pics.count];
- 5.UIImageView 图片切换 : 通过 调用 UIImage 的 imageNamed 方法 , 获取 UIImage 对象 ;
// ③ 设置 图片 显示
self.Image.image = [UIImage imageNamed:d[@"pic"]];
( 2 ) 完整代码
完整代码 :
//
// ViewController.m
// 3.ImageBrowser
//
// Created by octopus on 19/2/11.
// Copyright © 2019年 han. All rights reserved.
//
#import "ViewController.h"
@interface ViewController ()
// 显示图片的索引
@property (weak, nonatomic) IBOutlet UILabel *indexLabel;
// 显示图片
@property (weak, nonatomic) IBOutlet UIImageView *Image;
// 左箭头按钮
@property (weak, nonatomic) IBOutlet UIButton *lastButton;
// 右箭头按钮
@property (weak, nonatomic) IBOutlet UIButton *nextButton;
// 图片介绍
@property (weak, nonatomic) IBOutlet UILabel *imageDescription;
// 当前图片索引
@property (assign, nonatomic) int index;
// 用于保存所有图片数据的数组 , 每个数组元素存放字典数据
@property (strong, nonatomic) NSArray * pics;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 1. 初始化图片名称数组
NSMutableDictionary * d1 = [NSMutableDictionary dictionary];
d1[@"pic"]=@"1_Mustang";
d1[@"des"]=@"Mustang(福特野马)是美国福特汽车公司推出的2005款野马汽车,最高时速232.2公里,设计源自2003 年汽车巡回展上的概念车,野马的诞生标志着美国仅存的大马力轿车获得了重生。";
NSMutableDictionary * d2 = [NSMutableDictionary dictionary];
d2[@"pic"]=@"2_Prado";
d2[@"des"]=@"普拉多是一款进口ORV,源于丰田享誉全球的LAND CRUISER车系,1996年丰田正式将LAND CRUISER FJ90命名为PRADO普拉多,即真正意义上的第一代普拉多。";
NSMutableDictionary * d3 = [NSMutableDictionary dictionary];
d3[@"pic"]=@"3_Camaro";
d3[@"des"]=@"雪佛兰 科迈罗(英文名:Chevrolet Camaro)设计于1960年,目前共发展了六代。1966年9月26日发布的1967款Camaro是以雪佛兰Nova为原型而设计的。";
NSMutableDictionary * d4 = [NSMutableDictionary dictionary];
d4[@"pic"]=@"4_LandCru";
d4[@"des"]=@"兰德酷路泽【陆地巡洋舰】是丰田汽车出品的LAND CRUISER 200,是丰田公司生产的一款进口ORV越野车(Off Road Vehicle) [1] ,它的外观在继承原有设计DNA的同时向具备新时代的“新鲜感·先进性”风格进化。是四轮驱动,轴距2850毫米,四轮碟刹的硬派越野车。";
NSMutableDictionary * d5 = [NSMutableDictionary dictionary];
d5[@"pic"]=@"5_Mondeo";
d5[@"des"]=@"福特蒙迪欧(Mondeo)是一款长安福特旗舰车型,不仅搭载多项创新科技,并在至臻品质、动力系统以及安全性能等方面实现全面提升。";
// 将字典放入数组中
self.pics = @[d1, d2, d3, d4, d5];
// 2. 初始化索引 为 1 , 并且执行 第一次 图片 切换 操作 , 显示对应的 图片 , 索引 , 及 描述
self.index = 1;
[self showImage];
}
// 显示 上一张 图片
- (IBAction)lastImage:(UIButton *)sender {
// 设置图片索引 , 注意不能 小于 1 , 边界控制
self.index -- ;
if(self.index <= 1){
self.index = 1;
}
[self showImage];
}
// 显示 下一张 图片
- (IBAction)nextImage:(UIButton *)sender {
// 设置图片索引 , 注意不能 超过 5 , 边界控制
self.index ++ ;
if(self.index >= self.pics.count){
self.index = (int)self.pics.count;
}
[self showImage];
}
// 根据 当前的 索引值 显示指定的图片 , 以及控制 左右 切换按钮是否可用
- (void) showImage {
// 1. 设置按钮 禁用 启用 , index 为 1 和 5 时 分别启用 和 禁用 指定的按钮 , 其它情况下可以使用两个按钮
if(self.index == 1){
self.lastButton.enabled = NO;
self.nextButton.enabled = YES;
}else if(self.index == self.pics.count){
self.lastButton.enabled = YES;
self.nextButton.enabled = NO;
}else{
self.lastButton.enabled = YES;
self.nextButton.enabled = YES;
}
// 2. 设置 UIImageView 和 UILabel 切换
// ① 获取对应的数据 字典
NSMutableDictionary * d = self.pics[self.index - 1];
// ② 设置提示 UILabel 文字 , 拼接字符串 , 1/5
self.indexLabel.text = [NSString stringWithFormat:@"%d/%lu", self.index, self.pics.count];
// ③ 设置 图片 显示
self.Image.image = [UIImage imageNamed:d[@"pic"]];
// ④ 设置 文字 描述
self.imageDescription.text = d[@"des"];
}
@end
( 3 ) 效果展示
效果展示 :
四. Storyboard 添加 配置 及 相关知识点
1. 添加 新界面 ( ① 新建 Storyboard | ② 配置 Storyboard | ③ 新建ViewController 代码 )
( 1 ) 添加 Storyboard ( ① File -> New -> File | ② iOS -> User Interface -> Storyboard | ③ General -> Deployment -> Main Interface 配置 Storyboard )
Main.storyboard 添加流程 :
- 1.新建 : 菜单栏 File -> New -> File 选项 , 弹出 新建 对话框 ;
- 2.选择文件模板 : 在弹出的 对话框中 选择 iOS -> User Interface -> Storyboard 文件 , 点击 Next 按钮 , 进行下一步设置 ;
- 3.选择文件路径 : 最好将文件放在 主代码 路径下 , 点击 Create 进行下一步 ;
- 4.Xcode 设置 : 其 文件 创建在了 代码目录下 , Xcode 中的引用 放在了根目录 , 此时 将其拖动到 代码路径中即可 ;
设置完毕后的情况 : - 5.设置启动 UI 文件 : 选中 Xcode 项目 根路径文件 , 在 General -> Deployment -> Main Interface 一栏 选择 想要启动的 UI 文件 ;
( 2 ) Storyboard 设置 ( ① 拖动箭头设置启动界面 | ② View Controller 的 Is Initial View Controller 勾选框 设置启动界面 | ③ 关联 ViewController 代码 )
Storyboard 设置 :
- 1.设置多个 View Controller : 在 Main.storyboard 中 , 可以直接将 View Controller 拖入其中 ; 注意 为 每个 ViewController 设置 4.7inch 大小 ;
- 2.设置 3 个 View Controller : 拖入 三个 ViewController , 并为其 根 View 设置 不同的背景颜色 ;
- 3.拖动箭头 : 直接拖动 向右的 箭头 , 其指向就是第一个 启动的界面 ;
- 4.属性设置启动界面 : 选中 ViewController , 在属性查看器中 设置 View Controller 模块下的 Is Initial View Controller 选项 ;
- 5.关联 ViewController 代码 : 在 Main.Storyboard 中 虽然添加了 2 个 界面 , 但是没有与之对应的 ViewController.m 的代码 , 这里需要在 身份查看器 中 设置 Class 属性 ;
( 3 ) 新建 ViewController.m 文件 ( ① File -> New -> File | ② iOS -> Source -> Cocoa Touch Class | ③ Storyboard 中 身份查看器 配置 Class )
新建 ViewController.m 文件 :
- 1.新建文件 : 菜单栏 File -> New -> File 选项 , 弹出 新建对话框 ;
- 2.创建类型选择 : 在弹出的 对话框中 选择 iOS -> Source -> Cocoa Touch Class 文件 , 点击 Next 按钮 , 进行下一步设置 ;
- 3.设置类 : 选择 父类 类型为 UIViewController , 类名不要与其它 文件 重名 , 点击 Next 进行下一步设置 ;
- 4.设置文件路径 : 在 弹出 的 对话框中 设置代码的路径 , 这里直接使用默认值即可 ; 点击 Create 按钮 , 即可生成 对应的 ViewController 代码 文件 ;
- 5.Storyboard 代码对应设置 : 点击 Storyboard 中的 ViewController , 在 身份查看器 中配置 Class 选项 , 直接输入 刚才生成的 TestViewController 名称即可完成对应关系 ;
2. Storyboard 相关知识点 ( ① 删除 Storyboard | ② Storyboard 本质 )
( 1 ) 删除 Storyboard ( ① 删除文件及引用 | ② 删除引用 文件保留 )
删除 Storyboard : 选中 Storyboard 点击 Delete 键 , 就会弹出如下对话框 , 提供了 三个选项 ;
- 1.Move to Trash : 删除 Finder 中的 文件 , 及 Xcode 中的索引 , 该文件直接删除到 Trash 废纸篓 中 ;
- 2.Remove Reference : 删除 Xcode 中的 引用 , 但是 文件 还是 在 该项目 下 , 可以随时 通过 拖动 恢复该文件 ;
- 3.Cancel : 取消删除操作 ;
( 2 ) Storyboard 本质 ( XML 文本文件 )
Storyboard 本质 : 向 首界面 拖入 一个 UILabel , 并查看 该文件 ;
- 1.使用文本编辑器查看 : 使用 Subline 文本编辑器查看 Storyboard 界面 , 发现 其本质 是一个 纯文本 的 文件 ; 该方式 与 Android 的 布局文件相似 ;
- 2.xml 文本 : 该 文本 本质 是 一个 xml 文件 ;
- 3.Xcode 中使用文本打开 : 右键点击 Storyboard 文件 , 选择 Open As -> Source Code 即可 查看 源码 ;
- 4.查看 代码 样式 :
- 5.UILabel 代码 分析 : 其中 text 属性 就是 显示 文字 , rect frame 子标签 就是其 位置 和 宽高 ;
<label opaque="NO"
userInteractionEnabled="NO"
contentMode="left"
horizontalHuggingPriority="251" verticalHuggingPriority="251"
fixedFrame="YES" text="Hello" textAlignment="natural"
lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines"
adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO"
id="JUr-dt-qtd">
<rect key="frame" x="168" y="323" width="39" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
3. iOS 应用启动步骤简介
( 1 ) iOS 应用启动步骤
iOS 应用启动步骤 :
- 1.程序入口 main 函数 : main () 函数 在 Xcode 中 代码 路径 下的 Supporting Files 目录下 的 main.m 文件中 ;
- 2.调用 UIApplicationMain 方法 : 调用 UIApplicationMain 方法 , 启动应用 ;
UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
- 3.查找 Storyboard : 查找 在 应用设置中 的 Main Interface 设置的 Storyboard 文件 , 该文件是 应用启动 加载 的 UI 界面 ;
- 4.查找 启动界面 : 查找 在 Storyboard 中 箭头指向 的 启动 ViewController ;
- 5.加载 UI 界面 : 读取 Storyboard 文件 , 加载并分析 其 XML 标签 属性 和 值 对应的 控件 , 创建这些控件 并 添加到 ViewController 中 ;
- 6.调用 viewDidLoad 方法 : 界面 加载 完毕后 , 调用 ViewController.m 中的 viewDidLoad 方法 ;
- 7.界面 展示 : 将创建的 UI 界面 在手机屏幕上 展示 给用户 ;
五. Bundle 简介
( 1 ) Bundle 简介
Bundle 简介 : 应用程序名称.app 是 Bundle , 是一个 目录 ;
- 1.Mac 中的 Bundle : 在 Mac 中的 Finder 中 , 点击 应用程序 目录 , 其中是一个个 “.app” 后缀 的 文件 , 这些文件 就是 Bundle , 可以右键点击 选择 显示包内容 , 查看其中的 目录 内容 ;
- 2.显示包内容 : 右键点击 app 后缀 文件 , 选择 显示包内容 选项 , 即可查看其内容 , 其 Contents 下的 内容 就是 Bundle ;
- 3.iOS 中的 Bundle : 与 Mac 基本相同 , iOS 应用程序 , 打包好以后 , 也是一个 .app 后缀的 文件 , 也可以通过 右键 点击 该文件 , 选择 显示包内容 查看 Bundle ;
- 4.Bundle 路径 : 在应用中 , 可以通过
NSLog(NSHomeDirectory());
打印出 沙盒路径 , 在 该路径 向后 退 两层 目录 , 可以看到 Bundle 目录 , Bundle 文件都在该 目录中 ;
//打印出的路径示例
/Users/hanshuliang/Library/Developer/CoreSimulator/Devices/C7ECF957-38E2-4E3F-ADC1-1FC5D26B4C79/data/Containers/Data/Application/7128774A-7468-466B-9C44-962CF974F8CB
Bundle 路径 :
- 5.iOS 中的 .app 文件路径 : 在 Bundle 目录下 , Application 路径 下 的 二级 文件 就是 iOS 中的 app 后缀文件 , 右键 可查看其 内容 ;
- 6.查看 Bundle 内容 : 右键点击 “5.NSBundleDemo.app” 文件 , 选择 显示包内容 选项 , 可以查看 Bundle 内容 , 如下图 ;
- 7.创建文件 : 创建 1 个 新的 Storyboard 文件 , 然后 再次查看 Bundle , 即可看到 在 Bundle 中 出现了一个 新文件 ; 这个 文件 是 加密的 , 无法查看 ;
( 2 ) 图片放置 位置 ( ① 放在 Assets.xcassets [推荐] | ② 放在根目录[不推荐] )
图片放置 位置 : 准备两张图片 , 分别放在 代码 根目录 和 Assets.xcassets 中 ;
- 1.放在 根目录 : 在 Bundle 中 也可以 看到 该图片 , 不安全 ;
- 2.放在 Assets.xcassets 目录中 : 放在 该 目录下 , 打包后 放在 Assets.car 中 , 放在根目录的图片 直接显示在 Bundle 中 ;
( 3 ) NSBundle 使用 ( ① 获取 NSBundle 对象 | ② 获取 Bundle 目录下 某文件的 全路径 )
NSBundle 使用 :
- 1.NSBundle 类 作用 : 获取了 NSBundle 类 , 就相当于获取了 Bundle 目录中的内容 ; 如 下图 的内容 ;
- 2.获取 NSBundle 对象 : 通过 调用 NSBundle 的 mainBundle 方法 , 获取该对象 ;
// 2. 获取当前应用程序的 Bundle
NSBundle *mainBundle = [NSBundle mainBundle];
- 3.获取 Bundle 下的 文件路径 : 可以通过 pathForResource 方法 获取 某文件的 路径 , ① 传入 文件名 和 后缀 两个参数 , ② 或者 传入 文件名.后缀 参数 ;
// 3. 获取 Bundle 中 某文件 的 全路径
NSString *path = [mainBundle pathForResource:@"5_ Mondeo" ofType:@"jpeg"];
NSLog(path);
// 4. 获取 Bundle 中 某文件 的 全路径 , 使用另外一种方式
NSString *path1 = [mainBundle pathForResource:@"5_ Mondeo.jpeg" ofType:nil];
NSLog(path1);
- 4.输出结果 :
2019-02-12 22:46:33.797 5.NSBundleDemo[3253:29735] /Users/hanshuliang/Library/Developer/CoreSimulator/Devices/C7ECF957-38E2-4E3F-ADC1-1FC5D26B4C79/data/Containers/Bundle/Application/C004925F-E20C-4122-A6E0-89D2D6B0CA7B/5.NSBundleDemo.app/5_ Mondeo.jpeg
2019-02-12 22:46:33.797 5.NSBundleDemo[3253:29735] /Users/hanshuliang/Library/Developer/CoreSimulator/Devices/C7ECF957-38E2-4E3F-ADC1-1FC5D26B4C79/data/Containers/Bundle/Application/C004925F-E20C-4122-A6E0-89D2D6B0CA7B/5.NSBundleDemo.app/5_ Mondeo.jpeg
六. Property List 简介
( 1 ) Property List 创建 ( ① New File | ② iOS -> Resource -> Property List | ③ 数据设置 | ④ 类型设置 )
PList 创建 :
- 1.创建文件 : 右键 点击 代码目录 , 选择 New File 选项 ;
- 2.设置文件类型 : 选择 iOS -> Resource -> Property List 文件 ;
- 3.设置文件路径 : 设置 文件 名称 , 并 选择 文件路径 ;
- 4.添加数据 : 点击 PList 中的 加号 按钮 , 即可添加数据 ;
- 5.数据类型设置 : 默认 的 根元素 是 Dictionary 字典 , 这里暂时只讨论 字典 的 情况 ;
( 2 ) 获取 Property List 数据 ( ① 获取 Bundle PList 路径 | ② dictionaryWithContentsOfFile 初始化字典 | ③ 查看数据 )
获取 PList 数据 :
- 1.查看 Bundle 中 PList 文件 : 之前 创建 了一个 PList 文件 , 这里进入 Bundle 目录中 查看 , 根据之前 打印的 Bundle 路径 , 查看 其 文件内容 :
- 2.获取 Bundle 目录中 的 PList 文件 路径 : 调用 NSBundle 对象的 pathForResource 方法 , 获取 PList 在 Bundle 中的 全路径 ;
// 5. 获取 dictionary.plist 的 Bundle 路径
NSString *path2 = [mainBundle pathForResource:@"dictionary.plist" ofType:nil];
NSLog(path2);
- 3.根据文件路径 初始化 字典 : 调用 NSDictionary 的 dictionaryWithContentsOfFile 方法 , 初始化字典 , 传入的是 PList 路径 ;
// 6. 根据 PList 路径 初始化 字典 , 前提是 这个 PList 的类型是 字典类型的
NSDictionary *dictionary = [NSDictionary dictionaryWithContentsOfFile:path2];
- 4.调试查看字典内容 : 在 字典 初始化 位置 打断点 , 查看初始化的内容 ;
( 3 ) Property List 多种类型 数据 设置 获取 ( ① 设置 Root 类型为 NSArray | ② 设置 多类型 数据 | ③ 获取 PList 的 Bundle 路径 | ④ 初始化 数组 | ⑤ 打断点查看数据 )
PList 多种类型数据设置 : 上面 讲解 了 根元素 为 字典 的情况 , 这里讨论 根元素 为 数组 的情况 , 其中 数组的 每个元素 都可以设置 不同的类型 ;
- 1.设置根元素类型为数组 :
- 2.设置多个类型的数据 : 每个 数组 元素 可以设置 不同的 类型 , 这里设置 字典 , 数字 , 布尔 值 三个 数组元素 ;
- 3.获取 PList 的 Bundle 路径 : 调用 NSBundle 对象的 pathForResource 方法 获取 对应文件的 Bundle 全路径 ;
// 7. 获取 array.plist 的 Bundle 路径
NSString *path3 = [mainBundle pathForResource:@"array.plist" ofType:nil];
NSLog(path3);
- 4.初始化 数组 : 调用 NSArray 的 arrayWithContentsOfFile 方法 初始化 数组 , 传入 PList 的路径 , 注意 这个 PList 的 Root 类型 必须是 Array 类型 的 ;
// 8. 根据 PList 路径 初始化 数组 , 前提是 这个 PList 的类型是 数组类型的
NSArray *array = [NSArray arrayWithContentsOfFile:path3];
- 5.打断点查看 数组 内容 :
七. 优化 图片 浏览器 ( ① 使用 PList | ② 懒加载 )
( 1 ) 使用 PList 存储 数据 ( ① 创建 PList 文件 | ② 数据准备 | ③ 获取 Bundle 路径 | ④ 获取 PList 的 Bundle 路径 | ⑤ PList -> 数组 )
使用 PList 存储数据 :
- 1.创建 PList 文件 : 创建 名称为 car.plist 的文件 , 将其 Root 类型设置为 Array 类型 ;
- 2.数据准备 : 将 图片名称 和 描述 信息 存入 plist 文件中 ;
- 3.获取 Bundle 路径 :
// 1. 获取 Bundle
NSBundle *mainBundle = [NSBundle mainBundle];
- 4.获取 PList Bundle 路径 :
// 2. 获取 plist 文件路径
NSString *path = [mainBundle pathForResource:@"car.plist" ofType:nil];
- 5.初始化数组 :
// 3. 初始化数组
self.pics = [NSArray arrayWithContentsOfFile:path];
( 2 ) 懒加载 优化 ( ① 在 get 方法中加载数据 | ② 如果为 空 才 加载 )
懒加载优化 :
- 1.懒加载原则 : ① 用到 某 属性的时候才去 加载 ; ② 没有值 时 才 进行初始化 ;
- 2.点语法说明 : 以
@property (strong, nonatomic) NSArray * pics;
为例 , self.pics
相当于 get 方法 , 即调用了 -(NSArray *) pics;
方法 ; set 方法调用的是 -(void)setPics:(NSArray*)pics;
; 其实际的 变量名称 是 _pics
; 根据 用到 属性时 才去加载 原则 , 这里将加载过程放在 get 方法中 ; - 3.读取 plist 频率 : 一般情况下 程序 运行起来 , plist 是不会改变的 , 因此 只需要加载一次即可 ; 根据 没有值 的时候才去 初始化 原则 , 只有当属性为 空时 , 才执行初始化操作 ;
- 4.代码 :
//懒加载优化 , 原则 1 : 只有使用 pics 属性时 开始优化 , 因此 代码 放在 get 方法中
- (NSArray *)pics {
// 懒加载优化 , 原则 2 : 只有 pics 属性为 空时 才开始从 list 中 初始化 数据
if(_pics == nil){
// 1. 获取 Bundle
NSBundle *mainBundle = [NSBundle mainBundle];
// 2. 获取 plist 文件路径
NSString *path = [mainBundle pathForResource:@"car.plist" ofType:nil];
// 3. 初始化数组 , 注意 此处要使用 生成的 变量名
_pics = [NSArray arrayWithContentsOfFile:path];
}
return _pics;
}
八. UIImageView 播放动画 及 内存优化
1. 动画 播放
( 1 ) UIImageView 动画 相关属性 ( ① 图片数组 | ② 动画时长 | ③ 重复次数 )
UIImageView 动画相关属性 :
- 1.动画图片数组 : 多个 NSArray 数组 , 其中元素类型是 UIImage ;
@property (nullable, nonatomic, copy) NSArray<UIImage *> *animationImages;
// The array must contain UIImages. Setting hides the single image. default is nil
- 2.动画持续时间 : 单位 秒 ;
@property (nonatomic) NSTimeInterval animationDuration;
// for one cycle of images. default is number of images * 1/30th of a second (i.e. 30 fps)
- 3.动画重复次数 : 无限循环 设置 0 ;
@property (nonatomic) NSInteger animationRepeatCount;
// 0 means infinite (default is 0)
( 2 ) UIImageView 动画 相关方法 ( ① 开始播放 | ② 停止播放 | ③ 是否正在播放 )
UIImageView 动画相关方法 :
- 1.开始播放 :
- (void)startAnimating;
- 2.停止播放 :
- (void)stopAnimating;
- 3.是否正在播放 :
- (BOOL)isAnimating;
( 3 ) UIImageView 动画 执行流程 ( ① 准备 UIImage 数组 | ② 设置动画参数 UIImage数组 时长 重复次数 | ③ 启动动画 )
UIImageView 动画 执行流程 :
- 1.首先判断 动画 是否在执行 : 动画执行 操作 会覆盖 上一次的 动画 , 每次 调用 startAnimating 都会 重新开始 执行动画 , 因此 当动画正在 执行时 , 不要覆盖 ; 使用 isAnimating 方法 先判断 动画是否在习性 ;
// 1. 先判断 动画是否在执行 , 如果动画在执行 , 直接退出方法
if([self.imageView isAnimating]) return;
- 2.准备数据 : 准备 UIImage 数组 ;
// 2. 数据准备 , 准备 UIImage 数组
NSArray *nameArray = @[@"1_Mustang", @"2_Prado", @"3_Camaro", @"4_LandCru", @"5_Mondeo"];
NSMutableArray *imageArray = [NSMutableArray array];
for(int i = 0; i < nameArray.count; i ++){
//获取 UIImage 对象 , 并放入数组
[imageArray addObject:[UIImage imageNamed:nameArray[i]] ];
}
- 3.设置图片 : 将准备好的 UiImage 数组 设置 到 animationImages 属性中 ;
// 3. 设置图片
self.imageView.animationImages = imageArray;
- 4.设置动画参数 : 设置动画的 时长 ( animationDuration 属性 ) 和 重复次数 ( animationRepeatCount 属性 ) ;
// 4. 设置动画参数 : 时长 , 循环次数
self.imageView.animationDuration = 1;
self.imageView.animationRepeatCount = 1;
- 5.开始执行动画 : 执行 startAnimating 方法 , 开始执行动画 ;
// 5. 开始执行动画
[self.imageView startAnimating];
- 6.完整代码 :
//播放动画的 方法
- (IBAction)startAnimation:(UIButton *)sender {
// 1. 先判断 动画是否在执行 , 如果动画在执行 , 直接退出方法
if([self.imageView isAnimating]) return;
// 2. 数据准备 , 准备 UIImage 数组
NSArray *nameArray = @[@"1_Mustang", @"2_Prado", @"3_Camaro", @"4_LandCru", @"5_Mondeo"];
NSMutableArray *imageArray = [NSMutableArray array];
for(int i = 0; i < nameArray.count; i ++){
//获取 UIImage 对象 , 并放入数组
[imageArray addObject:[UIImage imageNamed:nameArray[i]] ];
}
// 3. 设置图片
self.imageView.animationImages = imageArray;
// 4. 设置动画参数 : 时长 , 循环次数
self.imageView.animationDuration = 1;
self.imageView.animationRepeatCount = 1;
// 5. 开始执行动画
[self.imageView startAnimating];
}
2. 图片内存 优化
( 1 ) UIImageView 动画 内存 查看 ( ① Debug Navigator 查看内存 | ② 查看 动画播放前后的内存变化 | ③ 分析内存不释放的原因 )
UIImageView 内存查看 :
- 1.查看内存方式 : 内存 可以在 Debug Navigator 中 进行查看 , 前提是 应用 必须处于正在运行的状态 ;
- 2.运行并查看内存 : 播放之前 内存 是 19.9M ;
- 3.点击播放动画查看内存 : 点击播放按钮 , 及 播放 完毕之后 , 内存一直保持在 36.9M ;
- 4.分析原因 : 这是 由于 图片 一直 驻留在内存中 没有释放 , 使用 UIImage imageNamed 方法 加载的图片 , 不会释放 ;
( 2 ) UIImage 内存分析 ( ① 使用 UIImage imageNamed:图片名称 加载图片 | ② 使用 UIImage imageWithContentsOfFile:Bundle路径名 加载图片 )
UIImage 内存分析 :
- 1.使用 UIImage imageNamed:图片名称 加载图片 : 使用该方式 加载 图片 , 图片会在 内存中 驻留 , 只有需要长期保持的 图片 , 如 UI 界面的 经常显示 的 各种背景 图标 等 , 使用该方式加载 ;
UIImage *image = [UIImage imageNamed:@"1.png"];
- 2.使用 UIImage imageWithContentsOfFile:Bundle路径名 加载图片 : 使用该方式加载图片时 , 如果图片没有被引用时 , 图片占用的内存就会被释放 ; 即 将图片持有变量设置为 nil 即可 ;
//2.1获取 Bundle
NSBundle *mainBundle = [NSBundle mainBundle];
//2.2获取 图片对应的 Bundle 路径
NSString *path = [mainBundle pathForResource:nameArray[i] ofType:@"jpeg"];
//2.3根据 Bundle 路径 获取 UIImage
UIImage *image = [UIImage imageWithContentsOfFile:path];
( 3 ) 内存优化 的 动画 执行 完整流程 ( ① 准备 UIImage 数组 | ② 设置动画参数 UIImage数组 时长 重复次数 | ③ 启动动画 | ④ 异步设置图片数组为 nil )
内存优化后的 动画 执行流程 :
- 1.首先判断 动画 是否在执行 : 动画执行 操作 会覆盖 上一次的 动画 , 每次 调用 startAnimating 都会 重新开始 执行动画 , 因此 当动画正在 执行时 , 不要覆盖 ; 使用 isAnimating 方法 先判断 动画是否在习性 ;
// 1. 先判断 动画是否在执行 , 如果动画在执行 , 直接退出方法
if([self.imageView isAnimating]) return;
- 2.准备数据 : 准备 UIImage 数组 ; 这里需要从 Bundle 中获取图片 , 因此需要将图片 放置在 Xcode 中的 Assets.xcassets 之外 ( Bundle 中无法获取其中的资源路径 ) , 拖入一个图片文件夹 , 这里要注意 在 “Choose options for adding these files” 对话框中 选择 Create groups 选项 , 否则 就无法获取到 Bundle 中的 文件路径 ;
// 2. 数据准备 , 准备 UIImage 数组
NSArray *nameArray = @[@"1_Mustang", @"2_Prado", @"3_Camaro", @"4_LandCru", @"5_Mondeo"];
NSMutableArray *imageArray = [NSMutableArray array];
for(int i = 0; i < nameArray.count; i ++){
//2.1获取 Bundle
NSBundle *mainBundle = [NSBundle mainBundle];
//2.2获取 图片对应的 Bundle 路径
NSString *path = [mainBundle pathForResource:nameArray[i] ofType:@"jpeg"];
//2.3根据 Bundle 路径 获取 UIImage
UIImage *image = [UIImage imageWithContentsOfFile:path];
//2.4获取 UIImage 对象 , 并放入数组
[imageArray addObject:image ];
}
- 3.设置图片 : 将准备好的 UiImage 数组 设置 到 animationImages 属性中 ;
// 3. 设置图片
self.imageView.animationImages = imageArray;
- 4.设置动画参数 : 设置动画的 时长 ( animationDuration 属性 ) 和 重复次数 ( animationRepeatCount 属性 ) ;
// 4. 设置动画参数 : 时长 , 循环次数
self.imageView.animationDuration = 1;
self.imageView.animationRepeatCount = 1;
- 5.开始执行动画 : 执行 startAnimating 方法 , 开始执行动画 ;
// 5. 开始执行动画
[self.imageView startAnimating];
- 6.清除动画图片方法 : 直接将 UIImageView 的 animationImages 动画图片数组 设置为 nil 即可 ;
//清除 UIImageView 的 动画图片
- (void) clearImage {
self.imageView.animationImages = nil;
}
- 7.异步执行方法 : 需要 在动画开始 1 秒之后执行 , 代码实现如下 :
// 6. 1秒后清除 动画图片
[self performSelector:@selector(clearImage) withObject:nil afterDelay:1];
- 8.完整代码 :
//播放动画 并释放内存
- (IBAction)startAnimationReleaseMemory:(UIButton *)sender {
// 1. 先判断 动画是否在执行 , 如果动画在执行 , 直接退出方法
if([self.imageView isAnimating]) return;
// 2. 数据准备 , 准备 UIImage 数组
NSArray *nameArray = @[@"1_Mustang", @"2_Prado", @"3_Camaro", @"4_LandCru", @"5_Mondeo"];
NSMutableArray *imageArray = [NSMutableArray array];
for(int i = 0; i < nameArray.count; i ++){
//2.1获取 Bundle
NSBundle *mainBundle = [NSBundle mainBundle];
//2.2获取 图片对应的 Bundle 路径
NSString *path = [mainBundle pathForResource:nameArray[i] ofType:@"jpeg"];
//2.3根据 Bundle 路径 获取 UIImage
UIImage *image = [UIImage imageWithContentsOfFile:path];
//2.4获取 UIImage 对象 , 并放入数组
[imageArray addObject:image ];
}
// 3. 设置图片
self.imageView.animationImages = imageArray;
// 4. 设置动画参数 : 时长 , 循环次数
self.imageView.animationDuration = 1;
self.imageView.animationRepeatCount = 1;
// 5. 开始执行动画
[self.imageView startAnimating];
// 6. 1秒后清除 动画图片
[self performSelector:@selector(clearImage) withObject:nil afterDelay:1];
}
//清除 UIImageView 的 动画图片
- (void) clearImage {
self.imageView.animationImages = nil;
}
( 4 ) NSBundle pathForResource 为 nil 解决方案 ( ① 拖入目录 选择 Create gropus | ② 查看 Xcode 项目 配置 -> Build phases 的 Bundle 配置 )
NSBundle pathForResource 为 nil 解决方案 :
- 1.拖入目录方法 : 在 将 pic 目录 拖入 Xcode 中时 , 需要选择 Create groups 选项 , 不能选择 Create folder reference 选项 ;
- 2.确认是否可以获取到 : 在 Xcode 项目设置中 , 如果有 要获取的 具体的 图片 文件设置 , 那么可以获取到 , 如果只有 图片的 目录 pic , 没有具体的 图片 配置 , 那么图片就获取不到 ;
( 5 ) 效果展示
效果展示 :
博客相关资源 :