• 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调用对象方法

  • 相关阅读:
    androidstudio配置http proxy以及配置gradle
    发布jar到docker的方法
    idea直接发布项目到docker中
    安卓启动相机报错android.os.FileUriExposedException: file:///storage/emulated/0/
    centos 7.4搭建Harbor、push docker镜像以及常见错误
    dock的卸载与安装
    centos部署Kubernetes(k8s)集群
    Logback将日志输出到Kafka配置示例
    JavaScript设计模式 Item 5 --链式调用
    你不知道的JavaScript--Item27 异步编程异常解决方案
  • 原文地址:https://www.cnblogs.com/cqb-learner/p/5732561.html
Copyright © 2020-2023  润新知