本文来自简书,原文地址:http://www.jianshu.com/p/7e8d3b845331
前言
最近项目和股票有关,自然而然想起了分时线,K线等东西.即使是出自自己手里的东西,放久了难觅看忘记,特别是当时的想法和逻辑思维过程.既然写了,总要留下点什么,于是有了这篇笔记.
先看看最后结果吧.此图确实不够美观,但是毕竟只是一个demo,一个骨架而已,具体的血肉需要大家自己根据需要去填充.
1.png
画分时线,我们需要做些什么?
画框架(网格线);横坐标上的文字(时间轴);纵坐标上的文字(左边价格,右边涨跌率);画分时线;心跳效果;添加手势(长按和点击);画十字交叉线;画十字交叉线与横纵坐标交点处的文字;
下面一步步来实现上面的效果吧
0.工欲善其事必先利其器,先来抽几个方法吧
心跳效果
- (void)heartAnimationWithLayer:(CALayer*)layer {
CAAnimationGroup *group = [[CAAnimationGroup alloc]init]
group.duration =
0.
5
group.repeatCount = HUGE
CABasicAnimation *
scaleAnim = [CABasicAnimation animationWithKeyPath:@
"transform.scale"]
scaleAnim.toValue = @
1.
2
CABasicAnimation *alphaAnim = [CABasicAnimation animationWithKeyPath:@
"opacity"]
alphaAnim.toValue = @
0.
3f
group.animations = @[
scaleAnim,alphaAnim];
[layer
addAnimation:group forKey:nil]
}
坐标轴的转换
-(
CGFloat)miniteTimeWithTimeStr:(
NSString*)timeStr {
if (timeStr ==
nil || [timeStr isEqualToString:
@""])
return 0.0;
NSArray *temp = [timeStr componentsSeparatedByString:
@":"];
NSInteger minte = [temp[
0] integerValue]*
60 + [temp[
1] integerValue];
CGFloat aveWidth = DPW/
240.0;
if (minte <=
11*
60+
30) {
return aveWidth*(minte -
9*
60-30);
}
else {
return DPW *
0.5 + aveWidth*(minte -
13*
60);
}
}
-(
NSString*)timeWithPoint:(
CGPoint)point{
NSString *str =
@"";
CGFloat aveWidth =
240.0/DPW;
CGFloat totalTime = aveWidth * point.x +
9*
60 +
30;
if (point.x >DPW *
0.5) {
totalTime = aveWidth * point.x +
11*
60;
}
int h = totalTime /
60;
int m = ((
int)(totalTime +
0.5)) %
60;
str = [
NSString stringWithFormat:
@"%d:%d",h,m];
return str;
}
- (
CGFloat)priceLabelLocationWithPrice:(
CGFloat)price {
CGFloat height = DPH -
60;
CGFloat avrSpace = height/(
self.max -
self.min);
return height - ((price -
self.min)*avrSpace);
}
- (
NSString*)pricWithPoint:(
CGPoint)point {
NSString *price =
@"";
CGFloat avePrice = (
self.max -
self.min)/(DPH -
60);
price = [
NSString stringWithFormat:
@"%.2f",(
self.max - point.y*avePrice)+
0.005];
return price;
}
画文字
- (
void)drawLabelAtRect:(
CGRect)rect textStr:(
NSString*)textStr {
CATextLayer *textLayer = [
CATextLayer layer];
textLayer.frame = rect;
[
self.layer addSublayer:textLayer];
textLayer.foregroundColor = [
UIColor blackColor].CGColor;
textLayer.alignmentMode = kCAAlignmentJustified;
textLayer.wrapped =
YES;
UIFont *font = [
UIFont systemFontOfSize:
10];
CFStringRef fontName = (__bridge
CFStringRef)font.fontName;
CGFontRef fontRef =
CGFontCreateWithFontName(fontName);
textLayer.font = fontRef;
textLayer.fontSize = font.pointSize;
CGFontRelease(fontRef);
textLayer.contentsScale = [
UIScreen mainScreen].scale;
textLayer.string = textStr;
}
- (
void)drawCrossLabelWithTextLayer:(
CATextLayer*)textLayer AtRect:(
CGRect)rect textStr:(
NSString*)textStr {
textLayer.frame = rect;
[
self.layer addSublayer:textLayer];
textLayer.foregroundColor = [
UIColor blackColor].CGColor;
textLayer.alignmentMode = kCAAlignmentJustified;
textLayer.wrapped =
YES;
UIFont *font = [
UIFont systemFontOfSize:
10];
CFStringRef fontName = (__bridge
CFStringRef)font.fontName;
CGFontRef fontRef =
CGFontCreateWithFontName(fontName);
textLayer.font = fontRef;
textLayer.fontSize = font.pointSize;
CGFontRelease(fontRef);
textLayer.contentsScale = [
UIScreen mainScreen].scale;
textLayer.string = textStr;
}
1.获取纵坐标的最大值,最小值和中间值
说明:
横线:分时线最中间的横线对应昨日收盘价,这是固定的.但是,其他横线是根据数据实时变化的,旨在包含所有的数据点.所以,max = mid + 最大偏差;min = mid - 最大偏差;最大偏差=所有数据中偏离mid最大的价格与mid之间差值的绝对值.这样max - min 为价格的波动范围,有了这个就可以根据需要,画出横线(这里画了3条横线);
竖线: 股票交易时间,上午9:30到11:30,下午13:00到15:00,总共4个小时;这里就可以算出单位距离代表的时间,从而确定每个时间节点在横坐标上的位置,画出横坐标.同理,也可算出每分钟代表的长度,这点在画十字交叉线与X轴的交点文字时用的到.对应的方法见上面已抽取的.
分时线: 可以看到在这个方法中已近开始划线了.划线无非就是连线,moveToPoint 和addLineToPoint.为了避免再次遍历所有数据,所以在确定最大和最小价格的循环中就开始添加线;
- (
void)preworkForData {
DPTimeLineItem *temp =
self.dataArrM[
0];
self.mid = [temp.pre_close_px doubleValue];
if ([temp.last_px doubleValue] -[temp.pre_close_px doubleValue] >
0) {
self.max = [temp.last_px doubleValue];
self.min = [temp.pre_close_px doubleValue] -([temp.last_px doubleValue] -[temp.pre_close_px doubleValue] );
}
else {
self.min = [temp.last_px doubleValue];
self.max = [temp.pre_close_px doubleValue] + ([temp.pre_close_px doubleValue] -[temp.last_px doubleValue] );
}
for (
int i =
0; i<
self.dataArrM.count; i ++ ) {
DPTimeLineItem *item =
self.dataArrM[i];
if (fabs(item.last_px.doubleValue -
self.mid) >(
self.max -
self.mid)) {
self.max =
self.mid +fabs(item.last_px.doubleValue -
self.mid);
self.min =
self.mid - fabs(item.last_px.doubleValue -
self.mid);
}
CGFloat timeX = [
self miniteTimeWithTimeStr:item.curr_time];
CGFloat priceY = [
self priceLabelLocationWithPrice:item.last_px.floatValue];
if (i ==
0) {
if (
self.isNeedBackGroundColor) {
[
self.timeLinePath moveToPoint:
CGPointMake(
0, DPH -
60)];
[
self.timeLinePath addLineToPoint:
CGPointMake(timeX, priceY)];
}
else {
[
self.timeLinePath moveToPoint:
CGPointMake(timeX, priceY)];
}
}
if (i ==
self.dataArrM.count
-1) {
self.currentPoint =
CGPointMake(timeX, priceY);
}
[
self.timeLinePath addLineToPoint:
CGPointMake(timeX, priceY)];
}
}
2.画网格线
说明:
利用for循环,画横竖线;横纵坐标固定地方画文字
- (
void)drawFramework {
UIBezierPath *path = [[
UIBezierPath alloc]init];
CGFloat rowSpace = (DPH
-60.0)/
2.0;
NSString *tempStr =
@"";
for (
int i =
0; i <
3; i ++) {
[path moveToPoint:
CGPointMake(
0,rowSpace*i)];
[path addLineToPoint:
CGPointMake(DPW, rowSpace*i)];
if (
0 == i) {
tempStr = [
NSString stringWithFormat:
@"%.2f",
self.max];
}
else if (
1==i) {
tempStr = [
NSString stringWithFormat:
@"%.2f",
self.mid];
}
else if (
2 == i) {
tempStr = [
NSString stringWithFormat:
@"%.2f",
self.min];
}
[
self drawLabelAtRect:
CGRectMake(
-25, rowSpace*i
-10,
25,
20) textStr:tempStr];
}
CGFloat colSpace = DPW /
4.0;
for (
int i =
0; i <
5; i ++) {
[path moveToPoint:
CGPointMake(colSpace*i,
0)];
[path addLineToPoint:
CGPointMake(colSpace*i, DPH
-60)];
if (
0 == i) {
tempStr =
@"9:30";
[
self drawLabelAtRect:
CGRectMake(colSpace*i, DPH
-60 ,
30,
20) textStr:tempStr];
continue;
}
else if (
1==i) {
tempStr =
@"10:30";
}
else if (
2 == i) {
tempStr =
@"11:30/13:00";
[
self drawLabelAtRect:
CGRectMake(colSpace*i
-30, DPH
-60 ,
70,
20) textStr:tempStr];
continue;
}
else if (
3==i) {
tempStr =
@"14:00";
}
else if (
4 == i) {
tempStr =
@"15:00";
[
self drawLabelAtRect:
CGRectMake(colSpace*i -
30, DPH
-60 ,
30,
20) textStr:tempStr];
continue;
}
[
self drawLabelAtRect:
CGRectMake(colSpace*i
-15, DPH
-60 ,
35,
20) textStr:tempStr];
}
CAShapeLayer *shapeLayer = [[
CAShapeLayer alloc]init];
shapeLayer.strokeColor = [
UIColor lightGrayColor].CGColor;
shapeLayer.path = path.CGPath;
[
self.layer addSublayer:shapeLayer];
}
3.画坐标轴上的文字
见2.画网格线
4.画分时线
说明:这里通过isNeedBackGroundColor控制是否画背景
- (
void)drawTimeLine {
if (
self.isNeedBackGroundColor) {
[
self.timeLinePath addLineToPoint:
CGPointMake(
self.currentPoint.x , DPH -
60)];
self.timeLineLayer.fillColor = [
UIColor lightGrayColor].CGColor;
}
else {
self.timeLineLayer.fillColor = [
UIColor clearColor].CGColor;
}
self.timeLineLayer.path =
self.timeLinePath.CGPath;
[
self.layer addSublayer:
self.timeLineLayer];
}
5.心跳效果
- (
void)setupheartLayer {
self.heartLayer.frame =
CGRectMake(
0,
0,
4,
4);
self.heartLayer.position =
self.currentPoint;
self.heartLayer.cornerRadius = _heartLayer.frame.size.width*
0.5;
self.heartLayer.masksToBounds =
YES;
[
self.layer addSublayer:
self.heartLayer];
[
self heartAnimationWithLayer:
self.heartLayer];
}
6.添加手势
说明:
长按手势 :触发方法画十字交叉线及其与坐标轴的交叉点文字
点击手势: 影藏十字交叉线及对应文字
- (
void)setupGestureRecognize {
UILongPressGestureRecognizer *longPress = [[
UILongPressGestureRecognizer alloc]initWithTarget:
self action:
@selector(longPressAction:)];
[
self addGestureRecognizer:longPress];
UITapGestureRecognizer *tap = [[
UITapGestureRecognizer alloc]initWithTarget:
self action:
@selector(tap:)];
[
self addGestureRecognizer:tap];
}
- (
void)longPressAction:(
UILongPressGestureRecognizer*)gesture {
CGPoint tempPoint = [gesture locationInView:
self];
if (tempPoint.x >= DPW) {
tempPoint =
CGPointMake(DPW, tempPoint.y);
}
if (tempPoint.x <=
0.0) {
tempPoint =
CGPointMake(
0, tempPoint.y);
}
if (tempPoint.y >= DPH -
60) {
tempPoint =
CGPointMake(tempPoint.x, DPH
-60);
}
if (tempPoint.y <=
0.0) {
tempPoint =
CGPointMake(tempPoint.x,
0);
}
if (gesture.state ==
UIGestureRecognizerStateBegan) {
[
self drawCrossLineWithPoint:tempPoint];
}
else if (gesture.state ==
UIGestureRecognizerStateChanged) {
[
self drawCrossLineWithPoint:tempPoint];
}
else if (gesture.state ==
UIGestureRecognizerStateEnded) {
}
}
- (
void)tap:(
UITapGestureRecognizer*) gesture {
self.crossLayer.path =
nil;
[
self.crossPriceLayer removeFromSuperlayer];
[
self.crossTimeLayer removeFromSuperlayer];
}
完整代码 拿走不谢
#import "DPTimeLineView.h"
#import "DPTimeLineItem.h"
#define DPW self.frame.size.width
#define DPH self.frame.size.height
@interface DPTimeLineView ()
@property (
nonatomic,
assign)
double max;
@property (
nonatomic,
assign)
double mid;
@property (
nonatomic,
assign)
double min;
@property (
nonatomic,
strong)
UIBezierPath *timeLinePath;
@property (
nonatomic,
assign)
CGPoint currentPoint;
@property (
nonatomic,
assign)
BOOL isNeedBackGroundColor;
@property (
nonatomic,
strong)
CALayer *heartLayer;
@property (
nonatomic,
strong)
CAShapeLayer *timeLineLayer;
@property (
nonatomic,
strong)
CAShapeLayer *crossLayer;
@property (
nonatomic,
strong)
CATextLayer *crossTimeLayer;
@property (
nonatomic,
strong)
CATextLayer *crossPriceLayer;
@end
@implementation DPTimeLineView
#pragma mark - 入口
- (
instancetype)initWithFrame:(
CGRect)frame {
if (
self = [
super initWithFrame:frame]) {
self.backgroundColor = [
UIColor whiteColor];
[
self setupGestureRecognize];
}
return self;
}
- (
instancetype)initWithCoder:(
NSCoder *)aDecoder {
if (
self = [
super initWithCoder:aDecoder]) {
self.backgroundColor = [
UIColor whiteColor];
[
self setupGestureRecognize];
}
return self;
}
#pragma mark - 懒加载
- (
UIBezierPath *)timeLinePath {
if (!_timeLinePath) {
_timeLinePath = [[
UIBezierPath alloc]init];
}
return _timeLinePath;
}
- (
CALayer *)heartLayer {
if (!_heartLayer) {
_heartLayer = [
CALayer layer];
_heartLayer.backgroundColor = [
UIColor blueColor].CGColor;
}
return _heartLayer;
}
- (
CAShapeLayer *)timeLineLayer {
if (!_timeLineLayer) {
_timeLineLayer = [[
CAShapeLayer alloc]init];
_timeLineLayer.strokeColor = [
UIColor redColor].CGColor;
_timeLineLayer.lineWidth =
0.5f;
}
return _timeLineLayer;
}
- (
CAShapeLayer *)crossLayer {
if (!_crossLayer) {
_crossLayer =[[
CAShapeLayer alloc]init];
_crossLayer.lineDashPattern = @[@
1, @
2];
}
return _crossLayer;
}
- (
CATextLayer *)crossPriceLayer {
if (!_crossPriceLayer) {
_crossPriceLayer = [[
CATextLayer alloc]init];
}
return _crossPriceLayer;
}
- (
CATextLayer *)crossTimeLayer {
if (!_crossTimeLayer) {
_crossTimeLayer = [[
CATextLayer alloc]init];
}
return _crossTimeLayer;
}
#pragma mark - GestureRecognize
- (
void)setupGestureRecognize {
UILongPressGestureRecognizer *longPress = [[
UILongPressGestureRecognizer alloc]initWithTarget:
self action:
@selector(longPressAction:)];
[
self addGestureRecognizer:longPress];
UITapGestureRecognizer *tap = [[
UITapGestureRecognizer alloc]initWithTarget:
self action:
@selector(tap:)];
[
self addGestureRecognizer:tap];
}
- (
void)longPressAction:(
UILongPressGestureRecognizer*)gesture {
CGPoint tempPoint = [gesture locationInView:
self];
if (tempPoint.x >= DPW) {
tempPoint =
CGPointMake(DPW, tempPoint.y);
}
if (tempPoint.x <=
0.0) {
tempPoint =
CGPointMake(
0, tempPoint.y);
}
if (tempPoint.y >= DPH -
60) {
tempPoint =
CGPointMake(tempPoint.x, DPH
-60);
}
if (tempPoint.y <=
0.0) {
tempPoint =
CGPointMake(tempPoint.x,
0);
}
if (gesture.state ==
UIGestureRecognizerStateBegan) {
[
self drawCrossLineWithPoint:tempPoint];
}
else if (gesture.state ==
UIGestureRecognizerStateChanged) {
[
self drawCrossLineWithPoint:tempPoint];
}
else if (gesture.state ==
UIGestureRecognizerStateEnded) {
}
}
- (
void)tap:(
UITapGestureRecognizer*) gesture {
self.crossLayer.path =
nil;
[
self.crossPriceLayer removeFromSuperlayer];
[
self.crossTimeLayer removeFromSuperlayer];
}
#pragma mark - 数据入口
- (
void)setDataArrM:(
NSMutableArray<DPTimeLineItem *> *)dataArrM {
_dataArrM = dataArrM;
[
self preworkForData];
[
self drawFramework];
[
self drawTimeLine];
[
self setupheartLayer];
}
#pragma mark - 画图方法
- (
void)drawTimeLine {
if (
self.isNeedBackGroundColor) {
[
self.timeLinePath addLineToPoint:
CGPointMake(
self.currentPoint.x , DPH -
60)];
self.timeLineLayer.fillColor = [
UIColor lightGrayColor].CGColor;
}
else {
self.timeLineLayer.fillColor = [
UIColor clearColor].CGColor;
}
self.timeLineLayer.path =
self.timeLinePath.CGPath;
[
self.layer addSublayer:
self.timeLineLayer];
}
- (
void)drawFramework {
UIBezierPath *path = [[
UIBezierPath alloc]init];
CGFloat rowSpace = (DPH
-60.0)/
2.0;
NSString *tempStr =
@"";
for (
int i =
0; i <
3; i ++) {
[path moveToPoint:
CGPointMake(
0,rowSpace*i)];
[path addLineToPoint:
CGPointMake(DPW, rowSpace*i)];
if (
0 == i) {
tempStr = [
NSString stringWithFormat:
@"%.2f",
self.max];
}
else if (
1==i) {
tempStr = [
NSString stringWithFormat:
@"%.2f",
self.mid];
}
else if (
2 == i) {
tempStr = [
NSString stringWithFormat:
@"%.2f",
self.min];
}
[
self drawLabelAtRect:
CGRectMake(
-25, rowSpace*i
-10,
25,
20) textStr:tempStr];
}
CGFloat colSpace = DPW /
4.0;
for (
int i =
0; i <
5; i ++) {
[path moveToPoint:
CGPointMake(colSpace*i,
0)];
[path addLineToPoint:
CGPointMake(colSpace*i, DPH
-60)];
if (
0 == i) {
tempStr =
@"9:30";
[
self drawLabelAtRect:
CGRectMake(colSpace*i, DPH
-60 ,
30,
20) textStr:tempStr];
continue;
}
else if (
1==i) {
tempStr =
@"10:30";
}
else if (
2 == i) {
tempStr =
@"11:30/13:00";
[
self drawLabelAtRect:
CGRectMake(colSpace*i
-30, DPH
-60 ,
70,
20) textStr:tempStr];
continue;
}
else if (
3==i) {
tempStr =
@"14:00";
}
else if (
4 == i) {
tempStr =
@"15:00";
[
self drawLabelAtRect:
CGRectMake(colSpace*i -
30, DPH
-60 ,
30,
20) textStr:tempStr];
continue;
}
[
self drawLabelAtRect:
CGRectMake(colSpace*i
-15, DPH
-60 ,
35,
20) textStr:tempStr];
}
CAShapeLayer *shapeLayer = [[
CAShapeLayer alloc]init];
shapeLayer.strokeColor = [
UIColor lightGrayColor].CGColor;
shapeLayer.path = path.CGPath;
[
self.layer addSublayer:shapeLayer];
}
- (
void)drawLabelAtRect:(
CGRect)rect textStr:(
NSString*)textStr {
CATextLayer *textLayer = [
CATextLayer layer];
textLayer.frame = rect;
[
self.layer addSublayer:textLayer];
textLayer.foregroundColor = [
UIColor blackColor].CGColor;
textLayer.alignmentMode = kCAAlignmentJustified;
textLayer.wrapped =
YES;
UIFont *font = [
UIFont systemFontOfSize:
10];
CFStringRef fontName = (__bridge
CFStringRef)font.fontName;
CGFontRef fontRef =
CGFontCreateWithFontName(fontName);
textLayer.font = fontRef;
textLayer.fontSize = font.pointSize;
CGFontRelease(fontRef);
textLayer.contentsScale = [
UIScreen mainScreen].scale;
textLayer.string = textStr;
}
- (
void)drawCrossLabelWithTextLayer:(
CATextLayer*)textLayer AtRect:(
CGRect)rect textStr:(
NSString*)textStr {
textLayer.frame = rect;
[
self.layer addSublayer:textLayer];
textLayer.foregroundColor = [
UIColor blackColor].CGColor;
textLayer.alignmentMode = kCAAlignmentJustified;
textLayer.wrapped =
YES;
UIFont *font = [
UIFont systemFontOfSize:
10];
CFStringRef fontName = (__bridge
CFStringRef)font.fontName;
CGFontRef fontRef =
CGFontCreateWithFontName(fontName);
textLayer.font = fontRef;
textLayer.fontSize = font.pointSize;
CGFontRelease(fontRef);
textLayer.contentsScale = [
UIScreen mainScreen].scale;
textLayer.string = textStr;
}
- (
void)drawCrossLineWithPoint:(
CGPoint)point {
UIBezierPath * path = [[
UIBezierPath alloc]init];
[path moveToPoint:
CGPointMake(point.x,
0)];
[path addLineToPoint:
CGPointMake(point.x, DPH -
60)];
[path moveToPoint:
CGPointMake(
0, point.y)];
[path addLineToPoint:
CGPointMake(DPH, point.y)];
self.crossLayer.strokeColor = [
UIColor blueColor].CGColor;
self.crossLayer.path = path.CGPath;
[
self.layer addSublayer:
self.crossLayer];
NSString *price = [
self pricWithPoint:point];
NSString *time = [
self timeWithPoint:point];
[
self drawCrossLabelWithTextLayer:
self.crossTimeLayer AtRect:
CGRectMake(point.x, DPH
-60,
30,
20) textStr:time];
[
self drawCrossLabelWithTextLayer:
self.crossPriceLayer AtRect:
CGRectMake(
0, point.y,
30,
20) textStr:price];
}
- (
void)setupheartLayer {
self.heartLayer.frame =
CGRectMake(
0,
0,
4,
4);
self.heartLayer.position =
self.currentPoint;
self.heartLayer.cornerRadius = _heartLayer.frame.size.width*
0.5;
self.heartLayer.masksToBounds =
YES;
[
self.layer addSublayer:
self.heartLayer];
[
self heartAnimationWithLayer:
self.heartLayer];
}
#pragma mark - Others
- (
void)preworkForData {
DPTimeLineItem *temp =
self.dataArrM[
0];
self.mid = [temp.pre_close_px doubleValue];
if ([temp.last_px doubleValue] -[temp.pre_close_px doubleValue] >
0) {
self.max = [temp.last_px doubleValue];
self.min = [temp.pre_close_px doubleValue] -([temp.last_px doubleValue] -[temp.pre_close_px doubleValue] );
}
else {
self.min = [temp.last_px doubleValue];
self.max = [temp.pre_close_px doubleValue] + ([temp.pre_close_px doubleValue] -[temp.last_px doubleValue] );
}
for (
int i =
0; i<
self.dataArrM.count; i ++ ) {
DPTimeLineItem *item =
self.dataArrM[i];
if (fabs(item.last_px.doubleValue -
self.mid) >(
self.max -
self.mid)) {
self.max =
self.mid +fabs(item.last_px.doubleValue -
self.mid);
self.min =
self.mid - fabs(item.last_px.doubleValue -
self.mid);
}
CGFloat timeX = [
self miniteTimeWithTimeStr:item.curr_time];
CGFloat priceY = [
self priceLabelLocationWithPrice:item.last_px.floatValue];
if (i ==
0) {
if (
self.isNeedBackGroundColor) {
[
self.timeLinePath moveToPoint:
CGPointMake(
0, DPH -
60)];
[
self.timeLinePath addLineToPoint:
CGPointMake(timeX, priceY)];
}
else {
[
self.timeLinePath moveToPoint:
CGPointMake(timeX, priceY)];
}
}
if (i ==
self.dataArrM.count
-1) {
self.currentPoint =
CGPointMake(timeX, priceY);
}
[
self.timeLinePath addLineToPoint:
CGPointMake(timeX, priceY)];
}
}
-(
CGFloat)miniteTimeWithTimeStr:(
NSString*)timeStr {
if (timeStr ==
nil || [timeStr isEqualToString:
@""])
return 0.0;
NSArray *temp = [timeStr componentsSeparatedByString:
@":"];
NSInteger minte = [temp[
0] integerValue]*
60 + [temp[
1] integerValue];
CGFloat aveWidth = DPW/
240.0;
if (minte <=
11*
60+
30) {
return aveWidth*(minte -
9*
60-30);
}
else {
return DPW *
0.5 + aveWidth*(minte -
13*
60);
}
}
-(
NSString*)timeWithPoint:(
CGPoint)point{
NSString *str =
@"";
CGFloat aveWidth =
240.0/DPW;
CGFloat totalTime = aveWidth * point.x +
9*
60 +
30;
if (point.x >DPW *
0.5) {
totalTime = aveWidth * point.x +
11*
60;
}
int h = totalTime /
60;
int m = ((
int)(totalTime +
0.5)) %
60;
str = [
NSString stringWithFormat:
@"%d:%d",h,m];
return str;
}
- (
CGFloat)priceLabelLocationWithPrice:(
CGFloat)price {
CGFloat height = DPH -
60;
CGFloat avrSpace = height/(
self.max -
self.min);
return height - ((price -
self.min)*avrSpace);
}
- (
NSString*)pricWithPoint:(
CGPoint)point {
NSString *price =
@"";
CGFloat avePrice = (
self.max -
self.min)/(DPH -
60);
price = [
NSString stringWithFormat:
@"%.2f",(
self.max - point.y*avePrice)+
0.005];
return price;
}
- (
void)heartAnimationWithLayer:(
CALayer*)layer {
CAAnimationGroup *group = [[
CAAnimationGroup alloc]init];
group.duration =
0.5;
group.repeatCount = HUGE;
CABasicAnimation *scaleAnim = [
CABasicAnimation animationWithKeyPath:
@"transform.scale"];
scaleAnim.toValue = @
1.2;
CABasicAnimation *alphaAnim = [
CABasicAnimation animationWithKeyPath:
@"opacity"];
alphaAnim.toValue = @
0.3f;
group.animations = @[scaleAnim,alphaAnim];
[layer addAnimation:group forKey:
nil];
}
提供一个数据入口,每次收到数据就重新划线
@class DPTimeLineItem;
@interface DPTimeLineView : UIView
@property (
nonatomic,
strong)
NSMutableArray<DPTimeLineItem*> *dataArrM;
@end
#pragma mark - 数据入口
- (
void)setDataArrM:(
NSMutableArray<DPTimeLineItem *> *)dataArrM {
_dataArrM = dataArrM;
[
self preworkForData];
[
self drawFramework];
[
self drawTimeLine];
[
self setupheartLayer];
}
备注:本文中之所以主要使用CAShapeLayer来画线,主要在于它的以下优势;
渲染快,采用硬件加速,比用Core Graphics快很多;
高效使用内存,由于不需要像普通layer那样创建寄宿图,所以无论改layer多大,都不要占用太多内存;
超出图层依然可以绘图,不会被图层边界裁剪掉;
不会出现像素化, CAShapeLayer在做3D变换时,不会像普通有寄宿图的CALayer那样变得像素画.