iOS端UI控件-循环滚动表格
前言
学习iOS开发一个多月了,最近做项目的时候碰到一个这样的需求:一个展示数据的面板,里面有一个表格,表格的数据循环滚动。类似下图:
我这个人又比较懒,一开始直接上Google看看有没有现成的控件使用,翻了半天也没找到一些能用的东西,基本上都满足不了我的需求,然后我就打算自己写一个用吧,有一篇文章的思路倒是给了我很大的启发,这篇文章讲述的代码使用swift写的,由于我用的是Objective-C,最后我自己封装了一个控件。
思路
- 控件:一个父view,一个headerView,两个TableView。其中headerView是表头,两个TableView加载的是相同的数据。父视图的clipsToBounds属性一定要设置为YES。
- 滚动:如何让它滚动起来呢?这里我用的是一个定时器,通过控制时间间隔和位移距离,让其滚动的效果平滑顺畅。
- 循环:如何让其循环滚动呢?在第1步中使用到的两个TableView,把这两个TableView上下拼接起来,当地一个TableView滚动出视图外的时候,就把它移到第二个TableView的下面,如此循环往复就实现的循环滚动。
代码
-
新建
ScrollTableView.h
和ScrollTableView.m
,其中ScrollTableView.h
代码如下:#import <UIKit/UIKit.h> NS_ASSUME_NONNULL_BEGIN @interface LSWScrollTableView : UIView /** * * @param frame 位置 * @param columns 表头数据 [{key:"", value:"", width:""}, ...] key为表头名字,value为与表头对应的字段,width为单元格宽度 * @param data 表格数据 * @param cellHeight 单元格高度 * @param headerHeight 表头高度 * @param cellBackgroundColor 单元格背景色只支持斑马纹 需要传两个UIColor组成的数组,例:@[[UIColor redColor], [UIColor blueColor]] * @param headerBackgroundColor 表头背景色 * @param headerTextColor 表头文字颜色 * @param cellTextColor 单元格文字颜色 * @return 返回一个UIView */ - (instancetype)initWithFrame:(CGRect)frame columns:(NSArray *)columns data:(NSArray *)data cellHeight: (CGFloat)cellHeight headerHeight:(CGFloat)headerHeight cellBackgroundColor:(NSArray *)cellBackgroundColor headerBackgroundColor:(UIColor *)headerBackgroundColor headerTextColor:(UIColor *)headerTextColor cellTextColor:(UIColor *)cellTextColor; /** * 关闭滚动 */ - (void)stopScroll; /** * 打开滚动 */ - (void)openScroll; @end NS_ASSUME_NONNULL_END
-
ScrollTableView.m
代码如下:#import "LSWScrollTableView.h" #define COLOR(R, G, B, A) [UIColor colorWithRed:R/255.0 green:G/255.0 blue:B/255.0 alpha:A] @interface LSWScrollTableView ()<UITableViewDataSource, UITableViewDelegate> @property (nonatomic, strong) NSTimer *timer; ///定时器,用于开启、关闭滚动 @property (nonatomic, strong) NSArray *data; ///传入的原始数据 @property (nonatomic) CGFloat cellHeight; ///单元格高度 @property (nonatomic, strong) NSArray *columns; ///表头数据 @property (nonatomic) CGFloat headerHeight; ///表头高度 @property (nonatomic, strong) NSArray *cellBackgroundColor; ///单元格背景色 @property (nonatomic, strong) UIColor *cellTextColor; ///文字颜色 @property (nonatomic, strong) UITableView *tableView1; ///表格1 @property (nonatomic, strong) UITableView *tableView2; ///表格2 @end @implementation LSWScrollTableView static NSString *const cellId = @"cellId"; - (instancetype)initWithFrame:(CGRect)frame columns:(NSArray *)columns data:(NSArray *)data cellHeight: (CGFloat)cellHeight headerHeight:(CGFloat)headerHeight cellBackgroundColor:(NSArray *)cellBackgroundColor headerBackgroundColor:(UIColor *)headerBackgroundColor headerTextColor:(UIColor *)headerTextColor cellTextColor:(UIColor *)cellTextColor { self = [super initWithFrame:frame]; if (self) { self.data = data; self.columns = columns; self.cellHeight = cellHeight; self.headerHeight = headerHeight; self.cellBackgroundColor = cellBackgroundColor; self.cellTextColor = cellTextColor; self.backgroundColor = COLOR(0, 0, 0, 0); ///表头部分 UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, frame.size.width, self.headerHeight)]; headerView.backgroundColor = headerBackgroundColor; if (columns && columns.count > 0) { __block CGFloat headerX = 0; [self.columns enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(headerX, 0, [obj[@"width"] floatValue], self.headerHeight)]; label.text = obj[@"key"]; label.textColor = headerTextColor; label.textAlignment = NSTextAlignmentCenter; label.backgroundColor = COLOR(0, 0, 0, 0); headerX += [obj[@"width"] floatValue]; [headerView addSubview:label]; }]; } else { NSLog(@"columns不能为空"); } [self addSubview:headerView]; ///表格部分 UIView *tableView = [[UIView alloc] initWithFrame:CGRectMake(0, self.headerHeight, frame.size.width, frame.size.height - self.headerHeight)]; tableView.clipsToBounds = YES; tableView.backgroundColor = COLOR(0, 0, 0, 0); self.tableView1 = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, frame.size.width, self.data.count * self.cellHeight)]; self.tableView2 = [[UITableView alloc] initWithFrame:CGRectMake(0, self.tableView1.frame.origin.y + self.tableView1.frame.size.height, frame.size.width, self.data.count * self.cellHeight)]; self.tableView1.backgroundColor = COLOR(0, 0, 0, 0); self.tableView2.backgroundColor = COLOR(0, 0, 0, 0); self.tableView1.delegate = self; self.tableView1.dataSource = self; self.tableView2.delegate = self; self.tableView2.dataSource = self; self.tableView1.scrollEnabled = NO; ///禁止表格1自带的滚动 self.tableView2.scrollEnabled = NO; ///禁止表格2自带的滚动 [tableView addSubview:self.tableView1]; [tableView addSubview:self.tableView2]; [self addSubview:tableView]; ///开始滚动 [self openScroll]; } return self; } #pragma mark - UITableViewDelegate ///渲染数据 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellId]; if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellId]; } __block CGFloat headerX = 0; [self.columns enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(headerX, 0, [obj[@"width"] floatValue], self.headerHeight)]; label.text = self.data[indexPath.row][obj[@"value"]]; label.textAlignment = NSTextAlignmentCenter; label.backgroundColor = COLOR(0, 0, 0, 0); label.textColor = self.cellTextColor; headerX += [obj[@"width"] floatValue]; [cell addSubview:label]; }]; ///这里我把单元格颜色做成斑马纹的样式 if (self.data.count % 2 == 1) { if (tableView == self.tableView1) { if (indexPath.row % 2 == 1) { cell.backgroundColor = self.cellBackgroundColor[0]; } else { cell.backgroundColor = self.cellBackgroundColor[1]; } } else if (tableView == self.tableView2) { if (indexPath.row % 2 == 0) { cell.backgroundColor = self.cellBackgroundColor[0]; } else { cell.backgroundColor = self.cellBackgroundColor[1]; } } } else if (self.data.count % 2 == 0) { if (indexPath.row % 2 == 1) { cell.backgroundColor = self.cellBackgroundColor[0]; } else { cell.backgroundColor = self.cellBackgroundColor[1]; } } cell.selectionStyle = UITableViewCellSelectionStyleNone; ///禁止选中 return cell; } ///cell个数 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.data.count; } ///分区个数 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 1; } #pragma mark - UITableViewDataSource ///cell高度 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { return self.cellHeight; } ///停止滚动 - (void)stopScroll{ [self.timer invalidate]; self.timer = nil; } ///开启滚动 - (void)openScroll{ if (self.timer == nil) { self.timer = [NSTimer timerWithTimeInterval:0.03 repeats:YES block:^(NSTimer *timer) { CGRect newTable1ViewFrame = self.tableView1.frame; newTable1ViewFrame.origin.y -= 0.9; if (newTable1ViewFrame.origin.y < -(self.tableView1.frame.size.height)) { newTable1ViewFrame.origin.y = self.tableView1.frame.size.height; } self.tableView1.frame = newTable1ViewFrame; CGRect newTable2ViewFrame = self.tableView2.frame; newTable2ViewFrame.origin.y -= 0.9; if (newTable2ViewFrame.origin.y < -(self.tableView1.frame.size.height)) { newTable2ViewFrame.origin.y = self.tableView1.frame.size.height; } self.tableView2.frame = newTable2ViewFrame; }]; [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSDefaultRunLoopMode]; } else { NSLog(@"已经在滚动中,请勿重复开启"); } } /* // Only override drawRect: if you perform custom drawing. // An empty implementation adversely affects performance during animation. - (void)drawRect:(CGRect)rect { // Drawing code } */ @end
使用效果图
-
效果图:
-
示例数据:
NSArray *columns = @[ @{ @"key": @"项目类型", @"value": @"projectType", @"width": [NSNumber numberWithInt:150] }, @{ @"key": @"客户名称", @"value": @"customerName", @"width": [NSNumber numberWithInt:250] }, @{ @"key": @"电梯数量", @"value": @"elevatorNum", @"width": [NSNumber numberWithInt:150] } ]; NSArray *data = @[ @{ @"projectType": @"T类", @"customerName": @"南昌轨道交通二号线", @"elevatorNum": @"1" }, @{ @"projectType": @"T类", @"customerName": @"南昌轨道交通三号线", @"elevatorNum": @"2" }, @{ @"projectType": @"T类", @"customerName": @"南昌轨道交通四号线", @"elevatorNum": @"3" }, @{ @"projectType": @"T类", @"customerName": @"南昌轨道交通五号线", @"elevatorNum": @"4" }, @{ @"projectType": @"T类", @"customerName": @"南昌轨道交通六号线", @"elevatorNum": @"5" }, @{ @"projectType": @"T类", @"customerName": @"南昌轨道交通七号线", @"elevatorNum": @"6" }, @{ @"projectType": @"T类", @"customerName": @"南昌轨道交通八号线", @"elevatorNum": @"7" }, @{ @"projectType": @"T类", @"customerName": @"南昌轨道交通九号线", @"elevatorNum": @"8" }, @{ @"projectType": @"T类", @"customerName": @"南昌轨道交通十号线", @"elevatorNum": @"9" }, @{ @"projectType": @"T类", @"customerName": @"南昌轨道交通十一号线", @"elevatorNum": @"10" }, ];
-
使用方式
// rgb颜色转换(16进制->10进制) #define UIColorFromRGB(rgbValue) [UIColor colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 green:((float)((rgbValue & 0xFF00) >> 8))/255.0 blue:((float)(rgbValue & 0xFF))/255.0 alpha:1.0] #define ODD_COLOR UIColorFromRGB(0x12141e) ///表格奇数行背景颜色 #define EVEN_COLOR UIColorFromRGB(0x18212f) ///表格偶数行背景颜色 #define TABLE_HEADER_COLOR UIColorFromRGB(0x0f3b47) ///表头背景颜色 ScrollTableView *scrollTableView = [[ScrollTableView alloc] initWithFrame:CGRectMake(0, 0, 550, 320) columns:columns data:data cellHeight:40 headerHeight:50 cellBackgroundColor:@[ODD_COLOR,EVEN_COLOR] headerBackgroundColor:TABLE_HEADER_COLOR headerTextColor:[UIColor whiteColor] cellTextColor:[UIColor whiteColor]];
写在最后
我已经把这个控件发布到cocoapods上面了,如果不想自己封装可以使用pod 'LSWScrollTableView'
,然后在项目中使用#import "LSWScrollTableView.h"
就可以使用了,这是GitHub地址