百思不得姐第3天:登录注册界面搭建
一:登录注册的界面效果如图
二:界面的搭建
1:登陆界面一般都是moda的模式:新建控制器,勾选xib,则系统会自动关联类,并且自动连线关联view(若是后创建的控制器的xib,则类名相同,关联类,在fileOwer处连线view),而我们自己不用去设置控制器view的frame。或是freeform,只需要更改控制器view的尺寸,例如4.7寸,那么在别的机型上运行正常适配。2:一般背景比较好看的都为背景图片。 3:控制状态栏的样式:1:[UIApplication sharedApplication].statusBarStyle; 设置全局状态的导航栏,还需要配置plist ,设置view controller base 为 no(不推荐) 2:从ios7开始就可以在控制器内,设值状态栏。- (UIStatusBarStyle)preferredStatusBarStyle
{ return UIStatusBarStyleLightContent;}
两者设置其一,则另一个就不管用,不推荐使用第一种,默认颜色为黑色。2:隐藏状态栏:- (BOOL)prefersStatusBarHidden 若是配置了pills,则用[UIApplication sharedApplication].statusBar hidden
2:登录界面的UI分析:1:控制器或是view,要想到分层封装思想(参照新浪微博cell的封装),将控制器或是view切分成一个个模块,分析每个模块都由哪些控件组成,将零散的控件都封装在一个统一的模块内部(具体参照view的方法),再看封装的每一个模块的内部view是否还可以继续封装,然后再看封装的view,是否项目中的其他地方也可以用到,若是可以,则想到继承,将公共部分抽成父类,子类去继承父类,不同的部分在子类中实现,1:父类可在.h中暴露方法,再在.m中实现该方法,则子类也继承了父类的方法,当子类调用父类的方法的时候,就会调用父类的实现方法 (新浪微博参数模型的抽父类继承)2:若是有多个子类继承同一个父类的时候,在父类中父类要根据不同的子类来执行不同的方法,此时父类可提供一个标识的属性方法供子类继承重写其get方法,此时在父类中就可以区别不同的子类了(百思的主界面继承结构)3:若是父类提供了某个方法,父类也实现了该方法,则子类继承该方法后,继续重写该方法,1:若是不保留父类行为,可以不调用super。 2:调用代码写在super之上,重写setframe方法,重新设计参数传入super方法 3:写在super之下,则先是保留父类的行为,在设置子类的行为 2:如图的登陆界面,则封装成三个view,上部一个view,中间一个view,底部一个view,而对于底部的view,也可以封装成两个view,上部一个view,底部一个view,底部的view中的按钮又可以继续去封装 3:当拷贝xib中已经设置好的约束控件后,只会拷贝宽高约束,其他约束不会拷贝。如图:中间为lable,两边为uimageView
补充:1:新浪微博cell的封装MVVM思想:1:封装的背景view0直接添加到cell上,又将微博正文view1 与 底部工具条 view2,封装起来添加到view0上,底部的工具条view2封装为一个整体view2,微博正文的view1的层级机构为原创微博view3与转发微博的view4,将头像昵称时间皇冠,微博内容,图片等信息都封装在原创微博的view3里,其中微博的图片又封装了一层view5,专门用来显示图片,被转发微博的微博正文和图片都添加到view4上。注意:不管有没有显示,先将尽可能显示的控件全部都添加到封装的view中,再根据数据模型model的字段值来判断让控件显示还是隐藏,要考虑到cell的循环利用(显示了,还要隐藏回来),避免因为cell的复用出现数据错乱。2:MVVM思想:把cellFrame封装为一个数据模型,在cellFrame数据模型的内部status数据模型作为cellFrame数据模型的属性,根据status数据模型的字段值来设置给个控件的frame,cellFrame的好处:既可以为控件设置frame,又可以为控件设置属性值。而每一个封装的view都对应一个cellFrame模型,在控制器内部的数据源也是存放的cellFrame的数据模型。MVVM思想层次结构更加清晰,大量简化了控制器的代码便于维护 3:如何设置cell的高度:1:在cell中设置:在cell中提供类方法传入每行row对应的数据模型,根据数据模型的字段值计算出总的cell的高度 2:在model中提供高度的属性,在model中重写get方法,根据model中的字段值计算总的cell的高度,为了优化,还可以设置内存缓存,当计算过cell的高度后让其直接返回,不再执行计算高度的方法。(推荐第二种)
2:view的封装方法:无论是代码还是xib都要想到模块化分层封装的思想。
1:instanceType方法提供类方法快速返回对象,1:内部调用alloc init ,alloc init内部调用[alloc initWithFrame ]方法,[super initWithFrame ]会调用setFrame方法,可以重写setFrame方法来设置自身固定的frame,禁止外界更改,还可以重写setFrame设置cell的上下左右的间距,分割线等,当外界设置frame的时候,又会调用setFrame方法,当setFrame方法调用完毕后,才会调用layoutSubview方法来设置frame 2:可以在[alloc initWithFrame ]方法中设置自身封装view的一些特定属性,或是一次性代码 2:懒加载子控件:(懒加载的作用:1:不用考虑代码的创建顺序 2:保证只初始化一次 3:懒加载可用weak 和 strong 都可以)在懒加载的方法中设置子控件的属性,并将子控件添加到父控件上。
2:重写layoutSubView方法设置子控件的frame:在此方法内设置子控件的frame较为准确严谨,不要忘记调用super,且此方法配合setNeedsLayout和layoutIfneed配合使用:前者是异步调用layoutSubView方法,而后者layoutIfneed是立即调用layoutSubView方法来更新约束。1:如何拿到控件:1:属性,成员变量,枚举tag值(1:直接取,2:或是遍历父控件的子控件数组,通过tag值取出,tag值一般不要设为0,不安全,因为所有控件默认的tag值都为0 3:一般在设置tag值的时候通过self.subviews,count 也可以设置tag值),或是继承父类直接从父类属性获取 2:将创建的控件放在一个属性定义的大数组中,若是含有不同类的控件则两两放在大数组中,在layoutSubView里通过for循环从数组中取出子控件 3:遍历父控件的子控件数组:1:self.subViews(UIView和scroll隐藏掉两个滚动条后是最纯洁的view,除了自己添加的不含有任何 子控件,所以可以直接遍历父控件的子控件数组),需要index就采用int i 遍历,不需要就可以采用for in快速遍历,并在外部定义index,内部index++,来记录索引值,也可以用enumer来遍历可以得到索引值和遍历的对象。在遍历时,先要做条件过滤(1:continue 2:return过滤,不执行return下面的代码,3:break,跳出循环,不再循环)找到后设置值,并停止遍历 2:若是遍历父控件的self.subViews子控件数组,有时候系统父控件没有直接提供属性使用,这时,可以打印子控件数组或是通过ViewUI来调 试查看所需要的子控件是什么,这样就可以拿到子控件从字符串转化为类,NSClassFromString()(新浪设置中间加号按钮)3:利用runtime拿到系统控件私有的属性来进行设置
3:为封装view设计model接口与业务逻辑接口:设计model接口,重写model的set方法,为封装view的子控件赋值。业务逻辑的接口设计:1:把与外界无关的业务逻辑全部封装在类的内部,类再提供接口供外界访问,保证外界调用时最简洁最方便的的 2:对于接口的设计:一般用属性接口重写通过重写代替方法接口,是否就提供BOOL属性接口,不同类型,就提供枚举type接口,外界想访问类内部的什么方法,变量就给外部提供属性接口。
4:业务逻辑的监听处理:1:查看子类有没有系统代理方法,通知方法,或是继承UIControl的可以addTarget都可以实现监听,若是子类没有还可以查看父类有没有上述 的方法,在查看系统的API时,可以查看其其英文注释该方法的使用说明,也可以按住option键点击某个方法来查看使用说明 2:通过重写监听:在开发中遇到问题首先考虑重写,重写非常好用,继承父类,通过重写父类的方法也可以对父类行为进行拦截,覆盖或是监听父类的行为。但是不要忘记调用super, 否则父类的默认行为就不会响应。3:当监听自身的属性变化的时候,可以使用kvo实现监听,当属性变化的时候可以去实现某些方法
5:监听回调:1:层级较浅时,用协议代理(1:仿照tableView的代理方法设计协议代理 2:有时需要重写setDelegate方法来,也就是成为代理之后才可以去做某些设置)block,两者都可以,当两个类需要相互回调时,可以给协议代 理或是block设置返回值,就可以实现两个类相互回调 2:层级较深的时候:可以利用通知回调,传值,其中通知可以在当前线程或是子线程中执行(只看post通知的时候在哪个线程里,注册观察者后,执行通知方 法就在哪个线程),其中注册观察者也可以用block方式注册观察者,并指定收到通知后的block任务在哪个线程中执行(也可实现一次性的通知,在 block中执行完任务后,就取消观察者),如果采用block的方式注册的观察者,要以熟悉定义id类型返回值类接受block通知的返回值,以便在 dealloc中注销观察者。一般项目中的通知名都写在配置常量的类里
6:考虑继承关系:若是封装的该view在项目中其他的地方也可以用到,则考虑用继承,将相同的部分抽成父类,让子类去继承,不同的部分在子类中实现,父类可以给子类提供方法供子类去重写,实现父类和子类相互的关联
7:问题分析:当系统提供的控件不能满足我们的要求的时候,我们可以选择自定义控件,自定义控件继承系统的控件,1:重写layoutSubView方法,1:在该方法内部直接拿到系统的控件去设置 2:如果不能直接拿到系统的子控件,在该方法内部遍历系统控件的子控件数组,并打印或是通过viewUI来调试查看子控件,再通过NSClassFromString来进行设置 3:利用runtime拿到系统控件内部私有的成员变量去设置(更改文本框的占位文字颜色)2:通过继承关系,自定义控件的子类重写父类的方法,super的调用三种情况。通过重写父类的方法可以实现对父类行为的监听,覆盖,修改 3:还可以为系统的类写分类,在分类中提供方法
3:控制器中代码的规范:1:先分析界面的UI,分析好界面的封装结构,先要整理好逻辑,把逻辑理顺了,再去下手去写代码 2:1:在控制器中实现+(void)load,做一些常用配置(例如配置MJExtension字典转模型的配置),不管有没有子类,该方法只执行一次,并且不用导入头文件 就可以调用,也就是该类被加载进内存就会调用 +(void)initalize该方法可能会被调用多次,当类被初始的时候会被调用,当有子类的时候,会先调用父类的+(void)initalize方法,在调用子类的+(void)initalize方法(父类中重写了+(void)initalize方法,子类继承,没有重写),在该方法中可以初始化一些配 置的设置或是只需要一次性设置的(自定义导航控制器设置全局导航主题,或是数据库建表)重写控制器的init方法,可以在控制器创建初始化时传递参数或是 初始化时做一些固定的一次性设置,例如设置tableView的样式可以在初始化的时候调用,当控制器初始化的时候会调用控制器的init方法。-(void)loadView方法,重写此方法可以更改控制器的self.view viewDidLoad方法view加载完毕后调用,viewWillAppear 或是viewWillDidAppear 这两个方法会调用不止一次,只要是界面出现即将出现就会调用,pop,dissmiss都会调用,一般在viewDidAppear方法中打印控件 的信息,因为此时控件已经完全显示出来,viewWillDisappear,viewDiddisappear页面即将消失或是已经消失 的时候调用,dealloc控制器销毁的时候调用,在此方法中可以移除通知或是在控制器销毁的时候传递给其他控制器一些数据信息。2:我们一般在 viewDidLoad方法中采取封装方法调用 1:当控制器中某个方法含有大量重复的代码时要考虑抽方法封装,将相同的代码抽到方法的内部,不同的部分作为参数传递 2:若是代码中涉及某些业务逻辑的处理或是项目中各个地方都可以用到,则也应考虑到封装:1:分类封装:1:当此段业务逻辑与系统某个类有关系时,要想到 给系统类写分类,而且能写分类尽量写分类,因为分类会少创建类,减少内存 2:分类的接口设计:对象方法或是类方法,类方法较对象方法简餐粗暴,但是当需要传递两个参数的时候可以考虑利用对象方法,分类中的self指的就是传递 的参数 ,若是在分类中以属性定义变量,则只会生成set和get的声明,不会生成实现也不会生成带下划线的成员变量,若是此时外界想要访问分类某个变量则可以用static定义的全局变量 在get方法中返回就可以了 2:管理类Tool封装:单例或是类方法,在类方法中要是想获得单例一样的成员变量,就用static定义全局变量,该成员变量也可以采用懒加载模式,只 让其初始化一次,外界若是想访问该成员变量,则该类可以提供接口get方法接口,供外界调用(get方法接口也可以用点语法去调用)3:考虑继承:将相同 的部分抽到父类,不同的部分分别在子类中去实现,父类可在.h中暴露方法供子类去重写(父类可提供标识属性,供子类去重写,以便于在父类中区分不同子 类),子类重写父类的方法后,也就相当于间接修改了父类的属性,父类中也就可以拿到子类修改的属性。3:控制器或是view中每一行代码的编写,都要力求 使最简洁的,要反复推敲,提炼,直到代码是最简洁不能再抽为止。1:像是hidden或是返回bool值的方法中一句代码解决 或是利用三目运算简化ifelse 2:赋值散三部,最上面定位nil,中间赋值,最后赋值 3:有两个返回值时,只用一个if,分别返回,不用if else 4:当遍历的时候,先做条件过滤(continue,braek,或是return条件过滤),找到赋值,并停止遍历。
三:登陆界面的知识总结
1:背景为图片,所以拖一个UIImageView设为其背景图片,在xib的左侧界面可以设置注释,方便查看:左侧都可以:1:添加
注释 2:可以设置相互间的层级关系 ,父子关系 3:可以设置约束,可以选中左侧的某一项,向另一个拖线设置约束,若是想设置多个约束,按住shift键,选择多个约束,点击add添加约束就可以了 3:
1:左边写注释,可以拖动成为某某子控件设置控件之间的层级关系,可以进行两个view之间的拖线限制约束 2:中间可以拉线设置约束 3:下面可以设置约束,一般设置对齐方式也会很简单的 4:右侧,查看约束,双击约束,可以更改约束的比例值
2:顶部view的约束设置:
:
1:xib设置按钮:要设置按钮的高亮状态,如果用system样式,则不能显示高亮状态,所以必须设置按钮的状态为custom状态,如果按钮的状态为system样式,则有时该按钮会被系统渲染为蓝色,图片按钮若不设置按钮的宽高,则默认按钮的宽高为图片的宽高。 2:设置如图所示的图片按钮:用set image,和setbackgruondImage都可以,但是最好用set image,图片不会变形,还会增加额外点击区域。setbackgruondImage,按钮有多大,图片有多大,有时图片会变形的,若使其不变形,就让图片的size等于按钮的size。
3:设置中间大view的约束:
具体思路:1:设置背景view的约束,先设置中间view左边右边对齐,顶部间距,高约束,当子控件再父控件上时,设置这些约束,就从如图处设置:设置具体约束值的时候也从如图处设置(如图所设置的就是距离设置约束控件距离最近的控件),不用拉线太麻烦。设置间距值等宽登高,对齐方式就从如下图的地方去设置。拉线一般不设置具体约束值的时候如等宽等高的时候,可以按住shift键拉线设置多个约束值并点击add。(中间view最后会去除高度的约束,最后让中间view的高度等于所有子控件的高度)
2:输入框的约束的设置:1:输入框背景为UIImageView,UIImageView设置水平居中,顶部约束,可以设置其宽高等于背景图片的宽高 2:分别拖入两个文本输入框,在最左侧分别选上文本框和背景图片,在最下角处设置两个左对齐,顶部,右对齐,高度等高,此时来到如图所示:登高处双击更改为0.5,也就是为背景框的一半高度。拖密码的文本框,设置左对齐,底部对齐,右对齐(在右下角设置子控件与父控件对齐)并设置两个文本框对齐。
3:登录按钮的约束设置:同时在左侧选中文本框背景和登陆按钮,来到右下角,设置左对齐,右对齐,顶部间距约束,不设置宽高,让其宽高等于图片的宽高(lable,imageView,btn都可以不设置宽高约束,让其根据内容自动计算宽高值)。
4:设置忘记密码的约束:同时在左侧选中文本框背景和忘记密码按钮,设置右对齐,顶部间距,不设置宽高约束,让其直接根据按钮内容的大小自动计算宽高值。
5:设置中间view的高度等于内部子控件的高度:删除之前设置的中间view的高度,同时设置忘记密码的的底部和中间view的底部约束就可以了
6:底部view的约束:为了适配,底部view的约束,也先设置左侧底部右侧顶部的约束,底部的view可以封装为快速登陆的view,三个按钮的约束。
7:三个按钮的约束:三个分享按钮放在一个大view里,让按钮的高度决定view的高度,设置左边按钮左间距,上下间距,右间距都为0,设置高度,另外两个按钮同样,每个按钮间距都为0,在分别选中三个按钮,等宽登高就可以了,就可以平分整个view。在设置三个按钮的大view的左侧顶部,右侧,底部距离底部view的间距。最后再删除底部view的上部间距就可以了。
8:注册界面的设置:直接comand+c 复制 command+v粘贴,在左侧将注册拖到当前的视图单独存在,在删除忘记密码,设置登陆按钮距离注册界面的底部间距,以计算出注册界面的高度。同时在左侧选中注册界面和登陆的界面,设置顶部对齐,登宽,设置左侧对其,来到最右侧再双击设置注册view的左边和登陆的右边对齐。
posted on 2016-09-14 18:30 Hello_IOS 阅读(1923) 评论(0) 编辑 收藏 举报