iOS 开源项目iOS进阶指南iOS Developer

一句代码创建表格

2016-04-18  本文已影响334人  MrFire_

本文是一个关于表格的demo,力求极简调用,一句代码,一个表格,如有需要,同时又能实现一定程度的定制,表格中可以放置图片或者文字,单元格具有相应点击的能了,先看gif演示,演示过程有点慢,因为牵涉到几种情况切换时要修改参数:

ChartViewDemo.gif
    //1、建立左边标题数据
    NSArray *leftTitles = @[@"时间",@"09:00-10:00",@"10:00-11:00",@"11:00-12:00",@"12:00-13:00",@"13:00-14:00",@"14:00-15:00",@"15:00-16:00",@"16:00-17:00"];
    //2、建立上部标题
    NSArray *topTitles = @[@"4月1日",@"4月2日",@"4月3日",@"4月4日",@"4月5日",@"4月6日",@"4月7日",@"4月8日",@"4月9日"];

上面两部为公共部分,无论建立那种表格都这样建立数据,下面则根据你需要创建的表格类型去选择性的使用,共分为四种情况:
(1) 所有单元格为文字

    //3-1、如果单元格全部放置文字,则建立要显示的文字数组,按顺序排列(从0行0列开始)
    NSMutableArray *allTitles = [[NSMutableArray alloc] init];
    for (int i =0; i < (leftTitles.count - 1) * topTitles.count; i ++) {
        [allTitles addObject:[NSString stringWithFormat:@"%d",i]];
    }
    charView = [[ChartView alloc] initWithFrame:CGRectMake(10, 80, kScreenWidth - 20, kscreenHeight - 290) leftTitles:leftTitles topTitles:topTitles itemAllTitleDatas:allTitles];
    //若需要单元格的点击事件则需要设置代理,否则不需要
    charView.delegate = self;
    //将表格添加到view上
    [self.view addSubview:charView];

(2) 所有单元格为图片

    NSMutableArray *allTitles = [[NSMutableArray alloc] init];
    for (int i =0; i < (leftTitles.count - 1) * topTitles.count; i ++) {
        [allTitles addObject:[NSString stringWithFormat:@"%d",i]];
    }
    charView = [[ChartView alloc] initWithFrame:CGRectMake(10, 80, kScreenWidth - 20, kscreenHeight - 290) leftTitles:leftTitles topTitles:topTitles itemAllTitleDatas:allTitles];
    //若需要单元格的点击事件则需要设置代理,否则不需要
    charView.delegate = self;
    //将表格添加到view上
    [self.view addSubview:charView];

(3) 单元格部分为文字

    //这个时候需要注意,因为是定制的针对个别的单元格,所以需要把该单元格的坐标和要展示的文字的信息给包含进来,这里我采用的是字典的形式,数组中放的全是字典的形式,每个字典代表一个单元格的信息,其中key为该单元格个坐标,格式为:@"横坐标":@"竖坐标"(从0行0列开始),value为要展示的文字
    NSArray *itemTitleDatas = @[@{@"0:1":@"item0-1"},@{@"3:3":@"item3-3"}];
    charView = [[ChartView alloc] initWithFrame:CGRectMake(10, 80, kScreenWidth - 20, kscreenHeight - 290) leftTitles:leftTitles topTitles:topTitles itemTitleDatas:itemTitleDatas];
    //若需要单元格的点击事件则需要设置代理,否则不需要
    charView.delegate = self;
    //将表格添加到view上
    [self.view addSubview:charView];

(4) 单元格部分为图片

    //格式同上,不同的地方是字典中的value为图片的名字
    NSArray *itemImageDatas = @[@{@"0:1":@"fullOrdered"},@{@"3:3":@"ordered"}];
    charView = [[ChartView alloc] initWithFrame:CGRectMake(10, 80, kScreenWidth - 20, kscreenHeight - 290) leftTitles:leftTitles topTitles:topTitles itemImageDatas:itemImageDatas];

如果设置了代理,则可以拿到单元格的点击事件:

-(void)chartViewDidSelecteItemAtRow:(NSInteger)row column:(NSInteger)column{
    NSLog(@"选中表格内容:%d行  -- %d列",row,column);
}
-(void)chartViewDidSelecteTitleAtRow:(NSInteger)row{
    NSLog(@"选中左边title:%d",row);
}

源码解析

#define kChartBorderColer  [UIColor lightGrayColor].CGColor  //表格外框线颜色
#define kLineInsideColer   [UIColor lightGrayColor]          //表格内部线的颜色
#define kContentTitleColor [UIColor blackColor]              //表格内文字的颜色
#define kTopTitleColor     [UIColor blackColor]              //顶部标题文字颜色
#define kTopLineColor      [UIColor lightGrayColor]          //顶部标题线的颜色
#define kLeftTopTitleColor [UIColor blackColor]              //左边顶部标题文字颜色
#define kLeftTitleColor    [UIColor blackColor]              //左边标题文字颜色
static CGFloat   const kChartBorderLineWidth  = 1.0f;        //表格外宽线的宽度
static CGFloat   const kLeftItemWidth         = 100.0f;      //左边item宽度
static CGFloat   const kTopTitleHeight        = 63.0f;       //顶部标题栏的高度
static CGFloat   const kContentItemWidth      = 43.0f;       //表格内容item的宽度
static CGFloat   const kContentItemHeight     = 43.0f;       //表格内容item的高度
static CGFloat   const kTitleContentSeperateLineWidth = 0.5f;//表格左边标题与表格内容分界线的宽度
static CGFloat   const kTitleLineWidth        = 0.3f;        //顶部标题栏线宽
static CGFloat   const kContentLineWidth      = 0.25f;       //表格内容线的宽度
static CGFloat   const kChartCornerRadius     = 3.0f;        //表格外框的圆角
static CGFloat   const kLeftTopTitleFont      = 12.0f;       //左边顶部标题字体的大小
static CGFloat   const kLeftTitleFont         = 12.0f;       //左边title字体的大小
static CGFloat   const kTopTitleFont          = 10.0f;       //顶部title字体的大小
static CGFloat   const kContentTitleFont      = 10.0f;       //表格内容字体的大小
static NSString *const kLeftTableViewCellId   = @"leftTableViewCellId";
static NSString *const kContentCollectionId   = @"contentCollectionId";
@protocol ChartDelegate;
@interface ChartView : UIView
@property (nonatomic, assign) id<ChartDelegate>delegate;
/**
 *  表格内容全是图片
 *
 *  @param frame      表格的frame
 *  @param leftTitles 左边title数组
 *  @param topTitles  顶部title数组
 *  @param allImages  图片数组,直接放图片的名字即可(但是,图片名字的个数不能少于表格的个数,否则会崩溃)
 *
 *  @return ChartView对象
 */
-(instancetype)initWithFrame:(CGRect)frame leftTitles:(NSArray *)leftTitles topTitles:(NSArray *)topTitles itemAllImageDatas:(NSArray *)allImages;
/**
 *  表格内容全是文字
 *
 *  @param frame      表格的frame
 *  @param leftTitles 左边title数组
 *  @param topTitles  顶部title数组
 *  @param allTitles  文字数组,直接放需要展示的文字(文字的个数同样不能少于表格的个数,否则会崩溃)
 *
 *  @return ChartView对象
 */
-(instancetype)initWithFrame:(CGRect)frame leftTitles:(NSArray *)leftTitles topTitles:(NSArray *)topTitles itemAllTitleDatas:(NSArray *)allTitles;
/**
 *  表格中只有特定的几个表格是图片,其他item为空
 *
 *  @param frame      表格的frame
 *  @param leftTitles 左边title数组
 *  @param topTitles  顶部title数组
 *  @param imageItems 图片数组,格式:数组中全是字典,其中key为该item在表格中的坐标,行和列用“:”隔开,“:”前为行,后为列,表格除开标题外从0行0列开始计算,value为该item对应的图片名称,例:@[@{@"0:1":@"fullOrdered"},@{@"3:3":@"ordered"}],则0为行,1为列,fullOrdered为图片名称
 *
 *  @return ChartView对象
 */
-(instancetype)initWithFrame:(CGRect)frame leftTitles:(NSArray *)leftTitles topTitles:(NSArray *)topTitles itemImageDatas:(NSArray *)imageItems;
/**
 *  表格中只有特定的几个表格是文字,其他item为空
 *
 *  @param frame      表格的frame
 *  @param leftTitles 左边的title数组
 *  @param topTitles  顶部的title数组
 *  @param titleItems 文字数组,格式同上,value为该item对应的文字
 *
 *  @return ChartView对象
 */
-(instancetype)initWithFrame:(CGRect)frame leftTitles:(NSArray *)leftTitles topTitles:(NSArray *)topTitles itemTitleDatas:(NSArray *)titleItems;
@end
@protocol ChartDelegate <NSObject>
/**
 *  可选,若需要表格中的某个item时的点击事件,则需要设置代理,实现代理方法,否则不需要
 */
@optional
/**
 *  选中的某个item
 *
 *  @param row    该item所在的行
 *  @param column 该item所在的列
 */
-(void)chartViewDidSelecteItemAtRow:(NSInteger )row column:(NSInteger )column;
/**
 *  选中的左边title
 *
 *  @param row 选中的左边item的row
 */
-(void)chartViewDidSelecteTitleAtRow:(NSInteger )row;
@end
-(instancetype)initWithFrame:(CGRect)frame leftTitles:(NSArray *)leftTitles topTitles:(NSArray *)topTitles itemAllImageDatas:(NSArray *)allImages{
    if (self = [super initWithFrame:frame]) {
        _leftData          = [NSMutableArray arrayWithArray:leftTitles];
        _topTitleData      = [NSMutableArray arrayWithArray:topTitles];
        _contentAllImages  = [NSMutableArray arrayWithArray:allImages];
        [self customeChartOutlook];
        [self createLeftTableView];
        [self createContentCollectionView];
    }
    return self;
}

2、表格的外观是这样设置的,直接使用的border

-(void)customeChartOutlook{
    self.layer.borderWidth  = kChartBorderLineWidth;
    self.layer.borderColor  = kChartBorderColer;
    self.layer.cornerRadius = kChartCornerRadius;
    self.clipsToBounds      = YES;
}

3、左边标题栏

-(void)createLeftTableView{
    //第一行标题
    UILabel *leftTitle      = [[UILabel alloc] initWithFrame:CGRectMake(kChartBorderLineWidth, kChartBorderLineWidth, kLeftItemWidth, kTopTitleHeight)];
    leftTitle.text          = self.leftData[0];
    leftTitle.font          = [UIFont systemFontOfSize:kLeftTopTitleFont];
    leftTitle.textAlignment = NSTextAlignmentCenter;
    leftTitle.textColor     = kLeftTopTitleColor;
    [self addSubview:leftTitle];
    
    CGFloat tableHeight = kContentItemHeight * (self.leftData.count - 1);
    if (self.frame.size.height > tableHeight) {
        CGRect tempFrame      = self.frame;
        tempFrame.size.height = tableHeight;
        self.frame            = tempFrame;
    }else if (self.frame.size.height < tableHeight){
        tableHeight           = self.frame.size.height;
    }
    self.leftTableView = [[UITableView alloc] initWithFrame:CGRectMake(kChartBorderLineWidth, kChartBorderLineWidth + kTopTitleHeight, kLeftItemWidth, tableHeight - kTopTitleHeight) style:UITableViewStylePlain];
    self.leftTableView.dataSource                     = self;
    self.leftTableView.delegate                       = self;
    self.leftTableView.separatorInset                 = UIEdgeInsetsZero;
    self.leftTableView.layoutMargins                  = UIEdgeInsetsZero;
    self.leftTableView.bounces                        = NO;
    self.leftTableView.showsVerticalScrollIndicator   = NO;
    self.leftTableView.showsHorizontalScrollIndicator = NO;
    [self addSubview:self.leftTableView];
    [self.leftTableView registerClass:[UITableViewCell class] forCellReuseIdentifier:kLeftTableViewCellId];
    UIView *vLine = [[UIView alloc] initWithFrame:CGRectMake(self.leftTableView.frame.origin.x + self.leftTableView.frame.size.width, kChartBorderLineWidth, kTitleContentSeperateLineWidth, self.leftTableView.frame.size.height + kTopTitleHeight + kTitleLineWidth)];
    vLine.backgroundColor = kLineInsideColer;
    [self addSubview:vLine];
    UIView *hLine = [[UIView alloc] initWithFrame:CGRectMake(kChartBorderLineWidth, leftTitle.frame.origin.y + leftTitle.frame.size.height, kLeftItemWidth, kTitleLineWidth)];
    hLine.backgroundColor = kTopLineColor;
    [self addSubview:hLine];
}

4、右边视图,这个方法写的有点长,分开写更好一点,大家知道思路就可以了,然后可以自己动手写一下

-(void)createContentCollectionView{
    CGFloat scrollX = self.leftTableView.frame.origin.x + self.leftTableView.frame.size.width + kTitleContentSeperateLineWidth;
    //减去0.5是为了消除黑线,如果调整了黑线的宽度,可以微调这个数来消除黑线
    self.contentScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(scrollX - 0.5, self.leftTableView.frame.origin.y - 0.5, self.frame.size.width - kChartBorderLineWidth - scrollX, self.leftTableView.frame.size.height)];
    //self.contentScrollView.backgroundColor = [UIColor orangeColor];
    self.contentScrollView.contentSize = CGSizeMake(self.contentScrollView.frame.size.width, kContentItemHeight * (self.leftData.count - 1));
    self.contentScrollView.delegate = self;
    self.contentScrollView.bounces = NO;
    self.contentScrollView.showsVerticalScrollIndicator = NO;
    [self addSubview:self.contentScrollView];
    [self sendSubviewToBack:self.contentScrollView];
    
    UICollectionViewFlowLayout *flow = [[UICollectionViewFlowLayout alloc] init];
    [flow setScrollDirection:UICollectionViewScrollDirectionHorizontal];
    flow.minimumLineSpacing = 0;
    flow.minimumInteritemSpacing = 0;
    flow.itemSize = CGSizeMake(kContentItemWidth, kContentItemHeight);
    //减去0.2是为了消去黑线
    self.contentCollectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 0 - 0.2, self.contentScrollView.frame.size.width, kContentItemHeight * (self.leftData.count - 1)) collectionViewLayout:flow];
    self.contentCollectionView.backgroundColor = [UIColor whiteColor];
    self.contentCollectionView.delegate = self;
    self.contentCollectionView.dataSource = self;
    self.contentCollectionView.bounces = NO;
    self.contentCollectionView.showsVerticalScrollIndicator = NO;
    self.contentCollectionView.showsHorizontalScrollIndicator = NO;
    [self.contentScrollView addSubview:self.contentCollectionView];
    [self.contentCollectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:kContentCollectionId];
    //顶部标题栏
    self.rightTopScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(self.contentScrollView.frame.origin.x, kChartBorderLineWidth, self.contentScrollView.frame.size.width, kTopTitleHeight + kTitleLineWidth)];
    [self addSubview:self.rightTopScrollView];
    self.rightTopScrollView.contentSize = CGSizeMake(kContentItemHeight * self.topTitleData.count, 0);
    self.rightTopScrollView.showsHorizontalScrollIndicator = NO;
    self.rightTopScrollView.bounces = NO;
    self.rightTopScrollView.delegate = self;
    for (int i = 0; i < self.topTitleData.count; i ++) {
        UILabel *rightTopTitle = [[UILabel alloc] initWithFrame:CGRectMake(i * (kContentItemWidth + kTitleLineWidth), 0, kContentItemWidth, kTopTitleHeight)];
        rightTopTitle.text = self.topTitleData[i];
        rightTopTitle.textAlignment = NSTextAlignmentCenter;
        rightTopTitle.font = [UIFont systemFontOfSize:kTopTitleFont];
        rightTopTitle.textColor = kTopTitleColor;
        rightTopTitle.backgroundColor = [UIColor clearColor];
        [self.rightTopScrollView addSubview:rightTopTitle];
        //以下坐标算法是为了调整顶部标题栏的竖线与下面内容线不对齐的问题,解决方案很不好,有待完善
        UIView *topVLine = [[UIView alloc] initWithFrame:CGRectMake((i + 1) * (kContentItemWidth + kTitleLineWidth) -  (i+1) *kContentLineWidth * 1.3, 0, 0.5, kTopTitleHeight)];
        topVLine.backgroundColor = kLineInsideColer;
        [self.rightTopScrollView addSubview:topVLine];
    }
    UIView *hLine = [[UIView alloc] initWithFrame:CGRectMake(kChartBorderLineWidth, kTopTitleHeight, self.rightTopScrollView.contentSize.width, kTitleLineWidth)];
    hLine.backgroundColor = kTopLineColor;
    [self.rightTopScrollView addSubview:hLine];
}

代码就贴这么多吧,主要是项目中用到了表格,需求也是某个单元格有内容,需要响应点击事件,没找到合适的第三方,就自己动手写了一个,由于是基于项目的功能,所以封装的不是特别好,不过对于一般的这种表格需要应该问题不太大了,若发现不足之处欢迎指出!


上一篇下一篇

猜你喜欢

热点阅读