iOS期货表实现

废话不多说,直接入主题。

期货表,如图下:

这里主要讲期货表UI地实现。

期货表是一个能横向+竖向滚动地表格,实时更新最新期货数据并且高亮显示。期货表地实现方法有很多,主要看组件地选择。我这里讲一个稍微简单点地方法。

这是期货表地IB图,很简单,就是一个UITableView:

我地方法是在每个UITableViewCell中创建一个UILable和UIScrollView,具体样子如图:

第一列为固定不动地UILabel,右边为滚动显示地UIScrollView,竖向滚动由UITableView自带实现,横向滚动做Cell同步处理,同步处理的Cell为当前显示地Cell(这点是必须地,表可能比较大,同步范围太大会有延迟)。

由于标题部分和Cell部分是相同地,所以代码不能放在Cell中,抽离公共部分单独为一个View,代码如下:

#import <UIKit/UIKit.h>
#import "TouchScrollView.h"

#define FuturesStyleTitle 0
#define FuturesStyleContent 1

@interface FuturesView : UIView <UIScrollViewDelegate>{
    UILabel *_titleLab;  // 第一列标题
    TouchScrollView *_titleScroll;  // 滚动数据
    UILabel *_arrowLeft;  // 标识方向地左箭头
    UILabel *_arrowRight;  // 右箭头
    int _style;  // 类别:标题还是数据
}

@property(nonatomic, readonly) UILabel *titleLab;
@property(nonatomic, readonly) TouchScrollView *titleScroll;
@property(nonatomic, readonly) UILabel *arrowLeft;
@property(nonatomic, readonly) UILabel *arrowRight;
@property(nonatomic, readonly) int style;

- (id)initWithFrame:(CGRect)frame byStyle:(int)style;

// 赋值
- (void) setData:(id)data allow:(BOOL)isAllow;

// 数据更新
- (void) update:(id)value;

// 高亮单元恢复显示
- (void) normal;

@end
.M文件
#import "FuturesView.h"
#import "FuturesEntity.h"

@implementation FuturesView
@synthesize titleLab = _titleLab;
@synthesize titleScroll = _titleScroll;
@synthesize arrowLeft = _arrowLeft;
@synthesize arrowRight = _arrowRight;

static NSMutableArray *pool = nil;  // 共享池,内部存储当前显示地CellView,因为UITableView地Cell本来就支持重用

- (id) init {
    return [self initWithFrame:CGRectMake(0, 0, 320, 28)];
}
- (id)initWithFrame:(CGRect)frame
{
    self = [self initWithFrame:frame byStyle:FuturesStyleContent];
    return self;
}
- (id)initWithFrame:(CGRect)frame byStyle:(int)style {
    self = [super initWithFrame:frame];
    
    _style = style;
    
    float width = 75;
    float height = style == FuturesStyleTitle ? 30 : 28;
    
    _titleLab = [self createLabel:0 width:(width+5) height:height];
    _titleLab.frame = CGRectMake(3, 0, width+5, height);
    _titleLab.textAlignment = UITextAlignmentLeft;
    if(self.style == FuturesStyleTitle) {
        [_titleLab setTextColor:[UIColor colorWithRed:0.35 green:0.76 blue:0.71 alpha:1]];
    } else {
        [_titleLab setTextColor:[UIColor yellowColor]];
    }
    [self addSubview:_titleLab];
    [_titleLab release];
    // 自定义ScrollView,主要处理事件穿透
    _titleScroll = [[TouchScrollView alloc] initWithFrame:CGRectMake((width+5), 0, frame.size.width - (width+5), height)];
    [_titleScroll setShowsVerticalScrollIndicator:NO];
    [_titleScroll setShowsHorizontalScrollIndicator:NO];
    [_titleScroll setBounces:NO];
    [_titleScroll setBackgroundColor:[UIColor clearColor]];
    [self addSubview:_titleScroll];
    [_titleScroll release];
    
    [_titleScroll setContentSize:CGSizeMake(10 * width + 5, height)];
    UILabel *temp = nil;
    for(int i=0; i<10; i++) {
        temp = [self createLabel:i width:width height:height];
        if(style == FuturesStyleTitle) {
            if(i <= 2) {
                temp.textColor = [UIColor whiteColor];
            } else {
                temp.textColor = [UIColor colorWithRed:0.35 green:0.76 blue:0.71 alpha:1];
            }
        } else if(style == FuturesStyleContent && (i == 2 || i == 6)) {
            temp.textColor = [UIColor yellowColor];
        }
        [_titleScroll addSubview:temp];
        [temp release];
    }
    
    if(pool == nil) {
        pool = [[NSMutableArray alloc] initWithCapacity:15];
    }
    // 加入共享池
    _titleScroll.delegate = self;
    [pool addObject:_titleScroll];
    
    if(style == FuturesStyleTitle) {
        _arrowLeft = [[UILabel alloc] initWithFrame:CGRectMake(70, 0, 10, 10)];
        _arrowLeft.font = [UIFont boldSystemFontOfSize:10];
        _arrowLeft.textColor = [UIColor colorWithRed:0.35 green:0.76 blue:0.71 alpha:1];
        _arrowLeft.backgroundColor = [UIColor clearColor];
        _arrowLeft.text = @"《";
        _arrowLeft.hidden = YES;
        [self addSubview:_arrowLeft];
        [_arrowLeft release];
        
        _arrowRight = [[UILabel alloc] initWithFrame:CGRectMake(self.frame.size.width - 10, 0, 10, 10)];
        _arrowRight.font = [UIFont boldSystemFontOfSize:10];
        _arrowRight.textColor = [UIColor colorWithRed:0.35 green:0.76 blue:0.71 alpha:1];
        _arrowRight.backgroundColor = [UIColor clearColor];
        _arrowRight.text = @"》";
        [self addSubview:_arrowRight];
        [_arrowRight release];
    }
    
    return self;
}

- (void) dealloc {
    [pool release];
    pool = nil;
    [super dealloc];
}

-(void)scrollViewDidScroll:(UIScrollView*)scrollView {
    for(UIScrollView *scroll in pool) {
        [scroll setContentOffset:scrollView.contentOffset];
    }
//    [info setContentOffset:CGPointMake(titl.contentOffset.x, info.contentOffset.y)];
    [self.arrowLeft setHidden:(scrollView.contentOffset.x <= 0.0f)];
    [self.arrowRight setHidden:(scrollView.contentOffset.x >= scrollView.contentSize.width - self.frame.size.width + scrollView.frame.origin.x)];
}

- (UILabel *) createLabel:(int)cellIndex width:(float)width height:(float)height {
    UILabel *lab = [[UILabel alloc] initWithFrame:CGRectMake(cellIndex * width, 0, width, height)];
    [lab setTextAlignment:UITextAlignmentRight];
    [lab setBackgroundColor:[UIColor clearColor]];
    [lab setTextColor:[UIColor whiteColor]];
    [lab setFont:[UIFont boldSystemFontOfSize:15]];
    return lab;
}

- (void) setData:(id)data allow:(BOOL)isAllow {
    if(self.style == FuturesStyleTitle) {
        NSArray *arr = (NSArray *)data;
        self.titleLab.text = [arr objectAtIndex:0];
        UILabel *temp = nil;
        for(int i=0; i<arr.count - 1; i++) {
            temp = [self.titleScroll.subviews objectAtIndex:i];
            temp.text = [arr objectAtIndex:(i+1)];
        }
    } else {
        FuturesEntity *entity = (FuturesEntity *)data;
        self.titleLab.text = entity.name;
        if(!isAllow) {
            NSArray *subviews = self.titleScroll.subviews;
            for(UILabel *lab in subviews) {
                lab.text = @"*****";
            }
            return;
        }
        NSArray *subviews = self.titleScroll.subviews;
        [self updateValue:[subviews objectAtIndex:0] value:entity.news isColor:FALSE];
        [self updateValue:[subviews objectAtIndex:1] value:entity.change isColor:FALSE];
        [self updateValue:[subviews objectAtIndex:2] value:entity.volume isColor:FALSE];
        [self updateValue:[subviews objectAtIndex:3] value:[NSString stringWithFormat:@"%@%%",entity.margin] isColor:FALSE];
        [self updateValue:[subviews objectAtIndex:4] value:entity.last_av isColor:FALSE];
        [self updateValue:[subviews objectAtIndex:5] value:entity.close isColor:FALSE];
        [self updateValue:[subviews objectAtIndex:6] value:entity.hold isColor:FALSE];
        [self updateValue:[subviews objectAtIndex:7] value:entity.open isColor:FALSE];
        [self updateValue:[subviews objectAtIndex:8] value:entity.high isColor:FALSE];
        [self updateValue:[subviews objectAtIndex:9] value:entity.low isColor:FALSE];
        
        UIColor *red = [UIColor redColor];
        UIColor *green = [UIColor greenColor];
        UIColor *color = entity.change.floatValue > 0 ? red : green;
        [[subviews objectAtIndex:0] setTextColor:color];
        [[subviews objectAtIndex:1] setTextColor:color];
        [[subviews objectAtIndex:3] setTextColor:color];
        
        float last = [entity.last_av floatValue];
        [[subviews objectAtIndex:7] setTextColor:(entity.open.floatValue > last ? red : green)];
        [[subviews objectAtIndex:8] setTextColor:(entity.high.floatValue > last ? red : green)];
        [[subviews objectAtIndex:9] setTextColor:(entity.low.floatValue > last ? red : green)];
    }
}

- (void) update:(id)value {
    FuturesEntity *entity = value;
    NSArray *subviews = self.titleScroll.subviews;
    [self updateValue:[subviews objectAtIndex:0] value:entity.news isColor:TRUE];
    [self updateValue:[subviews objectAtIndex:1] value:entity.change isColor:TRUE];
    [self updateValue:[subviews objectAtIndex:2] value:entity.volume isColor:TRUE];
    [self updateValue:[subviews objectAtIndex:3] value:[NSString stringWithFormat:@"%@%%",entity.margin] isColor:TRUE];
    [self updateValue:[subviews objectAtIndex:4] value:entity.last_av isColor:TRUE];
    [self updateValue:[subviews objectAtIndex:5] value:entity.close isColor:TRUE];
    [self updateValue:[subviews objectAtIndex:6] value:entity.hold isColor:TRUE];
    [self updateValue:[subviews objectAtIndex:7] value:entity.open isColor:TRUE];
    [self updateValue:[subviews objectAtIndex:8] value:entity.high isColor:TRUE];
    [self updateValue:[subviews objectAtIndex:9] value:entity.low isColor:TRUE];
}

- (void) updateValue:(UILabel *)lab value:(NSString *)value isColor:(BOOL)isColor {
    if(isColor && ![lab.text isEqualToString:value]) {
        [lab setBackgroundColor:[UIColor blueColor]];
    } else {
        [lab setBackgroundColor:[UIColor clearColor]];
    }
    lab.text = value;
}

- (void) normal {
    UIColor *color =[UIColor clearColor];
    [self.titleLab setBackgroundColor:color];
    NSArray *subviews = self.titleScroll.subviews;
    for(int i=0; i<10; i++) {
        UILabel *temp = [subviews objectAtIndex:i];
        [temp setBackgroundColor:color];
    }
}
// 事件穿透处理,向上层传递
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    [self.nextResponder touchesBegan:touches withEvent:event];
}
- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    [self.nextResponder touchesEnded:touches withEvent:event];
}
注意部分我加了注释,因为在UITableView中添加UIScrollView会出现事件拦截问题,即UIScrollView和UITableView只有一个能响应事件,要么 只能横向滚动要么只能竖向滚动,为了解决这个问题,自定义了UIScrollView,重载touch系列方法,实现事件穿透。

代码里有个FuturesEntity类,这是一个实例类,存储期货数据字段,代码比较长且没意义,就没贴上来了,可以根据上面调用看得出内容。

自定义地UISCrollView很简单:

#import "TouchScrollView.h"

@implementation TouchScrollView

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    return self;
}

- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    [self.nextResponder touchesBegan:touches withEvent:event];
}
- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    [self.nextResponder touchesEnded:touches withEvent:event];
}
UISCrollView的touch传递给上级,也就是包含UIScrollView地FuturesView,FuturesView再传递给上层,即UITableView,最终实现UIScrollView和UITableView都响应事件地目的。

最终UITableView协议方法代码如下:

- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"futuresCell"];
    FuturesView *cellView = nil;
    if(cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"futuresCell"] autorelease];
        cellView = [[FuturesView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 28) byStyle:FuturesStyleContent];
        [cell addSubview:cellView];
        [cellView release];
    } else {
        cellView = (FuturesView *)[cell.subviews objectAtIndex:(cell.subviews.count-1)];
    }
    [cellView setData:[self.mainData objectAtIndex:indexPath.row] allow:self.timer.isAllow];
    return cell;
}

整体运行起来就是前面第一幅图地样子,代码是我项目中复制过来地,如果有人需要,请改改。另外如果有问题需要交流请给我留言,不谢。

补充回复要求Timer:

FuturesTimer.h

#import <Foundation/Foundation.h>
#import "HttpUtil.h"
#import "FuturesView.h"

@interface FuturesTimer : NSObject <HttpProtocol> {
    BOOL _isWorking;
    id _delegate;
    int _filter;
    NSString *_searchValue;
    NSTimer *_timer;
}

@property (nonatomic, readonly) BOOL isWorking;
@property (nonatomic, assign) id delegate;
@property (nonatomic) int filter;
@property (nonatomic, retain) NSString *searchValue;
@property (nonatomic, retain) NSTimer *timer;

- (void) destory;
- (void) work;
- (void) stop;

- (void) empty;

- (FuturesView *) futuresViewInCell:(UITableViewCell *)cell;

@end



FuturesTimer.m

#import "FuturesTimer.h"
#import "Header.h"
#import "Config.h"
#import "UserEntity.h"
#import "FuturesViewController.h"
#import "FuturesEntity.h"
#import "UIUtil.h"
#import "AppDelegate.h"

@implementation FuturesTimer

@synthesize isWorking = _isWorking;
@synthesize delegate = _delegate;
@synthesize filter = _filter;
@synthesize searchValue = _searchValue;
@synthesize timer = _timer;

- (id) init {
    self = [super init];
    [self empty];
    return self;
}
- (void) empty {
    self.searchValue = nil;
    self.filter = -1;
}
- (void) work {
    _isWorking = YES;
    // retainCount=1为self.timer持有retain,本身对象已经释放
    if(self.timer == nil) {
        [self loadData];
    } else if([self.timer retainCount] > 1) {
        [self.timer fire];
    }
}
- (void) stop {
    _isWorking = FALSE;
}
- (void) loadData {
    NSString *url = nil;
    if(self.searchValue != nil) {
	// 期货表搜索
        url = [NSString stringWithFormat:@"xxx?key=%@", self.searchValue];
    } else if (self.filter == -1) {
	// 个人订阅
        UserEntity *user = (UserEntity *)[[Config Instance] getCache:@"user"];
        url = [NSString stringWithFormat:@"xxx?corpID=%d", user.uid];
    } else {
	// 期货表筛选(品种)
        url = [NSString stringWithFormat:@"xxx?id=%d", self.filter];
    }
    [HttpUtil HttpGet:self aciton:url keyBack:0];
}
- (float) getTime {
    UserEntity *user = (UserEntity *)[[Config Instance] getCache:@"user"];
    int time = [[[Config Instance] getCache:[NSString stringWithFormat:@"%@%d", futures_timer, user.uid]] intValue];
    if(time == 0) {
        time = 5;
    }
    return time;
}
- (void) start {
    self.timer = [NSTimer scheduledTimerWithTimeInterval:[self getTime] target:self selector:@selector(loop) userInfo:nil repeats:NO];
}
- (void) loop {
    FuturesViewController *viewController = (FuturesViewController *)self.delegate;
    if(self.isWorking && viewController.isViewLoaded && viewController.view.window) {
	// 是否处于显示状态,显示状态则刷新数据
        [self loadData];
    } else {
        [self start];
    }
}
- (void) httpCallBack:(id)data keyBack:(int)keyBack {
    // 成功处理
    [self data:data];
    if(self.searchValue == nil && self.filter == -1) {
        [NSThread detachNewThreadSelector:@selector(native:) toTarget:self withObject:data];
    }
    [self start];
}
- (void) httpError:(NSError *)error keyBack:(int)keyBack {
    NSString *msg = [error.userInfo objectForKey:@"message"];
    if([msg isEqualToString:@"cancel"]) {
//        NSLog(@"%d 被取消", keyBack);
    } else {
        // 失败处理,提示消息
        [UIUtil msgBox:msg];
    }
    [self start];
}
- (void) native:(NSArray *)data {
    // 处理数据
}

- (void) normal {
    FuturesViewController *futures = (FuturesViewController *)self.delegate;
    for(UITableViewCell *cell in futures.contentTableView.visibleCells) {
        [[self futuresViewInCell:cell] normal];
    }
}
- (FuturesView *) futuresViewInCell:(UITableViewCell *)cell {
    NSArray *subviews = cell.contentView.subviews;
    for(UIView *view in subviews) {
        if([view isKindOfClass:[FuturesView class]]) {
            return (FuturesView *)view;
        }
    }
    return nil;
}

- (void) destory {
    _isWorking = FALSE;
    self.searchValue = nil;
    self.delegate = nil;
    if([self.timer retainCount] > 1) {
        [self.timer invalidate];
    }
    self.timer = nil;
}
- (void) dealloc {
    [self destory];
    [super dealloc];
}

@end



Futures模块主页面调用部分,FuturesViewController.M

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    /* 期货表TITLE */
    FuturesView *titleView = [[FuturesView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 38) byStyle:FuturesStyleTitle];
    [titleView setData:[NSArray arrayWithObjects:@"品种名", @"最新", @"涨跌", @"成交量", @"涨跌幅", @"昨结算", @"昨收", @"持仓量", @"开盘", @"最高", @"最低", nil]];
    [self.view addSubview:titleView];
    [titleView release];
    
    /* 计时器加载数据 */
    _timer = [[FuturesTimer alloc] init];
    self.timer.delegate = self;
}



- (void) viewDidAppear:(BOOL)animated {
    [self.timer work];
}
- (void) destory {
    if(self.isViewLoaded && self.view.window) {
        return;
    }
    [self destory2];
}
- (void) clearTabCell {
    if(self.contentTableView.visibleCells.count > 0) {
        [[self.timer futuresViewInCell:[self.contentTableView.visibleCells objectAtIndex:0]] destory];
    }
}
- (void) destory2 {
    [self.timer destory];
    [self clearTabCell];
    self.timer = nil;
    self.contentTableView = nil;
    self.mainData = nil;
    self.load = nil;
    self.view = nil;
}
- (void) viewDidUnload {
    [self destory];
    [super viewDidUnload];
}
- (void) didReceiveMemoryWarning {
//    NSLog(@"futures didReceiveMemoryWarning called");
    [self destory];
    [super didReceiveMemoryWarning];
}
- (void) dealloc {
    [self destory2];
    [super dealloc];
}



转载于:https://my.oschina.net/5zx1Vm/blog/130071

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值