ios开发级联菜单(利用父子控制器--两个菜单封装为两个子控制器来实现)

一:1:级联菜单可以使用两个tableView来实现,也可以利用父子控制器,两个控制器来实现,根视图控制器作为两个控制器的父控制器,来管理两个子控制器。2:将左右菜单分别交给两个控制器去管理,对于一些复杂的业务逻辑,涉及大量回调操作,业务逻辑也要相对复杂,则不建议采取封装成view去处理,最好还是利用一个控制器去管理其内部复杂的业务逻辑,具体做法就是:利用父子控制器,将子控制器交由父控制器去管理,将子控制器的view添加到父控制器的view上。效果如图:

二:代码

1:根控制器代码:添加两个子控制器到,并将子view添加到根视图控制器的view上

 1 #import "ViewController.h"
 2 #import "RHCategoryViewController.h"
 3 #import "RHSubCategoryViewController.h"
 4 @interface ViewController ()
 5
 6 @end
 7
 8 @implementation ViewController
 9
10 - (void)viewDidLoad {
11     [super viewDidLoad];
12
13
14     CGFloat width = self.view.frame.size.width *0.5;
15     CGFloat height = self.view.frame.size.height;
16     //右侧菜单
17     RHSubCategoryViewController *sub = [[RHSubCategoryViewController alloc]init];
18     sub.view.frame = CGRectMake(width, 0, width, height);
19     [self addChildViewController:sub];
20     [self.view addSubview:sub.view];
21
22     //左侧菜单
23     RHCategoryViewController *category = [[RHCategoryViewController alloc]init];
24     category.view.frame = CGRectMake(0, 0, width, height);
25     category.delegate = sub;
26     [self.view addSubview:category.view];
27     [self addChildViewController:category];
28
29
30
31
32 }
33
34
35 @end

2:左侧菜单控制器

 1 //左侧菜单:
 2
 3 #import <UIKit/UIKit.h>
 4 @class RHCategoryViewController;
 5 @protocol RHCategoryViewControllerDelegate <NSObject>
 6
 7 @optional
 8
 9 - (void)categoryViewController:(RHCategoryViewController*)controller didSelectRowWithData:(NSArray*)dataArr;
10
11 @end
12
13 @interface RHCategoryViewController : UITableViewController
14
15 @property (nonatomic,weak)id <RHCategoryViewControllerDelegate>delegate;
16
17 @end
  1 #import "RHCategoryViewController.h"
  2 #import "RHCategoryModel.h"
  3 static NSString *const cellID = @"cellID";
  4 @interface RHCategoryViewController ()
  5 /*数据源*/
  6 @property (nonatomic ,strong)NSMutableArray *dataArr;;
  7
  8 @end
  9
 10 @implementation RHCategoryViewController
 11
 12 - (NSMutableArray*)dataArr {
 13
 14     if (!_dataArr) {
 15         NSString *filePath = [[NSBundle mainBundle]pathForResource:@"categories" ofType:@"plist"];
 16         NSArray *data = [NSArray arrayWithContentsOfFile:filePath];
 17         NSMutableArray *dataArray = [NSMutableArray array];
 18         for (NSDictionary *dic in data) {
 19             RHCategoryModel *model = [RHCategoryModel categoryModelWithDic:dic];
 20             [dataArray addObject:model];
 21         }
 22         /*
 23          1:此时的数组可以自己初始化,或是将其他的数组赋值给没初始化的数组 2:在懒加载还可以调用set方法为数组赋值,也就是,self.dataArr = dataArray;
 24          */
 25         _dataArr = dataArray;
 26     }
 27
 28     return _dataArr;
 29 }
 30
 31 - (void)viewDidLoad {
 32     [super viewDidLoad];
 33     //1:注册表格
 34     [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:cellID];
 35
 36     /*
 37      注: 1:写在viewDidLoad此处不会默认选中第一行,应该在viewWillAppear:(BOOL)animated,或是viewDidAppear:(BOOL)animated方法中设置默认选中第一行时,才会选中
 38          2:控制器的view是懒加载的,当在根控制器中设置view的frame时,vc.view.frame,vc.view调用的是vc中view的get方法,此时会加载view,执行viewDidload方法,加载view,但是此时view的UI,tableView还没有加载,先调用viewWillAppear:(BOOL)animated,在调用数据源代理方法,在调用viewDidAppear:(BOOL)animated
 39      //2:默认第0行被选中
 40      //     [self.tableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] animated:NO scrollPosition:UITableViewScrollPositionTop];
 41      */
 42
 43 }
 44
 45 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
 46
 47     return self.dataArr.count;
 48 }
 49
 50 - (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
 51     /*
 52      1:当cell被选中的时候,cell上的子控件都会显示高亮行为,所以可以设置cell上子控件高亮时的状态,来显示cell被选中时的状态。 cell.textLabel.highlightedTextColor,cell.imageView.highlightedImage
 53      */
 54     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
 55     RHCategoryModel *model = self.dataArr[indexPath.row];
 56     cell.textLabel.text = model.name;
 57     cell.textLabel.highlightedTextColor = [UIColor orangeColor];
 58     cell.imageView.image = [UIImage imageNamed:model.icon];
 59     cell.imageView.highlightedImage = [UIImage imageNamed:model.highlighted_icon];
 60     cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
 61     return cell;
 62 }
 63
 64 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
 65
 66     if (self.delegate && [self.delegate respondsToSelector:@selector(categoryViewController:didSelectRowWithData:)]) {
 67         RHCategoryModel *model = self.dataArr[indexPath.row];
 68         [self.delegate categoryViewController:self didSelectRowWithData:model.subcategories];
 69
 70     }
 71 }
 72
 73 - (void)setDelegate:(id<RHCategoryViewControllerDelegate>)delegate {
 74
 75     _delegate = delegate;
 76     /*
 77      1:默认表格的某一行被选中,不会调用didSelectRowAtIndexPath方法,只是设置cell的选中的一个状态
 78      2:获得tableView选中的某一行的indexpath:self.tableView.indexPathForSelectedRow
 79      */
 80     [self tableView:self.tableView didSelectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
 81
 82 }
 83
 84 /*
 85  1:两方法分别是:视图即将出现的时候调用,视图已经出现的时候调用
 86  2:当某个控制器被压入栈里,或是被moda的控制器遮住的时候,返回到此控制器,则两个方法依然会被调用
 87  */
 88 - (void)viewWillAppear:(BOOL)animated {
 89
 90     [super viewWillAppear:animated];
 91 //     [self.tableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] animated:NO scrollPosition:UITableViewScrollPositionTop];
 92 }
 93
 94 - (void)viewDidAppear:(BOOL)animated {
 95
 96     [super viewDidAppear:animated];
 97
 98     [self.tableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] animated:NO scrollPosition:UITableViewScrollPositionTop];
 99
100 }
101 @end

3:右侧菜单控制器

1 #import <UIKit/UIKit.h>
2 #import "RHCategoryViewController.h"
3 @interface RHSubCategoryViewController : UITableViewController<RHCategoryViewControllerDelegate>
4
5 @end
 1 #import "RHSubCategoryViewController.h"
 2 #import "RHCategoryViewController.h"
 3 static NSString *const cellID = @"cellID";
 4 @interface RHSubCategoryViewController ()
 5 /*数据源*/
 6 @property (nonatomic ,strong)NSArray *dataArr;
 7 @end
 8
 9 @implementation RHSubCategoryViewController
10
11 - (void)viewDidLoad {
12     [super viewDidLoad];
13     [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:cellID];
14 }
15
16 - (void)categoryViewController:(RHCategoryViewController *)controller didSelectRowWithData:(NSArray *)dataArr {
17
18     self.dataArr = dataArr;
19     [self.tableView reloadData];
20 }
21
22 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
23
24     return self.dataArr.count;
25 }
26
27 - (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
28
29     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
30     cell.textLabel.text = self.dataArr[indexPath.row];
31     return cell;
32 }
33
34
35 @end

5:数据模型model

 1 #import <Foundation/Foundation.h>
 2
 3 @interface RHCategoryModel : NSObject
 4 /*高亮图片*/
 5 @property (nonatomic,copy)NSString *highlighted_icon;
 6 /*icon*/
 7 @property (nonatomic,copy)NSString *icon;
 8 /*名字*/
 9 @property (nonatomic,copy)NSString *name;
10 /*分类数组*/
11 @property (nonatomic ,strong)NSArray *subcategories;
12
13 +(instancetype)categoryModelWithDic:(NSDictionary*)dic;
14 @end
 1 #import "RHCategoryModel.h"
 2
 3 @implementation RHCategoryModel
 4
 5 +(instancetype)categoryModelWithDic:(NSDictionary*)dic {
 6
 7     RHCategoryModel *model = [[self alloc]init];
 8     [model setValuesForKeysWithDictionary:dic];
 9     return model;
10 }
11 @end

三:知识点总结

1:从plist中读取数据:1:先加载plist的路径: NSString *filePath = [[NSBundle mainBundle]pathForResource:@"categories" ofType:@"plist"]; 2:在查看pilist文件中根节点是数组还是字典,从而将plist数据读出: NSArray *data = [NSArray arrayWithContentsOfFile:filePath];

2:懒加载:属性修饰必须用strong,若用weak则刚创建完对象就会被销毁。在懒加载中,懒加载数组或是其他变量时,1:若没初始化,可以将一个已经初始化的变量直接赋值 2:若已经初始化,则可以返回 3:只要是属性定义的变量,就会生成下划线的变量,set方法,get方法,所以在懒加载时,除了可以用带下划线的成员变量,也可以用self.data = dataArray;左侧调用的是set方法,右侧调用的是get方法 4:若是系统或是自定的属性,调用完set方法赋值后,若想在其他方法中获得所赋的值,则可直接调用其get方法,例如titleLable.font,从父控制器数组中取出子控制器,直接调用title的get方法,直接获得title,不用再讲title放在数组中再去赋值。5:若外部向获得在.m中声明的成员属性,则该变量可以再.h中提供自身的get方法供外部调用

3:1:[self.tableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] animated:NO scrollPosition:UITableViewScrollPositionTop];tableView的默认选中某一行 1:默认表格的某一行被选中,不会调用didSelectRowAtIndexPath方法,只是设置cell的选中的一个状态  2:获得tableView选中的某一行的indexpath:self.tableView.indexPathForSelectedRow 2:1:写在viewDidLoad此处不会默认选中第一行,应该在viewWillAppear:(BOOL)animated,或是viewDidAppear:(BOOL)animated方法中设置默认选中第一行时,才会选中 2:控制器的view是懒加载的,当在根控制器中设置view的frame时,vc.view.frame,vc.view调用的是vc中view的get方法,此时会加载view,执行viewDidload方法,加载view完毕,但是此时view的UI视图并没有去加载,tableView还没有加载,先调用viewWillAppear:(BOOL)animated,在去绘制视图UI,完毕后在调用viewDidAppear:(BOOL)animated。3:只有当整个表格绘制完毕或是即将绘制时,设置selectRowAtIndexPath才会起作用

4:当cell被选中的时候,cell上的子控件都会显示高亮行为,所以可以设置cell上子控件高亮时的状态,来显示cell被选中时的状态。 cell.textLabel.highlightedTextColor,cell.imageView.highlightedImage

5:重写setDelegate方法:因为在viewDidload里如果调用didselecrow方法,默认选中,则不会执行,是因为此时还没有设置代理,代理为空,self.delegate对象为空值,所以重写setDelegate方法,在设置代理成功后,再调用didselecrow,来设置默认选中

6:- (void)viewWillAppear:(BOOL)animated ,- (void)viewDidAppear:(BOOL)animated。 1:两方法分别是:视图即将出现的时候调用,视图已经出现的时候调用  2:当某个控制器被压入栈里,或是被moda的控制器遮住的时候,返回到此控制器,则两个方法依然会被调用

7: [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:cellID];self.tableView注册完cell后,就不用在其数据源方法中判断cell是否存在了,直接从缓存池中取出cell,就可以了

8:用类方法快速获得数据模型的对象:+(instancetype)categoryModelWithDic:(NSDictionary*)dic;在实现方法中,创建出对象后,利用对象调用kvc方法快速为属性赋值,并将模型对象返回。self在类方法中指的是当前类,在对象方法中指的是当前的对象,所以在类方法中不能用self调用对象方法

时间: 2024-10-08 17:36:09

ios开发级联菜单(利用父子控制器--两个菜单封装为两个子控制器来实现)的相关文章

iOS开发网络篇—文件下载(五&#183;下载功能的封装)

iOS开发网络篇—文件下载(五·下载功能的封装) 一.简单说明 在前面几篇文章介绍下载代码的基础上,此文分析对下载功能进行封装. 通过之前的代码,我们发现仅仅是下载一个文件就需要写很长的代码,那么如果要下载多个文件,就需要写多份代码.在这里,我们把下载一个文件的代码进行封装.控制器只需要知道,下载哪个文件,下载到哪个路径就可以了. 在对下载的功能进行封装后,添加一个文件下载器,一个文件下载器只下载一个文件,封装后如果要下载多个文件的话,那么只需要创建多个文件下载器对象就可以进行控制和下载了. 二

【iOS开发-26】利用协议代理实现导航控制器UINavigationController视图之间的正向传值和反向传值

实验说明 (1)正向传值:比如A类里地值要传给B类用,就是我们先在A类中声明一个B类对象(当然B类头文件要import过来),然后把A类中得某个值传递给B类中得某个值(所以需要在B类中先准备一个变量来接受,就是用@property和@synthesize整个变量即可). (2)反向传值:比如需要把B类中的值传递给A类用.我们先在B类中写一个协议,协议里面有一个可以带参数的方法,这个参数就是我们要传递的值(这个协议也可以单独写,不一定写在B类中),然后B类遵循这个协议后,利用这个协议创建一个委托变

【iOS开发-50】利用创建新的类实现代码封装,从而不知不觉实践一个简单的MVC实验

接上次案例谈代码封装.上次案例见:[iOS开发-48]九宫格布局案例:自动布局.字典转模型运用.id和instancetype区别.xib重复视图运用及与nib关系 代码封装的原则是:要保证视图控制器尽量少的接触到其他对象的属性,也就是说,尽量把数据或者属性封装到一个类里面,然后利用类或者对象的方法来调用或者设置数据.而是赤裸裸地把属性都写在视图控制器中.核心作用在于:减少视图控制器的代码量,把数据和属性的处理封装起来,这样也便于其他视图控制器的使用. 要做到的结果就是如下(我们要根据数组里面的

【iOS开发-79】利用Modal方式实现控制器之间的跳转

利用Modal方法.事实上就是以下两个方法的运用. Modal方式的切换效果是从底部呈现. -(void)clickModal{ WPViewController *wp=[[WPViewController alloc]init]; [self presentViewController:wp animated:YES completion:^{ }]; } -(void)clickDismiss{ [self dismissViewControllerAnimated:YES complet

iOS开发小技巧--利用MJExtension解决数据结构复杂的模型转换

一.开发中难免会遇到,系统返回的数据中字典套集合,集合里面又套一层字典,然后字典里面还有字典或者集合等等的复杂结构的数据...MJExtension轻松搞定这类问题 1.解决方法一: 例:百思项目中帖子数据有个模型,模型中还有一个最热评论的集合数据,集合数据要求是ChaosComment模型数据,然后ChaosComment模型中还有一个user字典(ChaosUser模型),如图: 解决方案:利用MJExtension,实现mj_objectClassInArray方法,告诉模型中的这个集合属

【iOS开发-46】利用UIButton和UIImageView的区别分辨哪些控件有addTarget监听事件这个方法

(1)UIButton和UIImageView的相同点 都能显示图片. (2)UIButton和UIImageView的不同点 --前者不仅能显示图片还能监听事件(就是有addtarget方法) --前者不仅能显示图片还能显示两张图片(就是setImage和setBackgroundImage两个方法) --前者不仅能显示图片还能显示文字(就是setTitle方法) (3)使用场合 --如果仅仅是显示一个图片没其他花头,那就用UIImageView --如果有其他,那么-- 因为如果仅仅用于显示

ios开发之手势动作状态细分state,同一视图添加两个手势

1.比如拖拽一个视图,形成类似scrollView的翻页形式 在拖拽的方法里判断拖拽的状态state属性,根据状态不同执行自己需要的效果. 2.同一视图添加两个手势,需要使用手势的代理方法.允许此操作.(可看手势演讲稿) 版权声明:本文为博主原创文章,未经博主允许不得转载.

iOS开发小技巧--利用运行时得到隐藏的成员变量

一.关于运行时,已经从网络上摘抄了一片文章,这里只有项目中自己的简单使用 -- 查找隐藏的成员变量 导入头文件 可以获得隐藏的成员变量,方法,属性等 代码: 打印效果图:

ios开发 Reflection(三) 利用反射自动绑值

反射的具体应用,自动绑值 获取属性列表 1 - (NSArray*)propertyKeys 2 { 3 unsigned int outCount, i; 4 objc_property_t *properties = class_copyPropertyList([self class], &outCount); 5 NSMutableArray *keys = [[NSMutableArray alloc] initWithCapacity:outCount]; 6 for (i = 0;