美文网首页UI基础iOS自学之路学习封装
(四)iOS 实战项目开发:团购之下拉菜单的封装

(四)iOS 实战项目开发:团购之下拉菜单的封装

作者: 952625a28d0d | 来源:发表于2015-07-29 16:10 被阅读1431次
  • 搜索城市结果的选择

  • 封装下拉二级菜单的思路

  • 封装下拉二级菜单的实现

  • 完整的二级下拉菜单

  • 搜索城市结果的选择

  • 创建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控件

相关文章

网友评论

    本文标题:(四)iOS 实战项目开发:团购之下拉菜单的封装

    本文链接:https://www.haomeiwen.com/subject/dvmmqttx.html