zoukankan      html  css  js  c++  java
  • iOS_12_tableViewCell的删除更新_红楼梦

    终于效果图:



    Girl.h

    //
    //  Girl.h
    //  12_tableView的增删改
    //
    //  Created by beyond on 14-7-27.
    //  Copyright (c) 2014年 com.beyond. All rights reserved.
    //
    
    #import <Foundation/Foundation.h>
    
    @interface Girl : NSObject
    // UI控件用weak,字符串用copy,其它对象用strong
    // 头像图片名
    @property(nonatomic,copy)NSString *headImgName;
    // 姓名
    @property(nonatomic,copy)NSString *name;
    // 判词
    @property(nonatomic,copy)NSString *verdict;
    // 提供一个类方法,即构造函数,返回封装好数据的对象(返回id亦可)
    + (Girl *)girlNamed:(NSString *)name headImgName:(NSString*)headImgName verdict:(NSString *)verdict;
    
    // 类方法,字典 转 对象 相似javaBean一次性填充
    + (Girl *)girlWithDict:(NSDictionary *)dict;
    
    // 对象方法,设置对象的属性后,返回对象
    - (Girl *)initWithDict:(NSDictionary *)dict;
    @end
    




    Girl.m

    //
    //  Girl.m
    //  12_tableView的增删改
    //
    //  Created by beyond on 14-7-27.
    //  Copyright (c) 2014年 com.beyond. All rights reserved.
    //
    
    #import "Girl.h"
    
    @implementation Girl
    // 提供一个类方法,即构造函数,返回封装好数据的对象(返回id亦可)
    +(Girl *)girlNamed:(NSString *)name headImgName:(NSString *)headImgName verdict:(NSString *)verdict
    {
        Girl *girl = [[Girl alloc]init];
        girl.name = name;
        girl.headImgName = headImgName;
        girl.verdict = verdict;
        return girl;
    }
    
    // 类方法,字典 转 对象 相似javaBean一次性填充
    + (Girl *)girlWithDict:(NSDictionary *)dict
    {
        // 仅仅是调用对象的initWithDict方法,之所以用self是为了对子类进行兼容
        return [[self alloc]initWithDict:dict];
    }
    
    // 对象方法,设置对象的属性后,返回对象
    - (Girl *)initWithDict:(NSDictionary *)dict
    {
        // 先调用父类NSObject的init方法
        if (self = [super init]) {
            // 设置对象自己的属性
            self.name = dict[@"name"]   ;
            self.headImgName = dict[@"headImg"] ;
            self.verdict = dict[@"verdict"];
        }
        // 返回填充好的对象
        return self;
    }
    @end
    




    BeyondViewController.h

    //
    //  BeyondViewController.h
    //  12_tableView的增删改
    //
    //  Created by beyond on 14-7-27.
    //  Copyright (c) 2014年 com.beyond. All rights reserved.
    //
    
    #import <UIKit/UIKit.h>
    
    @interface BeyondViewController : UIViewController
    
    
    
    // 标题
    @property (weak, nonatomic) IBOutlet UILabel *titleStatus;
    // tableView
    @property (weak, nonatomic) IBOutlet UITableView *tableView;
    // 清空button
    @property (weak, nonatomic) IBOutlet UIBarButtonItem *trashBtn;
    // 全选 反选button
    @property (weak, nonatomic) IBOutlet UIBarButtonItem *checkAllBtn;
    
    // 清空
    - (IBAction)trashBtnClick:(UIBarButtonItem *)sender;
    // 全选 or 反选
    - (IBAction)checkAll:(UIBarButtonItem *)sender;
    @end
    




    BeyondViewController.m

    //
    //  BeyondViewController.m
    //  12_tableView的增删改
    //
    //  Created by beyond on 14-7-27.
    //  Copyright (c) 2014年 com.beyond. All rights reserved.
    //
    
    #import "BeyondViewController.h"
    #import "Girl.h"
    @interface BeyondViewController ()<UITableViewDataSource,UITableViewDelegate>
    {
        // 从plist文件里载入的全部girls,返回字典数组
        NSArray *_arrayWithDict;
        // 全部的对象数组
        NSMutableArray *_girls;
        
        // 被勾选的行的相应该的模型数组
        // 不用数组也行,仅仅要在模型中添加一个属性:记录是否被选中
        NSMutableArray *_checkedGirls;
    }
    @end
    
    @implementation BeyondViewController
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
        // 全部的对象数组
        _girls = [NSMutableArray array];
        // 被勾选的行的数组
        _checkedGirls = [NSMutableArray array];
        // 调用自己定义方法,载入plist文件
        [self loadPlist];
        
    	
    }
    // 自己定义方法,载入plist文件
    - (void)loadPlist
    {
        // sg_bundle模板代码,1,获得.app基本的包;2,返回基本的包中某个文件的fullPath全路径
        NSBundle *mainBundle = [NSBundle mainBundle];
        NSString *fullPath = [mainBundle pathForResource:@"girls.plist" ofType:nil];
        
        // 从plist文件里依据全路径,返回字典数组
        _arrayWithDict = [NSArray arrayWithContentsOfFile:fullPath];
        
        // 再调用自己定义方法,将字典数组,转换成对象数组
        [self dictArrayToModel];
        
    }
    
    // 自己定义方法,将字典数组,转换成对象数组
    - (void)dictArrayToModel
    {
        // 字典数组 _arrayWithDict
        // 方式1:for in,这样的情况下,控制器知道的东西太多了,假设模型添加属性,还要改控制器中的代码
        /*
         for (NSDictionary *dict in _arrayWithDict) {
         
         Girl *girl = [Girl girlNamed:dict[@"name"] headImgName:dict[@"headImg"] verdict:dict[@"verdict"]];
         [_girls addObject:girl];
         }
         */
        
        
        // 方式2:类方法返回对象,參数仅仅要一个字典数组就可以
        for (NSDictionary *dict in _arrayWithDict) {
            // 參数仅仅要字典,这样一来,控制器就不用知道太多东西了
            // Girl *girl = [[Girl alloc]initWithDict:dict];
            Girl *girl = [Girl girlWithDict:dict];
            
            [_girls addObject:girl];
        }
    }
    
    // 数据源方法,默认是单组,共同拥有多少行 (每次刷新数据都会调用此行)
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    {
        
        
        
        // 返回数组中相应的字典的长度
        return _girls.count;
    }
    // 数据源方法,每一组的每一行应该显示怎么的界面(含封装的数据),重点!!!必须实现否则,Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'UITableView dataSource must return a cell from tableView:cellForRowAtIndexPath:'
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        
    
        
        
        
        static NSString *cellID = @"Beyond";
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
        if (cell == nil) {
            // 假设池中没取到,则又一次生成一个cell
            /*
             cell的4种样式:
             1,default   左图右文字
             2,subtitle  左图  上文字大    下文字小
             3,value 1   左图  左文字大    右文字小
             3,value 2   恶心  左文字小    右文字大
             */
            cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellID];
        }
        // 设置cell中独一无二的内容
        Girl *girl = _girls[indexPath.row];
        cell.textLabel.text = girl.name;
        cell.imageView.image = [UIImage imageNamed:girl.headImgName];
        cell.detailTextLabel.text = girl.verdict;
        // 推断,假设模型存在于checkedArray中,则标记为checked
        if ([_checkedGirls containsObject:girl]) {
            cell.accessoryType = UITableViewCellAccessoryCheckmark;
        } else {
            cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
        }
        // 返回cell
        return cell;
    }
    
    // 代理方法,每一行的高度
    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        return 83;
    }
    
    // 代理方法,点击行,新版本号 MVC
    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
    {
        // 取消tableView点击后背景高亮的蓝色
        [tableView deselectRowAtIndexPath:indexPath animated:YES];
        
        // 获得被点击的行的相应的数据模型
        Girl *girl = [_girls objectAtIndex:indexPath.row];
        
        // 推断,若没被勾选过,则勾选,否则取消勾选
        // 方式2:仅仅改动模型,不动cell,让tableView reload数据就可以,符合MVC~
        if ([_checkedGirls containsObject:girl]) {
            // 取消勾选,从勾选数组中移除,然后再次reloadData
            [_checkedGirls removeObject:girl];
        } else {
            // 加入到选中数组中,然后再次reloadData!
            [_checkedGirls addObject:girl];
        }
        
        // 再次reloadData
        [_tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
        
        
        // 最后调用自己定义方法,检查trashbutton的可用性,以及标题的变化
        [self statusCheck];
        
        
    
    }
    // 代理方法,点击行----旧版本号
    - (void)oldVersionTableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
    {
        // 取消tableView点击后背景高亮的蓝色
        [tableView deselectRowAtIndexPath:indexPath animated:YES];
        
        // 获得被点击的行
        UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
        // 获得被点击的行的相应的数据模型
        Girl *girl = [_girls objectAtIndex:indexPath.row];
        
        
        // 推断,若没被勾选过,则勾选,否则取消勾选
        // 方式1:手动设置cell的样式,可是,这不符合MVC思想~
        /*
         if (cell.accessoryType != UITableViewCellAccessoryCheckmark) {
         // 勾选上,同一时候要加入到数组中,记住!
         cell.accessoryType = UITableViewCellAccessoryCheckmark;
         
         [_checkedGirls addObject:girl];
         
         } else {
         // 取消勾选,同一时候要移除
         cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
         [_checkedGirls removeObject:girl];
         }
         */
        
        // 方式2:仅仅改动模型,不动cell,让tableView reload数据就可以,符合MVC~
        if (cell.accessoryType != UITableViewCellAccessoryCheckmark) {
            // 加入到选中数组中,然后再次reloadData!
            [_checkedGirls addObject:girl];
            [_tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
        } else {
            // 取消勾选,从勾选数组中移除,然后再次reloadData
            [_checkedGirls removeObject:girl];
            [_tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
        }
        
        
        
        // 最后调用自己定义方法,检查trashbutton的可用性,以及标题的变化
        [self statusCheck];
    }
    
    
    
    // 当点击了toolBar中的trash button时调用
    - (IBAction)trashBtnClick:(UIBarButtonItem *)sender {
       
        
        
        
        
        // 可变数组,成员是全部的勾选的行组成的indexPath
        NSMutableArray *indexPaths = [NSMutableArray array];
        // 遍历checkedGirls,得到勾选的行号们,并封装成一个个indexPath,然后加入到indexPaths数组,目的是后面tableView删除行方法中用到
        for (Girl *girl in _checkedGirls) {
            // 勾选的行的行号
            int row = [_girls indexOfObject:girl];
            // 封装成IndexPath
            NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:0];
            // 加入到IndexPaths数组
            [indexPaths addObject:indexPath];
        }
        
        
        
        // 先改动模型(从全部的对象数组中删除 勾选的对象们,而且清空勾选的对象数组),最后再deleteRowsAtIndexPaths(注意reload前提是数据源个数不能添加或降低)
        [_girls removeObjectsInArray:_checkedGirls];
        [_checkedGirls removeAllObjects];
        // deleteRows删除行之后,剩余的行数,必须与数据源的行数相等,意思就是:数据源中也要删除相同多的行的数据,才干够调用deleteRows方法
        [_tableView deleteRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationRight];
        
        // 最后调用自己定义方法,检查trashbutton的可用性,以及标题的变化
        [self statusCheck];
    }
    
    // 最后调用自己定义方法,检查trashbutton的可用性,以及标题的变化
    - (void)statusCheck
    {
        
        // 假设表格没有数据了,则直接禁用掉全选button
        if (_girls.count == 0) {
            _checkAllBtn.enabled = NO;
        }
        
        
        
        
        // 设置显示checked的行数
        if (_checkedGirls.count != 0) {
            // 假设没有被选中的行,则禁用 删除button
            _trashBtn.enabled = YES;
            // 显示数字(默认bar button item中的文本是不可更改的,所以改成label标签)
            NSString *titleStatus = [NSString stringWithFormat:@"红楼梦(%d)",_checkedGirls.count];
            _titleStatus.text = titleStatus;
        } else {
            _trashBtn.enabled = NO;
            _titleStatus.text = @"红楼梦";
        }
    }
    
    // toolBar最右边的 全选 or 反选button
    - (IBAction)checkAll:(UIBarButtonItem *)sender {
        
        
        if (_girls.count == _checkedGirls.count) {
            // 取消全选   先改动模型,再reload
            [_checkedGirls removeAllObjects];
            [_tableView reloadData];
        } else {
            // 全选   先改动模型,再reload
            // 必须先清空checked数组,再全部加入
            [_checkedGirls removeAllObjects];
            [_checkedGirls addObjectsFromArray:_girls];
            [_tableView reloadData];
        }
        
        // 调用自己定义方法 改动检測状态
        [self statusCheck];
        
        
        
    }
    @end
    





    属性列表文件girls.plist





    main.storyboard 

    由于bar button item的文字不可更改, 遂换成label,

    label不接收点击事件,所以能够向后传递给button处理点击事件






  • 相关阅读:
    设计模式的征途—12.享元(Flyweight)模式
    设计模式的征途—11.外观(Facade)模式
    UML类图10分钟快速入门
    设计模式的征途—10.装饰(Decorator)模式
    设计模式的征途—9.组合(Composite)模式
    设计模式的征途—8.桥接(Bridge)模式
    我的2017OKR
    设计模式的征途—7.适配器(Adapter)模式
    《白夜行》读后感:白夜行走,暗中羁绊
    设计模式的征途—6.建造者(Builder)模式
  • 原文地址:https://www.cnblogs.com/llguanli/p/6848561.html
Copyright © 2011-2022 走看看