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調用對象方法

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM