iOS_动态插入或删除行

终于效果图:
iOS_动态插入或删除行
分MVC三层设计;自己定义的Cell有两种;一种是MainCell,由ModelArr提供数据源;还有一种是插入的cell,由代码创建,而且由另外一个数组供状态数据
数据源部分:
iOS_动态插入或删除行

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcHJlX2VtaW5lbnQ=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

//
// MyProjectCellModel.h
// 动态插入删除行
//
// Created by beyond on 14-10-18.
// Copyright (c) 2014年 com.beyond All rights reserved.
// 列表 的cell用到的数据模型 #import <Foundation/Foundation.h> @interface MyProjectCellModel : NSObject // 图标
@property (nonatomic,copy) NSString *icon;
// 标题
@property (nonatomic,copy) NSString *title;
// 公布状态
@property (nonatomic,copy) NSString *publishStatus;
// 日期
@property (nonatomic,copy) NSString *date;
// 多少人关注
@property (nonatomic,copy) NSString *num; // 点击最右側的button,须要进行什么操作?? 弹出一个View,用于改动公布的状态??? // 类方法,字典 转 对象 相似javaBean一次性填充
+ (MyProjectCellModel *)modelWithDict:(NSDictionary *)dict; // 对象方法,设置对象的属性后,返回对象
- (MyProjectCellModel *)initWithDict:(NSDictionary *)dict; @end
<span style="color:#330033;">//
// MyProjectCellModel.m
// 动态插入删除行
//
// Created by beyond on 14-10-18.
// Copyright (c) 2014年 com.beyond All rights reserved.
// 列表 的cell用到的数据模型 #import "MyProjectCellModel.h" @implementation MyProjectCellModel
// 类方法,字典 转 对象 相似javaBean一次性填充
+ (MyProjectCellModel *)modelWithDict:(NSDictionary *)dict
{
// 仅仅是调用对象的initWithDict方法,之所以用self是为了对子类进行兼容
return [[self alloc]initWithDict:dict];
} // 对象方法,设置对象的属性后,返回对象
- (MyProjectCellModel *)initWithDict:(NSDictionary *)dict
{
// 必须先调用父类NSObject的init方法
if (self = [super init]) {
// 设置对象自己的属性
[self setValuesForKeysWithDictionary:dict];
}
// 返回填充好的对象
return self;
}
@end
</span>

主Cell,由xib和类声明、类实现组成
iOS_动态插入或删除行

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcHJlX2VtaW5lbnQ=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

//
// MyProjectCell.h
// 动态插入删除行
//
// Created by beyond on 14-10-18.
// Copyright (c) 2014年 com.beyond All rights reserved.
// 这个是基本的Cell,用于展示微博数据的Cell #import <UIKit/UIKit.h>
// 定义一个block,作用是点击了 右側的button,告诉主控制器弹出一个 View(包括暂停、改动、删除),block的參数是(int row)
typedef void(^cellRightBtnBlock)(int) ; @class MyProjectCellModel; @interface MyProjectCell : UITableViewCell // 图标
@property (nonatomic,weak)IBOutlet UIImageView *iconView;
// 标题
@property (nonatomic,weak)IBOutlet UILabel *titleLabel;
// 微博的公布状态【暂停、草稿、公布、过期】
@property (nonatomic,weak)IBOutlet UILabel *publishStatusLabel;
// 日期
@property (nonatomic,weak)IBOutlet UILabel *dateLabel;
// 多少人关注的数字 部分
@property (nonatomic,weak)IBOutlet UILabel *numLabel;
// 多少人关注的固定的文字,没有人关注此条微博时,就不显示
@property (nonatomic,weak)IBOutlet UILabel *constLabel; // 一个成员属性block,当cell右边的button被点击的时候,就会调用,弹出一个view,供用户改动微博的状态
@property (nonatomic,copy)cellRightBtnBlock wannaChangeStatusBlock; // 从xib中载入 实例化一个对象
+ (MyProjectCell *)myProjectCell; // 返回封装好数据之后的对象
- (MyProjectCell *)cellWithCellModel:(MyProjectCellModel *)cellModel;
@end

//
// MyProjectCell.m
// 动态插入删除行
//
// Created by beyond on 14-10-18.
// Copyright (c) 2014年 com.beyond All rights reserved.
// 这个是基本的Cell,用于展示微博数据的Cell #import "MyProjectCell.h"
#import "MyProjectCellModel.h"
@implementation MyProjectCell // 从xib中载入 实例化一个对象
+ (MyProjectCell *)myProjectCell
{
// mainBundel载入xib,扩展名不用写.xib
return [[NSBundle mainBundle] loadNibNamed:@"MyProjectCell" owner:nil options:nil][0];
} // 返回封装好数据之后的对象
- (MyProjectCell *)cellWithCellModel:(MyProjectCellModel *)cellModel
{ // 头像圆角
_iconView.layer.cornerRadius = 6;
_iconView.layer.masksToBounds = YES; _iconView.image = [UIImage imageNamed:cellModel.icon];
_titleLabel.text = cellModel.title;
_publishStatusLabel.text = cellModel.publishStatus;
_dateLabel.text = cellModel.date;
if ([_numLabel.text intValue]) {
_constLabel.hidden = YES;
} else {
_numLabel.text = cellModel.num;
_constLabel.hidden = NO;
}
// 生成一个右側button,加入到cell最右方
UIButton *rightBtn = [UIButton buttonWithType:UIButtonTypeCustom];
[rightBtn setBackgroundImage:[UIImage imageNamed:@"MyProjectCellRightBtn"] forState:UIControlStateNormal];
rightBtn.frame = CGRectMake(286, 0, 34, 44);
[self.contentView addSubview:rightBtn];
rightBtn.tag = 5267;
[rightBtn setBackgroundImage:[UIImage imageNamed:@"MyProjectCellRightBtn.png"] forState:UIControlStateNormal];
[rightBtn addTarget:self action:@selector(rightBtnClicked:) forControlEvents:UIControlEventTouchUpInside];
return self;
} // 定义宏,推断ios7
#define iOS7 [[[UIDevice currentDevice]systemVersion] floatValue] >= 7.0
- (void)rightBtnClicked:(UIButton *)sender
{
int row = 0;
MyProjectCell *cell;
UITableView *tableView;
if(iOS7){
NSLog(@"button的父类2:%@",[[[sender superview] superview] superview]);
cell = (MyProjectCell *)[[[sender superview] superview] superview]; NSLog(@"cell的父类2:%@",[[cell superview] superview] ); tableView = ( UITableView*)[[cell superview] superview] ;
}else{
// iOS6
cell = (MyProjectCell *)[sender superview];
NSLog(@"被点击的cell:%@",cell);
tableView = ( UITableView*)[cell superview];
}
NSIndexPath *path = [tableView indexPathForCell:cell];
row = path.row;
NSLog(@"父类1%@",[sender superview]);
NSLog(@"父类2%@",[[sender superview] superview]);
NSLog(@"父类3%@",[[[sender superview] superview]superview]);
NSLog(@"父类4%@",[[[[sender superview] superview]superview]superview]); NSLog(@"点击了第%d行 右边的button",row);
// 调用外界的控制器的block,并将cell的行号传递过去
_wannaChangeStatusBlock(row);
} @end

附加的Cell,即当点击MainCell最右側的button时,动态加入在主Cell下方
//
// ChangeStatusCell.m
// 动态插入删除行
//
// Created by beyond on 14-10-18.
// Copyright (c) 2014年 com.beyond All rights reserved.
// 附加的Cell,当点击MainCell最右側的按钮时,动态加入在主Cell下方 #import "ChangeStatusCell.h" @implementation ChangeStatusCell
// 附加的cell,没有xib,由代码创建
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// 加入三个按钮,并设置tag
UIButton *b1 = [self createButtonWithFrame:CGRectMake(0 , 0, 106.5, 44) Target:self Selector:@selector(btnAction:) Image:@"StatusPause_gray.png" ImagePressed:@"StatusPause_blue.png"];
b1.tag = 1; UIButton *b2 = [self createButtonWithFrame:CGRectMake(106.5, 0, 106.5, 44) Target:self Selector:@selector(btnAction:) Image:@"StatusModify_gray.png" ImagePressed:@"StatusModify_blue.png"];
b2.tag = 2; UIButton *b3 = [self createButtonWithFrame:CGRectMake(213, 0, 106.5, 44) Target:self Selector:@selector(btnAction:) Image:@"StatusTrash_gray.png" ImagePressed:@"StatusTrash_blue.png"];
b3.tag = 3;
// 加入到contentView,否则无法接收到事件
// 比如:直接加入一个按钮到tableView里面 是无法接收到事件的;由于tableView它不会把事件传递给它体系之外的不论什么控件
[self.contentView addSubview:b1];
[self.contentView addSubview:b2];
[self.contentView addSubview:b3];
}
return self;
} - (void)btnAction:(id)sender {
UIButton *btn = (UIButton *)sender;
switch (btn.tag) {
case 1:
{
NSLog(@">>>>>>>>>>B1");
}
break;
case 2:
{
NSLog(@">>>>>>>>>>B2");
}
break;
case 3:
{
NSLog(@">>>>>>>>>>B3");
}
break;
default:
break;
} }
#pragma mark - 工具方法
- (UIButton*) createButtonWithFrame: (CGRect) frame Target:(id)target Selector:(SEL)selector Image:(NSString *)image ImagePressed:(NSString *)imagePressed
{
UIButton * button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setFrame:frame];
UIImage *newImage = [UIImage imageNamed: image];
[button setBackgroundImage:newImage forState:UIControlStateNormal];
UIImage *newPressedImage = [UIImage imageNamed: imagePressed];
[button setBackgroundImage:newPressedImage forState:UIControlStateHighlighted];
[button addTarget:target action:selector forControlEvents:UIControlEventTouchUpInside];
return button;
}
@end

控制器,继承自UIViewController,最核心的部分
//
// MyProjectController.m
// 动态插入删除行
//
// Created by beyond on 14-10-18.
// Copyright (c) 2014年 com.beyond All rights reserved.
// 控制器,最最重要的部分 #import "MyProjectController.h"
#import "MyProjectCell.h"
#import "ChangeStatusCell.h"
#import "MyProjectCellModel.h"
// 很好用的,高速创建rect而且适配的宏
#define IsIOS7 ([[[[UIDevice currentDevice] systemVersion] substringToIndex:1] intValue]>=7)
#define CGRECT_NO_NAV(x,y,w,h) CGRectMake((x), (y+(IsIOS7?20:0)), (w), (h))
#define CGRECT_HAVE_NAV(x,y,w,h) CGRectMake((x), (y+(IsIOS7? 64:0)), (w), (h)) #define IS_IOS7 [[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0
@interface MyProjectController ()<UITableViewDataSource,UITableViewDelegate>
{
UITableView *_tableView;
// 数据源 对象 数组
NSMutableArray *_modelArr;
// 辅助的状态 字典 数组;长度与上面的modelArr一样
NSMutableArray *_statusDictArr;
// 记录已经展开的行号
int _ExpandedMainCellRow;
}
@end
@implementation MyProjectController
- (void)viewDidLoad
{
[super viewDidLoad]; if (IS_IOS7) {
self.edgesForExtendedLayout = UIRectEdgeNone;
self.extendedLayoutIncludesOpaqueBars = NO;
self.modalPresentationCapturesStatusBarAppearance = NO;
}
// 加入tableView,并设置代理和数据源
UITableView *tableView = [[UITableView alloc]initWithFrame:CGRECT_NO_NAV(0, 0, 320, 460) style:UITableViewStylePlain];
tableView.dataSource = self;
tableView.delegate = self;
[self.view addSubview:tableView]; _tableView = tableView;
_ExpandedMainCellRow = -1;
// 提供数据模型的数组
_modelArr = [NSMutableArray array];
// 用于记录 主Cell和附加Cell 以及 附加状态的数组;二者长度同样
_statusDictArr = [NSMutableArray array];
// 载入数据源
[self loadData];
}
#pragma mark - 初始化数据
- (void)loadData
{
NSString *filePath = [[NSBundle mainBundle]pathForResource:@"MyProjectList.plist" ofType:nil];
NSArray *tempArr = [NSArray arrayWithContentsOfFile:filePath];
// 很重要!!!!!!!仅供状态数组 使用
NSDictionary *statusDict = @{ @"Cell": @"MyProjectCell",
@"isAttached":@(NO)
};
for (NSDictionary *dict in tempArr) {
MyProjectCellModel *model = [MyProjectCellModel modelWithDict:dict];
[_modelArr addObject:model];
[_statusDictArr addObject:statusDict];
}
} #pragma mark - TableView代理方法
// 取消默认点击cell的选中效果
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
// 行高
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 44;
}
#pragma mark - TableView数据源
// 总的行数
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return _statusDictArr.count;
}
// 核心方法;分情况创建cell;或者为cell填充数据模型
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([[_statusDictArr[indexPath.row] objectForKey:@"Cell"] isEqualToString:@"MyProjectCell"])
{
static NSString *cellID_1 = @"MyProjectCell";
MyProjectCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID_1];
if (cell == nil) {
cell = [MyProjectCell myProjectCell];
cell.selectionStyle = UITableViewCellSelectionStyleGray;
__unsafe_unretained MyProjectController *blockCtroller = self;
cell.wannaChangeStatusBlock = ^(int row){
NSLog(@"控制器中拿到被点击的cell的行号: %d",row);
// 调用控制器的方法,显示 或者 隐藏 用于更改状态的view
[blockCtroller showHideChangeStatusView:row];
};
}
// 传递数据源
// 设置cell中独一无二的内容
int tempRow = indexPath.row;
if (_ExpandedMainCellRow != -1 && indexPath.row > _ExpandedMainCellRow) {
tempRow = indexPath.row - 1;
}
// 假设是由于 刚才展开的行,被关闭,而导致 本方法被调用;则没有展开的,还是按原来的位置取数据模型
if (_ExpandedMainCellRow == -1) {
tempRow = indexPath.row;
}
MyProjectCellModel *model = [_modelArr objectAtIndex:tempRow];
cell = [cell cellWithCellModel:model];
return cell;
}else if([[_statusDictArr[indexPath.row] objectForKey:@"Cell"] isEqualToString:@"ChangeStatusCell"]){
static NSString *cellID_2 = @"ChangeStatusCell";
ChangeStatusCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID_2];
if (cell == nil) {
cell = [[ChangeStatusCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID_2];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
return cell;
}
return nil;
}
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
// 開始滚动之前先关闭已经展开的AttachRow
}
#pragma mark - 点击了cell最右边的button时调用
//显示 或者 隐藏 用于更改状态的view
- (void)showHideChangeStatusView:(int)row
{
if (row == _ExpandedMainCellRow) {
// 假设这次点击的行 已经是打开的行,则直接关闭,并返回
[self closeOneExpandedCell:_ExpandedMainCellRow];
}else{
if (_ExpandedMainCellRow == -1) {
//代表从来没有展开过,首次展开
[self expandOneRow:row];
} else {
// 假设本次点击的行还没有展开,先关闭上次的展开的行;再展开开次的行
// 特别注意,这个row行号是包括了已经展开的AttachCell,因此,要 减去 1;此时的行号才是modelArr中的行号
if (_ExpandedMainCellRow < row) {
// 展开的行,在上面;新点击的行 在以下
row = row - 1;
}
[self closeOneExpandedCell:_ExpandedMainCellRow];
[self expandOneRow:row];
} }
}
// 关闭一个指定行的ExpandedCell
- (void)closeOneExpandedCell:(int)row
{
// 由于本操作运行完毕后,就没有展开的行,所以要先清零;必须先清零~~~~由于tableViewupdate方法中会调用cellForRow方法
_ExpandedMainCellRow = -1; // 假设第0行已经是附加了,则关闭附加cell
NSDictionary * dic = @{@"Cell": @"MyProjectCell",@"isAttached":@(NO)};
// 主Cell中的bool还原为NO
_statusDictArr[row] = dic;
NSLog(@"删除前:%d",[_statusDictArr count]);
// 主Cell数组中的的下一个位置处的AttchedCell删除
[_statusDictArr removeObjectAtIndex:row+1];
NSLog(@"删除后:%d",[_statusDictArr count]);
[_tableView beginUpdates];
NSIndexPath *path = [NSIndexPath indexPathForRow:row+1 inSection:0];
[_tableView deleteRowsAtIndexPaths:@[path] withRowAnimation:UITableViewRowAnimationMiddle];
[_tableView endUpdates]; }
//记录下 而且 展开指定的行 (顺序千万不能反)
- (void)expandOneRow:(int)row
{
_ExpandedMainCellRow = row;
// 假设第0行没有打开附加的cell,则打开附加cell
NSDictionary * dic = @{@"Cell": @"MyProjectCell",@"isAttached":@(YES)};
// 改动主Cell的状态字 isAttached为yes
_statusDictArr[row] = dic;
// 插入一个新的ChangeStatusCell到数组中
NSDictionary * addDic = @{@"Cell": @"ChangeStatusCell",@"isAttached":@(YES)};
[_statusDictArr insertObject:addDic atIndex:row + 1];
[_tableView beginUpdates];
NSIndexPath *path = [NSIndexPath indexPathForRow:row + 1 inSection:0];
[_tableView insertRowsAtIndexPaths:@[path] withRowAnimation:UITableViewRowAnimationMiddle];
[_tableView endUpdates];
if (row == _modelArr.count -1) {
// 假设展开的是最后一行,还要让tableView向上滚动44的高度
[self showExpandedCellForLastRow];
}
}
// 假设展开的是最后一行,还要让tableView向上滚动44的高度
- (void)showExpandedCellForLastRow
{
NSIndexPath *path = [NSIndexPath indexPathForRow:_modelArr.count inSection:0];
[_tableView scrollToRowAtIndexPath:path atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
} @end



版权声明:本文博主原创文章,博客,未经同意不得转载。

上一篇:XMLHttpRequest发送请求


下一篇:[转]win7+ubuntu 13.04双系统安装方法