美文网首页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