仿网易彩票思路
第一步、 项目的配置
1>
新建项目:项目前缀:把项目名称里面的大写抽出来。
2>
支持项目部署,支持ios6,ios7
3>
不支持横竖屏
4>
导入图标和启动图片
5>
程序启动的时候,隐藏状态栏,ios6需要恢复状态栏显示
6>
设置状态栏颜色 ios7默认状态栏交给控制器管理,修改info.plist文件,让状态栏交给application管理
6>
项目文件夹按模块划分,Main:(主框架,自定义tab控制器),Other:存放其他头文件和.m文件(main,代理,pch(头文件))
第二步、 搭建项目主框架
1>
修改窗口的根控制器。
原因:主窗口的根控制器是TabBar控制器,TabBar里面的子控制器是导航控制器?为什么,因为每个导航条的标题不一样。
第三步、设置tabBar上按钮的图片
存在的问题:
1>
设置tabBar上面的按钮图片不好使,tabBarButton的图片有规格,用不了。
解决方式:
1>
自定义tabBar,系统自带的tabBar上的tabBarButton都不好使,自定义的tabBar添加UIButton,注意继承UIView,因为UITabBar里面的子控件根本用不上。
2>
自定义tabBar,添加5个按钮,显示图片
存在的问题?
1> tabBar里面的按钮应该由控制器决定
2> push控制器的时候底部条,隐藏不了。
解决方法:
1> 提供一个方法,给控制器添加按钮。系统自带的tabBar里有多少按钮也是根据控制器个数决定的。
2> 把自定义tabBar添加到系统自带的tabBar上
第四步、点击按钮,切换控制器(UITabBarController.selectedIndex)
存在的问题?
1>
只有UITabBarController设置selectedIndex才可以切换控制器,但是UITabBarController不知道当前选中哪个按钮
解决方式:
2>
用代理或者block把角标传给控制器
第五步、设置导航条的外观(背景图片和文字),只需要设置一次.
1>
为什么要获取整个应用程序的导航条外观?避免拿到一个一个导航控制器去设置导航条的外观
2>
怎么获取?UINavigationBar *navBar = [UINavigationBar appearance]
只要遵守UIAppearance这个协议,都可以这样获取。
3>
设置导航条的背景颜色?ios7和ios6是不一样的。
4>
运行ios6,适配ios6的导航条。
5> ios7和ios6导航条图片的区别?
ios7:控制器包括状态栏20的高度,导航条的高度为64,会自动把状态栏20的高度填充
ios6:状态栏20的高度不属于控制器,导航条高度44。用44高度的图片
6>
定义宏,方便适配 #define iOS7 ([[UIDevice currentDevice].systemVersion floatValue] >=
7.0)
7>
设置导航条文字颜色
第六步、自定义导航控制器
1>
为什么要自定义导航控制器?拦截push操作,重写push方法,在push的时候,隐藏底部条,就不需要一个控制器一个控制器的勾选Hide
Bottom Bar on Push
2>
在自定义导航控制器设置导航条外观
3>
在initialize里设置:导航条外观只需要设置一次
4> initialize:在第一次使用这个类或者子类的时候调用
5> initialize里判断下是否是本类调用,是才需要设置导航条,保证设置一次主题。self
== [ILNavgationController class]
第七步、 完成每个模块的导航条
购彩大厅:系统自带的UIBarButton不能同时设置图片和文字,拖一个按钮同时设置文字和图片,还需要设置按钮宽度,资讯和图片中间有间距。
//
设置按钮标题的位置
- (CGRect)titleRectForContentRect:(CGRect)contentRect;
//
设置按钮图片的位置
- (CGRect)imageRectForContentRect:(CGRect)contentRect;
合买跟单:titleView需要自定义按钮,设置内部的位置
第八步、自定义按钮:修改内部子控件的尺寸
1.获取当前文字:self.currentTitle
2.获取当前文字尺寸.计算内部Label的尺寸。
3.图片尺寸:假设图片宽度30.
w = contentRect.size.width -
30
注意点:
* titleRectForContentRect内部不能调用self.titleLabel,会造成死循环。因为self.titleLabel内部会调用titleRectForContentRect
* boundingRectWithSize在ios7才有,ios6没有这个方法,需要判断使用。
第九步、 自定义按钮尺寸计算-多版本处理
1>
理解编译时报错和运行时报错?#import <Availability.h>
2>
运行时报错:在SDK7.0的环境(xcode5)编译boundingRectWithSize,是不会报错的,但是运行在ios6的系统上会报错,ios6没有这个方法。需要判断当前运行在哪个系统,用ios7宏判断。
3>
编译时报错:在SDK6.0的环境(xcode4.6)编译boundingRectWithSize,是直接报编译错误,因为sdk6.0没有这个方法。
第十步、 我的彩票(登录界面)-ios7和ios6简单适配
存在问题
1>
观察UIImageView的y值
1> UIImageView的y值在ios6和ios7不一样。
原因:
0> ios6,ios7控制器view的尺寸不一样。
1> ios6里主流框架中,导航控制器的根控制器view的尺寸,很小。PPT演示,ios6控制器从导航条开始,ios7从屏幕左上角开始,包含状态栏。
2> ios7多了一个edgesForExtendedLayout属性,才让导航控制器的根控制器view的尺寸和屏幕一样大.
3> edgesForExtendedLayout可以让控制器上下左右扩展
解决:
1>
通过代码判断下,调整在ios7和ios6的UIImageView的位置,这种方式麻烦。因为界面是固定的,用xib或者storyboard描述更省时间。
2>
找到我的彩票控制器,告诉他不要上下扩展就好了,找到Extend Edages,把Under Top Bars
和
Under Bottom Bars取消选中
2>
一般开发中,如果不需要滚动的控制器,就不需要扩展,因为不需要有穿透效果。
3>
在ios7取消我的彩票控制器的上下扩展。这时候ios7导航控制器的根控制器view的尺寸就和ios6一样的了。
4> autolayout解决运行在3.5上图片被压扁。
13>
登录按钮图片拉伸(按钮尺寸:300
*
40)
1>
拉伸图片中间一个像素点。
2>
通过storyboard只能拉伸UIImageView
3> storyboard中
x:表示左边多少不拉伸
y:表示上边多少不拉伸
w:表示宽度拉伸多少个像素
h:表示高度拉伸多少个像素
x:0.5(左边一半不拉伸)
y:0.5(顶部一半不拉伸)
w:0
(宽度拉伸一个像素) h:0(高度拉伸一个像素)
4>
拉伸按钮,必须通过代码。
5>
自定义登录控制器loginController
6> UIImage抽分类resizableImageWithName
14>
我的彩票(右上角设置按钮的颜色和返回按钮的颜色默认是蓝色,需要设置为白色)
1>
应用程序所有导航条上的UIBarButton都需要设置白色的。
2> UIBarButton在导航条上,所以我们设置导航条的主题颜色就好了。
3>
获取整个应用程序的外观设置主题颜色
UINavigationBar setTintColor(主题颜色)
3>
只需要设置一次,并且跟导航控制器有关系,在导航控制器里的initialize里设置,并且之前在导航控制器拿到了整个应用程序的导航条
15>
设置ios6上应用程序所有导航条上的按钮背景
1>
导航条白色主题只有在ios7才需要设置。
2>
设置导航条上的UIBarButton背景,只有在ios6才需要设置
3> UIBarButton由UIBarButtonItem决定。
4>
获取整个应用程序的UIBarButtonItem,设置整个应用程序的UIBarButton。避免一个控制器一个控制器的设置
5> UIBarButtonItem setBackgroundImage
//
设置按钮背景
6> UIBarButtonItem setBackButtonBackgroundImage
//
设置返回按钮背景
/*
彩票第二天
*/
1>
搭建设置界面分析
1>
静态单元格:一个cell一个cell的改,太麻烦,而且不灵活
2> plist文件:配置plist文件太费时间
2>
自定义设置控制器(代码跳转)
1> group样式
2>
分析数据结构:大数组里面存放两个小数组,小数组存放每一行的模型
3>
实现数据源方法
* 大数组:告诉tableView有多少组
tableView:numberOfSectionsInTableView:
* 小数组:告诉tableView每一组有多少行
tableView:numberOfRowsInSection:
* 小数组里存:每一行长什么样
tableView:cellForRowAtIndexPath:
3>
自定义cell模型,ILSettingItem(title,icon)
1>
运用模型,展示tableView数据
4> tableView里面的所有显示都交给模型去管理?怎么做
1>
自定义组模型,ILSettingGroup(header,footer,items):每一组有头部标题和尾部标题和有多少行cell。
5>
模型差不多设计好了,该封装视图了。设计步骤:先设计模型,在封装视图。因为视图是根据模型展示的。
1>
自定义cell,传一个模型,就展示数据。
2> accessoryView:由模型决定。tableView上的所有显示,由模型决定。
3>
给item模型添加一个枚举。不够面向对象,应该把每一个cell的类型都对应一个模型,因为不同的cell类型不同的操作。箭头的cell一般需要跳转,开关的不需要跳转。箭头应该比开关多添加一个属性,跳转的控制器类型Class。
4>
自定义箭头模型(ILSettingArrowItem),继承ILSettingItem,添加一个跳转的控制器的属性,并提供一个类方法
1> Class
用assign
因为不是都系类型,不需要管理内存在的问题
2>
为什么用Class,因为Class写错类型就会报错。
5>
自定义开关模型(ILSettingSwitchItem),继承ILSettingItem。
6>
设置cell的accessoryView
1>
完善tableView模型,弄真实数据。
2>
在重写set模型的方法里,根据item的类型判断cell上显示什么样的accessoryView。
3> cell懒加载UIImageView和UISwitch,注意用strong,否则会被销毁,没有其他视图强引用他,没有addSubviews。
4>
总结:只要没有add的控件,都需要强引用
7>
完善cell的跳转功能
1>
点击cell就跳转
2>
实现tableView代理方法didSelectRowAtIndexPath
1.根据模型判断是否需要跳转
2.是否有destVcClass属性
3.通过类名创建控制器对象,跳转。[[arrowItem.destVcClass alloc] init];
8>
检查新版本cell(完善cell操作功能)
1>
点击更新cell,做一些事情,而不是跳转,怎么做?
2>
最蠢的办法根据角标去判断,点击了哪一行
3>
更新操作交给模型去管理。让模型保存一个功能,功能及代码。
4>
怎么保存代码?给ILSettingItem添加一个block属性,用block保存一段代码.
5>
每一行cell应该都会有操作,因此给ILSettingItem添加block属性,这样子类都有这个block属性
6>
完善更新模型
1. 思路:只有服务器才知道是否有最新数据,因此需要发送网络请求
2. 更新功能步骤:
发送网络请求(当前手机版本)
-> 服务器返回数据(是否需要更新)
-> 弹框提示用户。
3. 如果需要更新跳到appstory更新
7>
点击cell的时候调用block
8>
更新cell一直选中状态,应该点击一行的时候,立即取消
9>
产品推荐(UICollectionViewController)
1>
使用UICollectionViewController,跳入头文件,发现和UITableViewController一样,有数据源和代理
2> UITableView每一行是UITableViewCell,UICollectionView每一个是UICollectionViewCell
2>
实现数据源,
* numberOfSectionsInCollectionView
返回UICollectionView有多少组
* numberOfItemsInSection
返回一组多少个
* cellForItemAtIndexPath
返回一个cell长什么样
3>
解释section,item,循环利用。section:哪一组
item:哪一个
4>
怎么使用UICollectionViewCell?必须先注册,init方法没有提供标识符的构造方法
5>
注册cell,在viewDidLoad注册一次
6>
必须传入布局,告诉他怎么布局。这么多格子,他怎么知道怎么布局啊。
7>
使用流水布局 UICollectionViewFlowLayout ,
封装到控制器里面
8>
怎么设置UICollectionViewCell的尺寸和位置,通过layout布局设置
10>
完成产品推荐(分析产品json数据)以后的思路都是这样的,
思路:解析数据,转换模型,描述界面,传递模型给界面,展示到视图。
1>
解析json数据,json最外面是[],表示这是个json数组,解析出来也是数组
2>
创建模型,提供类方法,不能用KVC,id比较特殊
3>
自定义cell,传递模型
4>
注册xib的cell
5>
设置cell里UIImageView的圆角属性,设置cell的尺寸。
6>
监听点击
7>
导航条的标题:在push之前的时候就设置,拿到模型的title直接设置
vc.title = arrowItem.title;
10>
推送和提醒模块(抽取父控制器)
1>
分析界面外观:跟设置界面一样的cell,只需要给cell传递一个模型,就自动生成一个界面了。
2>
配置模型
3>
抽取父控制器ILBaseTableViewController
4>
配置中奖提醒,中奖动画,比分直播(ILAwardPushViewController,ILAwardAnimationViewController,ILScorNoticeViewController)
5> ILScorNoticeViewController控制器比较特殊,cell右边有label
6>
根据模型,显示cell
7>
自定义ILSettingLabelItem,添加text属性,用于显示label文字
8>
修改ILSettingCell,根据模型,判断是否懒加载UILabel,label必须设置尺寸
9>
配置比分直播的模型
11>
比分直播label处理
1>
从下往上钻的是什么?键盘才有这样的效果,也就是点击label弹出键盘
2>
什么东西能弹出键盘?textField成为第一响应者
3>
创建一个textField,不需要显示,目的就是弹出键盘
4>
修改键盘inputView为UIDatePicker
* 设置UIDatePicker的默认时间
//
日期格式对象
NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
fmt.dateFormat =
@"HH:mm";
//
字符串转日期
NSDate *date = [fmt dateFromString:_startItem.text];
_datePicker.date = date;
* UIDatePicker的模式
//
模式
_datePicker.datePickerMode = UIDatePickerModeTime;
* UIDatePicker的地区
//
地区
_datePicker.locale = [NSLocale localeWithLocaleIdentifier:@"zh_CN"];
5>
监听UIDatePicker的滚动,改变ILSettingLabelItem的值
* 日期转字符串
NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
fmt.dateFormat =
@"HH:mm";
_startItem.text = [fmt stringFromDate:datePicker.date];
6>
刷新表格,更新界面
12>
数据存储
1>
存储cell的accessoryView的状态,用[NSUserDefaults
standardUserDefaults]快速存储,别忘记同步synchronize
2> ILSettingLabelItem的text
* 重写模型setText方法,在设置的text的时候就存储。
* key:用模型的title属性,目的知道是哪个cell存储了,每个cell都有title
3> ILSettingSwitchItem开关的状态
* 监听switch的改变
* 给模型添加一个属性,开关属性off
* 重写setOff方法,设置的时候就存储
4>
怎么读取,重写两个模型的setTitle方法,在设置title的时候就读取一次,给对应的属性赋值。
* ILSettingLabelItem存储代码
- (void)setTitle:(NSString *)title
{
//
这里不能拿到_title赋值,只能调用父类的set方法赋值
[super
setTitle:title];
_text = [ILSettingTool objectForKey:self.title];
}
- (void)setTitle:(NSString *)title
{
//
这里不能拿到_title赋值,只能调用父类的set方法赋值
[super
setTitle:title];
_off = [ILSettingTool boolForKey:self.title];
}
* ILSettingSwitchItem存储代码
- (void)setOff:(BOOL)off
{
_off = off;
[ILSettingTool setBool:off forKey:self.title];
}
- (void)setTitle:(NSString *)title
{
//
这里不能拿到_title赋值,只能调用父类的set方法赋值
[super
setTitle:title];
_off = [ILSettingTool boolForKey:self.title];
}