(四)iOS 实战项目开发:团购之下拉菜单的封装
2015-07-29 本文已影响1431人
952625a28d0d
-
搜索城市结果的选择
-
封装下拉二级菜单的思路
-
封装下拉二级菜单的实现
-
完整的二级下拉菜单
-
搜索城市结果的选择
-
创建Cities模型并解析Plist文件返回数组
#import <Foundation/Foundation.h>
@interface Cities : NSObject
@property(nonatomic, copy) NSString * name;
@property(nonatomic, copy) NSString * pinYin;
@property(nonatomic, copy) NSString * pinYinHead;
@property(nonatomic, strong) NSArray * regions;
/**
* 获取所有城市
*
* @return 所有城市模型数组
*/
+ (NSArray *)getCities;
@end
- 通过SearchBar代理方法传递结果text给控制器
#pragma mark 在SearchBar 的检测SearchText内容发生改变的代理方法中给搜索结果控制器传入SearchText
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
if (searchText.length) {
NSLog(@"搜索结果控制器为%@", _searchCityResultVC);
self.searchCityResultVC.view.hidden = NO;
// 把改变了的文字传给search结果控制器
self.searchCityResultVC.searchText = searchText;
}else
{
self.searchCityResultVC.view.hidden = YES;
}
}
- set方法中赋值之后进行搜索操作
#pragma mark - cities set方法中赋值之后 进行搜索操作
- (void)setSearchText:(NSString *)searchText
{
_searchText = [searchText lowercaseString]; // 小写转换
// 获取到城市数组
if (!_citiesArray) {
_citiesArray = [Cities getCities];
}
_searchResultArray = [NSMutableArray array]; // 搜索结果数组
// 遍历和判断
for (Cities *city in _citiesArray) {
if ([city.name containsString:searchText] || [city.pinYin containsString:searchText] || [city.pinYinHead containsString:searchText]) {
[_searchResultArray addObject:city];
}
}
[self.tableView reloadData];
}
-
运行效果
Paste_Image.png -
封装下拉菜单的思路
-
封装的概念:
隐藏对象的属性和实现细节,仅对外开放接口,控制在程序中属性的读取和修改访问级别。 -
封装的意义:
增强安全性和简化编程,使用者不必了解具体的使用细节,而是只要通过外部的接口,以特定的访问权限来使用类的成员。 -
知识点:
-
协议的制定
-
UITableView 协议
-
逆向思维
-
封装的思想
以UITableView为例,分析一下下拉菜单的封装思想。 -
数据源
-
行数、列数都需要留给外界传入
-
封装下拉菜单的实现
-
协议的制定:
/**
* 协议
* 1:声明一个协议
* 2:声明协议中的方法
* 3:声明一个遵守协议的id类型的指针,它的作用是帮我们找到类的代理,让代理帮助我们完成想要做的事情,传值等等
* 4:实现我们声明好的协议方法
*/```
- 协议中方法的制定
```objc
#import <UIKit/UIKit.h>
@class popView;
@protocol MyPopViewDataSource <NSObject>
// 制定协议方法
// table View行数
- (NSInteger)NumberOfRowsInLeftTable:(popView *)popView;
// left 标题
- (NSString *)popView:(popView *)popView titleForRowAtIndexPath:(NSInteger)row;
// 图标
- (NSString *)popView:(popView *)popView imageForRowAtIndexPath:(NSInteger)row;
// 子数据
- (NSArray *)popView:(popView *)popView subDataForRowAtIndexPath:(NSInteger)row;
@end```
- 指针
```objc
@property (nonatomic, assign) id<MyPopViewDataSource>dataSource;```
- 实现协议方法
- 首先我们来声明一个属性用来记录当前选择的行
```objc
@property (nonatomic, assign) NSInteger selectRow; // 选择的row```
- 在tableView的代理方法中用代理属性调用协议方法赋值
```objc
#pragma mark - UITableView Delegate
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// 判断TableView
if (tableView == _leftTVC) {
return [self.dataSource NumberOfRowsInLeftTable:self];
}else
{
//返回选择模型子分类的数据
return [self.dataSource popView:self subDataForRowAtIndexPath:_selectRow].count;
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (tableView == _leftTVC) {
static NSString *cellIdentifier = @"meCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
cell.textLabel.text = [self.dataSource popView:self titleForRowAtIndexPath:indexPath.row];
cell.imageView.image = [UIImage imageNamed:[self.dataSource popView:self imageForRowAtIndexPath:indexPath.row]];
NSArray *subDataArray = [self.dataSource popView:self subDataForRowAtIndexPath:indexPath.row];
if (subDataArray.count) {
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}else
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}else
{
// 子数据
static NSString *cellIdentifier = @"meCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
cell.textLabel.text = [self.dataSource popView:self subDataForRowAtIndexPath:_selectRow][indexPath.row];
return cell;
}
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (tableView == _leftTVC) {
self.selectRow = indexPath.row; // 记录选中的行号
[_rightTVC reloadData];
}
}```
- 到这里基本完成了封装,到现在我们的视图完全符合MVC的设计模式,也就是我们封装的这个下拉菜单,完全跟数据不沾边,也就是说它们是完全独立的两个东西。
- 封装的完整的下拉菜单的使用
1. 引入
2. 遵守协议
3. 设置代理
4. 实现协议方法
```OBJC
#import "PopViewController.h"
#import "popView.h"
#import "CategoriyModel.h"
@interface PopViewController ()<MyPopViewDataSource>
{
NSArray *_categotyArray;
}
@end
@implementation PopViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 获取所有分类数据模型
_categotyArray = [self getData];
// Do any additional setup after loading the view.
popView *pop = [popView makePopView];
pop.dataSource = self;
[self.view addSubview:pop];
// 关掉自动缩放的属性
pop.autoresizingMask = UIViewAutoresizingNone;
// 设置控制器的尺寸和xib的尺寸一样
self.preferredContentSize = CGSizeMake(pop.frame.size.width, pop.frame.size.height);
}
#pragma mark - popView Deledate
- (NSInteger)NumberOfRowsInLeftTable:(popView *)popView
{
return _categotyArray.count;
}
- (NSString *)popView:(popView *)popView titleForRowAtIndexPath:(NSInteger)row
{
return [_categotyArray[row] name];
}
- (NSString *)popView:(popView *)popView imageForRowAtIndexPath:(NSInteger)row
{
return [_categotyArray[row] small_icon];
}
- (NSArray *)popView:(popView *)popView subDataForRowAtIndexPath:(NSInteger)row
{
return [_categotyArray[row] subcategories];
}
// 获取到第一个分类菜单的模型数组
- (NSArray *)getData{
CategoriyModel *md = [[CategoriyModel alloc] init];
NSArray *categorieyArray = [md loadPlistData];
NSLog(@"获取到的数据模型为%@", categorieyArray);
return categorieyArray;
}
- 总结
- 封装的思想
- 协议的使用
- 编写通用的UI控件