UI组件布局及动画学习——MOSAD_HW2
一、实验目的:
- 学习使用纯代码进行UI布局
- 学习TableView,UICollectionView,UINavigationController,UICollectionController,UITabBarController等组件的使用,以及delegate和protocol的概念。
- 学习使用UIView动画及Core Animation动画
二、实现功能
- 下方导航栏分为三个界面:发现、打卡、我的;点击导航栏可以进行三个界面的快速切换。
- 每个界面上方拥有title,显示每个界面的标题
- 发现界面:
- 拥有搜索框,实现伪搜索功能,输入回车键进行搜索之后,弹出搜索成功的提示框
- 背景为自左上到右下渐变
- 拥有打卡清单的滚动列表,打卡记录按时间倒序从上至下排列,下方或上方加载新的打卡记录时,拥有0.5s的加载动画
- 每个打卡记录为圆角矩形,并且点击打卡记录后,会显示0.5s的转场动画,之后跳转至打卡详情页
- 打卡界面:
- 用户输入时间、地点、景点名称、心得、配图进行打卡
- 用户点击配图的图片按钮进行添加图片,最多可以添加6张
- 时间要求格式:yyyy.mm.dd,否则点击发布会显示错误信息
- 发布成功后弹出发布成功提示框,之后跳转 到发现界面
- 我的界面
- 第一次进入时,在中心为登陆按钮,点击后进入用户信息界面,显示用户信息和版本信息
三、程序实现:
3.1 整体架构:
一开始在编写程序时,使用的是Navigation来做页面,而且root界面设定为发现页面,这虽然也能够实现页面跳转,但是无法实现刚进入程序时就是发现界面,之后更改为目前框架,使用一个TabBarController来作为根控制器,然后把发现界面,打卡界面,我的界面作为子界面,实现导航栏和页面跳转
文件结构:
其中:
- RootTabBarController作为根控制器,控制我们的三个主界面作为子控制器;
- viewController为发现页面文件,定义发现页面功能和样式
- AppDelegate界面为程序的初始化文件(也许),程序加载过程中加载其中的特定函数,我们在其中设定程序的window,rootviewController等信息
- MakeRecord为打卡界面,实现打卡功能
- Mypage为我的界面,实现伪登陆功能
3.2 AppDelegate:加载基础设定
app在加载过程中会调用AppDelegate的该函数进行初始化信息的加载,所以本次实验中我们要做的就是创建一个窗口,并加入我们设定的根控制器,这里我们用的是一个RootTabBarController作为根控制器,而不要用页面也就是真正的viewcontroller作为根控制器,否则实现页面跳转根页面会很难做(排下坑
3.3 RootTabBarController:根控制器
这是我们自定的一个根控制器,继承UITabBarController,在viewDidLoad中加载我们的子控制器,也就是我们的三个主界面进入tabbar中,实现导航栏的页面跳转
- 由于要求实现控制器图片的选中和非选中的图片不同,所以我们这里设定tabBarItem的selectedImage和非选中图片
- 这样我们分别将三个界面设定完成图片后,将其加入到我们的根控制器的子控制器中;
- PS:这里我们将vc2的代理设定为vc1,是为了之后在打卡界面向发现页传输数据用的,这里先不叙述;
3.4 ViewController:发现页面
组成:使用UINavigationBar制作title栏,NSMuTableArray存储数据,UISearchBar制作搜索框,TableView存放所有的卡打记录
首先在.h文件中定义我们要用到的数据类型:
- searchBar:定义搜索框;
- tableView:定义表单,用于显示我们的打卡记录
- 多个可变数组NSMutableArray:存储信息数据
- num:定义打卡记录数量
- 两个UINavigationBar:上方标题栏,这个刘海屏的原因,所以要两个高度才合适,因为没找到方法能够成功调整他的每个高度,所以只好设定两个,然后叠放
之后在.m文件中实现:
- init函数,初始化我们设定的几个默认打卡记录,存到可变数组中;
- viewDidLoad函数:实现背景渐变,初始化标题栏,并将所有需要加入到当前视图的内容加入到当前视图中
- searchBar初始化函数:定义代理为自身,设定背景和边框颜色和键盘属性等信息,并设定点击代理,规定搜索后弹出提示框的伪搜索:
- 代理为搜索按钮点击后出发,我们在其中设定弹出一个UIAlertController来实现伪搜索;
- 代理为搜索按钮点击后出发,我们在其中设定弹出一个UIAlertController来实现伪搜索;
- tableview:定义tableview的初始化、形状以及代理和dataSource,这两个很关键,否则之后的代理函数无法实现;
-
返回有几个分区的代理numberOfSectionsInTableView:我们要在其中返回有多少个section,因为我们用一个section来实现每一个打卡记录,所以我们将num值付给她就好了
-
每个分区的单元格数numberOfRowsInSection:我们因为每个打卡记录的显示格式都一样,所以只要返回3就好了,否则可以用switch case来实现分区单元格设置
-
每个cell的设置cellForRowAtIndexPath:判断cell是否存在,不存在的话就初始化它,并设定显示内容didSelectRowAtIndexPath
-
设定点击效果didSelectRowAtIndexPath:将输入框中输入数据传入查看页,并新建一个查看页作为子界面,进入查看页,这里设定一个0.5s的动画
-
重新绘制边框实现圆角,并且加入加载cell时候的0.5s动画willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath:这里参考了网上的方法,就不贴了,大家可以百度(太菜了太菜了
-
send这是一个接收protocol的函数,用于数据传输的接受,这里实现了数据的按顺序插入,从而实现打卡记录的排序功能:
-
最终效果:
3.5 MakeRecord:打卡界面
组成:多个Label制作提示文本,UITextFiled制作输入框,UIButton作为加入图片的元素,点击后出发系统相册加入图片,点击发布后,弹出提示框,然后触发页面跳转,跳转到发现页面
.h文件中定义我们要用到的数据类型:
- 分别为
- 五个提示的label
- 六个图片button
- 三个单行输入框UITextField
- 一个多行输入框UITextview
- 发布按钮button
- 标题栏UINavigationBar
- 提示框UINavigationBar
- 设定protocol来进行数据传输
之后在.m文件中进行实现
-
在viewDidLoad函数中实现背景渐变和页面组件的加载
-
多个label的初始化函数:实现label的初始化和位置,并设定text值,例如:
-
多个UITextField输入框的初始化函数:实现输入框的初始化,例如:
-
之后实现六个图片,这里每个图片使用button来实现,关于图片的系统调用使用的是TA提供的办法来实现,总体思路为给每个button一开始设置一个default的图片,之后给按钮设置@selector出发函数,以及点击代理和数据来源,在触发函数中设置自身的代理和初始化UIImagePickerController,之后调用[self presentViewController: imagePickerController animated:YES completion:nil]来进行图片选择,最后在代理中决定要将图片设为那个image的图像;过程代码如下:
首先定义button和设置selectot
然后触发selector函数,进行照片的选择,从系统相册中查找图片
在图片选定完成之后,触发代理,在代理中设置我们要设置的那一个button
- 我们还要设置我们的图片button一开始只显示一个,每选一个才显示另一个,这个只需要设置一下hidden属性即可,之后在点击后的出发函数中设定下一个的hidden为no
- 最后设定发布按钮:首先要设定触发函数,然后再出发函数中进行判断输入是否符合格式,如果不符合,弹出提示框,如果符合,则将数据通过protocol输入到发现页面中,并弹出成功提示框之后跳转进入,具体流程如下:
然后触发protocol函数send,将数据传输,并且设定弹出对应的提示框和动画效果
使用self.delegate来传输对应数据到发现页面,这就是上文根控制器要将vc2的代理设置为vc1的原因
实现效果
发布成功后主界面加入对应记录:
3.6 CheckRecord:查看打卡界面
本界面和打卡界面相似,区别在于本页面存储一组由发现页面所传输数据的初始化数据,用来实现内容的显示,实现方式同简化版打卡界面,不再赘述,只展示效果
图:
.h文件
效果图:
3.7 Mypage:我的界面
组成:一开始是一个登陆按钮,点击后hidden改按钮,并渲染登陆后信息
.h界面:
- 定义两个button用来作为登陆按钮和登陆后的头像设置
- leadBar和emptyBar依旧为标题栏
- tableview用于存储版本相关
- label用于存储个人信息
.m界面:
- 由于要设定一开始为登陆界面,之后点击后跳转为个人信息,所以这里与之前不同的是要设定按钮的出发函数来实现跳转:
- 设定点击登陆按钮后再加载其他的页面组建,并隐藏本身按钮
- 设定一个转场动画
实现效果:
点击登陆前:
点击登陆后:
四、心得体会:
本次实验总体感觉就是一个盲人摸象的过程,因为第一次接触oc的ui设计,所以从一开始的程序运行结构,到每个组件之间的关系和特性,controller控制器之间的关系,视图的层次结构,数据传输,页面跳转,颜色设定,函数触发等等等等,完全是一个懵懂的状态,巧的是网上的教程还很不详尽,所以几乎是自己一个坑一个坑踩过来的,其中也麻烦了助教很多次,不过终于完成了,并且对大体框架有所了解,知道了如何从零开始搭建一个ios应用的简单框架,并且明白了组件的基本使用,收获还是蛮大的,不过过程有点点艰难
五、排坑点
- 首先是要选对根控制器,一开始尝试用页面控制器作为根控制器,成功自闭,原因是实现不了首页面,并且会自动生成跳转,之后使用TabBarController作为控制器,这样虽然没有了Title栏和跳转的自动生成,但是相关功能可以自己通过添加button和相关代理的重写来实现,感觉灵活性更高
- 再就是采用我的根控制器选择方法,需要手动加入标题栏,但是好像默认高度不能够手动调整(默认设置的为44),所以这里我使用了每个页面加入了两个标题栏来模拟增加高度
- 发现页面:主要的难点是背景层次和TableView显示打卡界面,要注意tableview的自身background和每个cell的背景,还有section背景等,显示打卡界面这里要用到页面间的数据传输,父页面向子页面传输比较简单,但是这里为同级页面传输,采用了protocol来实现
- 打卡界面:难点为照片调用系统相册,这里用了助教给的博客的解决方法
- 我的界面:比较简单吧,只要成功hidden和加载就好了