彩票-设置核心功能
(彩票项目的精髓:引导页的循环利用思想,在一个就是这个设置页面—>调转table封装利用)
4.1我的彩票—>设置—>重点来了核心功能()之前页面的跳转用的是拖线,接下来用代码实现跳转。
点击设置按钮push一个TableViewController控制器
Setting(设置)功能放到一起;报的错误?:duplicate symbols for architecture //又重复定义的类;
push控制器,隐藏底部导航条:vc.hidesBottomBarWhenPushed = YES;
[self.navigationController pushViewController : vc animated:YES];很多控制器push出来的导航条要隐藏:重写push方法
修改系统的API方法添加功能,重写导航控制器的方法
来到这个,导航条用的是自己定义的导航条,重写:
??-(void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated{
//通过导航控制的子控制器的数来判断到底是不是根控制器self.viewControllers.count==0//等于0说明第一个添进去的时候根控制器,
// push之前判断一下是不是根控制器
if(self.viewControllers.count !=0){
viewController.hidesBottomBarWhenPushed = YES;
}
[super push…];
}
非根控制器的底部导航条都要隐藏,
复习一下:给导航控制器设置根控制器的时候,root的时候底层都会调用pushViewController:animated 这个方法;
[导航控制器 initWithRootViewController : vc];
统一设置导航返回按钮(导航控制器的左边的按钮)
什么时候需要设置:也是非根控制器的时候才需要设置返回按钮。
获取UIBarButtonItem setBackButtonTitlePositionAdjustment:UIOffsetMake。。。一般不使用这个方法;(setback,leftbar)
只有栈顶控制器才能设置导航控制器的左边的按钮(栈顶控制器即是要push的控制器的)
第一种方法:定义左边按钮设置图片
if(self.viewControllers.count !=0){
viewController.navigationItem.leftBarButtonItem = [UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@“”] style:UIBarButtonItemStyleBordered target : self action:@selector(back)];
//重写了left按钮,点击事件也要自己实现一下下;
}
-(void)back{
[self popViewControllerAnimated:YES];//self就是导航控制器;( 栈存储先进后出)
}
第二种设置左边按钮的方式:(本身有剪头图片修改原本的颜色,去掉文字)
[bar setTintColor:[UIColor whiteColor]];
[[UIBarButtonItem appearance] setBackButtonTitlePositionAdjustment:UIOffsetMake(0,-100) forBarMetrics:UIBarMetricsDefault];
**系统自带的返回按钮,有滑动返回功能—>自定义按钮会把这个功能给抹杀掉;
自定义按钮也想要滑动返回功能???
self.interactivePopGestureRecognizer.delegate = nil; //还原滑动返回功能;(返回手势代理清空了怎么触发监听方法等呢);
这里有一个BUG:手势交互的代理清空了,其他的手势也监听不到了
清空滑动代理之前先保存一份,在返回之后在复原之前清空的代理;(在哪里保存在哪里复原呢?)
//保存—>搞一个强引用的成员变量
self.popDelegate = self.interactivePopGestureRecognizer.delegate;
//复原的时候也要注意是否是根控制器,不是根控制器不需要还原(点—>—>—>)
??-(UIViewController *)popViewControllerAnimated :(BOOL)animated{
//popView之后判断这个count 是1 那就是只剩下一个根控制器了;
if(self.viewControllers.count ==1 ){
self.interactivePopGestureRecognizer.delegate = self.popDelegate;//复原
}
//在这里写有一个BUG滑一半的时候,马上就还原了,——>又没有了滑动功能
[super …];
}
那要等这个pop动画完全还原的时候,再去还原—>监听这个动画什么时候完成
设置导航控制器的代理—>自己来监听
遵守代理:<UINavigationControllerDelegate>
代理的方法:
- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated{
//代理的这个方法不管是push,还是pop方法展示控制控制器,只要是完全展示完都会调用;
//viewController参数就是当前展示完的控制器;
if(viewController == [self.viewControllers firstObject]){//当前这个控制器是不是控制器数组里的第一个(根控制器)
self.interactivePopGestureRecognizer.delegate = self.popDelegate;//复原
}
}
如果展示的是根控制器,就还原pop手势代理;
push 是进入下一个控制器,栈顶压入控制器;pop是退回到上一个控制器取出了栈顶控制器
4.2深入了解系统的手势滑动功能(添加一个手势,实现手势对应的方法)
//系统的self.popDelegate = self.interactivePopGestureRecognizer.delegate;代理做个一个滑动功能,而且做了一系列的判断;(根控制器就不能滑动)
自定义返回滑动功能(添加手势,实现手势方法—>系统的基础上修改)
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:系统的target对象 action:@selector(系统的滑方法)];
怎么拿到系统的target对象???
??重点:
self.interactivePopGestureRecognizer//系统的一个滑动手势,系统也是使用Target(对象)实现了滑动功能action(方法)
/*
<UIScreenEdgePanGestureRecognizer: 0x10033e1b0; state = Possible; delaysTouchesBegan = YES; view = <UILayoutContainerView 0x100411740>; target= <(action=handleNavigationTransition:, target=<_UINavigationInteractiveTransition 0x10033d320>)>>
系统滑动手势类型:UIScreenEdgePanGestureRecognizer
target:_UINavigationInteractiveTransition
action:handleNavigationTransition:
*/
??// 防止手势冲突self.interactivePopGestureRecognizer.enabled = NO;
取出系统的target对象
取出某个对象的属性—>获取系统的私有属性;—->通过运行时遍历一个对象的属性;
1.KVC—>前提条件:必须知道属性名
??运行时框架:<objc/runtime.h>
遍历某个类里面的所有属性:
class_copyIvarList(__unsafe_unretained Class cls ,unsigned int *outCount);
这方法会返回一个成员属性的数组 Ivar *ivars = 指向数组第一个元素地址的
//Class 获取哪个类的成员属性(当前类,不包括父类)
//count:告诉你当前类里面成员属性的总数(传的是一个地址)&count
Ivar *ivars = class_copyIvarList([UIGestureRecognizer class],&count);
接下里遍历这个数组:
for(int i = 0; i < count; i ++){//遍历出所有属性名
Ivar ivar = ivars[i];//取出每一项刚刚遍历返回的数组
NSString *ivarName = @(ivar_getName(ivar)) //
ivar_getName();//获取属性名;
ivar_getTypeEncoding(Ivar v);//获取属性的类型;
ivar_getOffset(Ivar v);//偏移量吧;
//将C语言字符串转化成OC字符串; @()
NSLog(@“%@”,ivarName);//打印的是私有属性_targets
}
_targets:属性名 对应的属性值value———>KVC
??以上一推都是为了获得(知道)这个_targets这个属性名
知道了这个属性名之后呢,可以通过KVC获得某对象的_targets属性值
NSArray targets = [self.interactivePopGestureRecognizer valueForKeyPath:@“_targets”];
self.interactivePopGestureRecognizer是一个手势对象,拥有UIGestureRecognizer对象的属性;
NSArray targets 是一个数组:(action = handleNavigationTransition; target = <UINavigationInteractiveTransition>)
取出数组里的元素看看是啥
id objc = [targets firstObject];//取出数组的第一个元素,是一个对象;
用断点看看objc有什么属性:_target,_action;
取出target对象:id target = [objc valueForKeyPath:@“_target”];
结果:自己创建的手势调用系统target对象,实现系统的handleNavigationTransition:方法;
自己写的有个BUG,系统的有个delegeate做了一些事情,当是根控制的时候,这手势会造成各种事件失灵;
所以,自己充当代理,实现代理的一个方法:当是根控制器的时候,手势不可用:
-(BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{
//当前控制器就是栈顶控制器;
return (self.topViewController != [self.viewControllers firstObject]);
}
一种简单的方式获得target:
self.interactivePopGestureRecognizer.delegate就是上面获得target对象;
——————自定义滑动功能完—————————
4.3搭建设置的table页面(MVC思想去管理这个TableViewController)
每一个cell要展示的内容不同 ——>XMGSettingItem : NSObject
image ,title, subtitle
+(instancetype)itemWithImage:(UIImage *)image title:(NSString *)title
{
XMGSettingItem *item =[ [self alloc] init];
item.image = image;
item.title = title;
return item;
}
XMGSettingGroup模型
items,headTitle,footTitle;
+(instancetype) groupWithItems:(NSArray *items){
XMGSettingGroup *group = [[self alloc] init];
group.items = items;
return group;
}
组模型中有个数组的成员属性是用来存放每个cell内容的的items模型;
细化cell—>item模型,对于带尖头的(要跳转),switch(是YES是NO):
给每一个 cell设置一个模型;模型分类:(剪头,switch)
搞个继承XMGSettingItem的模型XMGArrowSettingItem,XMGSwitchSettingItem
XMGArrowSettingItem,创建模型的时候,剪头就用这个
XMGSwitchSettingItem:创建模型的时候Switch就用这个
@property(nonatomic, assign) BOOL isOn;
设置cell内容的时候判断是哪种模型 [item isKindOfClass : [XMGArrowSettingItem class]];
cell模型既然有多种,又要重复利用—>cell复原操作;
cell封装: XMGSettingCell
@class XMGSettingItem;
+(instancetype)cellWithTableView:(UITableView *)tableView;
@property (nonatomic, strong) XMGSettingItem *item;//把这个模型传进来好给cell赋值;
@property (nonatomic ,strong) UIImageView *arrowView;//不能和系统的重名
@property (nonatomic ,strong) UISwitch *switchView;
-(UIImageView *)arrowView{//懒加载
if(_arrowView == nil){
_arrowView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@“”]];
}
return _arrowView;
}
-(UISwitch *)switchView{//懒加载
if(_switchView ==nil){
_switchView = [[UISwitch alloc] init];
}
return _switchView;
}
+(instancetype)cellWithTableView:(UITableView *)tableView{
static NSString *ID = @“cell”;
XMGSettingCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
if(cell == nil){
cell = [[XMGSettingCell alloc] initWithStyle : UITableViewCellStyleValue1 reuseIdentifier:ID];
}
return cell;
}
-(void)setItem:(XMGSettingItem *)item
{
_item = item;
[self setUpData];
[self setUpAccessoryView];
}
//给cell设置数据
-(void)setUpData{
self.textLabel.text = _item.title;
self.detailTextLabel.text = _item.subTitle;
self.imageView.image = _item.image;
}
//给cell设置辅助视图
-(void)setUpAccessoryView{
if([_item isKindOfClass:[XMGArrowSettingItem class]]){
self.accessoryView = self.arrowView;
self.selectionStyle = UITableViewCellSelectionStyleDefault;
}else if([_item isKindOfClass:[XMGSwitchSettingItem class]]){
self.accessoryView = self.switch;
//switch不要行选中样式;
self.selectionStyle = UITableViewCellSelectionStyleNone;
}else{
self.selectionStyle = UITableViewCellSelectionStyleDefault;//还原
self.accessoryView = nil;//还原;
}
}
4.4 App版本检测— >用到了服务请求—>高斯模糊地图提示功能
高斯模糊的实现原理:截屏—>生成图片—>对图片进行处理(第三方框架DRNRealTimeBlurView)
用第三方框架:封装起来用(搞自己的一个view继承这个框架)
XMGBlurView :DRNRealTimeBlurView
//DRNRealTimeBlurView他会把父控件截屏,做高斯模糊效果;
当cell点击的时候-(void)tableView: didSelectRowAtIndexPath:{
//判断组判断行;
XMGBlurView *blurView = [XMGBlurView alloc] initWithFrame:XMGScreenBounds];
[XMGKeyWindow addSubview : blurView];
[MBProgressHUD showSuccess:@“”];
dispatch_after(dispatch_time),dispatch_get_main_queue(),^{
[blurView removeformSuperView];
}
//点击事件,功能写在这里很恶心??,而且每一个cell都有自己的功能且还可以保存到模型中,最好写在block
}
??在模型中定义block,保存代码快:void没有返回值,^block标志,itemOperation是block变量名,后面的()是有米有参数;
给cell模型(父类)添加属性:@property (nonatomic , strong) void(^ itemOperation )();
取消按钮的选中:[tableView deselectRowAtIndexPath : indexPath animated : YES];
itemOperation = ^{
//block代码写在这快
}
点击cell跳转,在block中添加代码,所有的剪头cell都要跳转就会写很多重复的代码—>不好
来到跳转的模型XMGArrowSettingItem,添加descVc属性外界只要告诉要转转的控制器就可以了,XMGArrowSettingItem帮你跳descVc;
//保存一个需要跳转的控制器
@property (nonatomic, weak) Class descVc; //用Class有提示,以免类名写错,Class不是对象,不用带*
if(item.itemOperation){
item.itemOperation();
return;//如果有block的话,就会有跳转操作;如果没有block,那么接着往下判断有米有传个类名进来,进行跳转;
}
if( [item isKindOfClass : [XMGArrowSettingItem class]] ){//判断下是不是掉转的类,在判断有米有传destVc;
if(arrowItem.destVc){
UIViewController *vc = [UIViewController alloc] ]init];
[self.navigationController pushViewController :vc animated:YES];
}
}
补充:cell选中与否-(void)setUpAccessoryView{
//在这个方法中设置要不要选中功能;还记得得还原;
}
4.5点击推送———>跳转到和tableView很像的界面;