54

iOS动画折线图

 5 years ago
source link: http://www.cocoachina.com/ios/20180816/24589.html?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

效果图:

iIjuArm.png!web

后端传一个数组,然后根据数组生成点的坐标。所以解析下,我们需要画的有点,点和点之间的线,以及背景和下面的期数时间。最后我们需要加块有效果的红色块,这块要的效果是可以手指点击和滑动区域这个块就在哪个位置的点上。

首先我们需要把几个方法整理出来:

//画点和点之间的线和背景
- (void)drawTimeLine:(CGPoint)point toPoint:(CGPoint)toPoint {
    [self.timeLinePath moveToPoint:point];
    [self.timeLinePath addLineToPoint:toPoint];

    [self.fillPath moveToPoint:point];
    [self.fillPath addLineToPoint:toPoint];

    [self.fillPath addLineToPoint:self.xendPoint];
    [self.fillPath addLineToPoint:self.xstartPoint];

    self.fillColorLayer.path = self.fillPath.CGPath;

    [self.layer addSublayer:self.fillColorLayer];

    self.timeLineLayer.path = self.timeLinePath.CGPath;
    [self.layer addSublayer:self.timeLineLayer];
}

//画点
- (void)setupCircleLayer:(CGPoint)point tag:(NSInteger)tag{
    self.circleLayer = [[CALayer alloc] init];
    self.circleLayer.backgroundColor = [UIColor baseColor].CGColor;
    self.circleLayer.frame = CGRectMake(0, 0, 4, 4);
    self.circleLayer.cornerRadius = 2;
    self.circleLayer.position = point;
    self.circleLayer.masksToBounds = YES;
    [self.layer addSublayer:self.circleLayer];
}

//画文字
- (void)drawLabelAtRect:(CGRect)rect textStr:(NSString*)textStr color:(UIColor *)color {
    CATextLayer *textLayer = [CATextLayer layer];
    textLayer.frame = rect;
    [self.layer addSublayer:textLayer];
    //set text attributes
    textLayer.foregroundColor = color.CGColor;
    textLayer.alignmentMode = kCAAlignmentCenter;
    textLayer.wrapped = YES;
    //choose a font
    UIFont *font = [UIFont systemFontOfSize:10];
    //set layer font
    CFStringRef fontName = (__bridge CFStringRef)font.fontName;
    CGFontRef fontRef = CGFontCreateWithFontName(fontName);
    textLayer.font = fontRef;
    textLayer.fontSize = font.pointSize;
    CGFontRelease(fontRef);
    textLayer.contentsScale = [UIScreen mainScreen].scale;
    //choose some text
    //set layer text
    textLayer.string = textStr;
}

好有了上面3个方法我们基本图形概括就可以画出来了,现在我们需要的是确定坐标。

我们都知道在手机上,左上角是(0,0),而在我们这个坐标中我们想要的是左下角的这个点是我们的(0,0)对不对,所以我们需要一个转换思维的过程,就是我们左下脚的真实坐标可能是(20, 125)而在我们眼里是(0,0)然后去算其他的所有坐标,我不知道这么说能不能理解。

然后后端传给你的是一些比如第几期多少利率之类的数据。所以你先要确定的就是首尾的4个点,然后根据百分比变化去算其他的点,不然没有根据你是算不出来的。如果这些你都理清楚了,那基本就没什么问题了。

接下来说下上面这个动画我们怎么实现,很清晰的一个就是在这个块区域你点击的横坐标x肯定是要和红色块相关的,所有我们要做的就是根据你手指的点击或者滑动的x(横坐标)来显示这个块该在哪,然后就是这个块肯定是和我们点相关的,所以我的做法,是把数组转换出来的坐标存下来,然后根据横坐标X,去确定红色块的Y,而红色块始终是在我们点的上面的,之间的纵坐标的的差距是固定的,这样一分析就很明了,上代码:

- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    UITouch *touch=[touches anyObject];
    CGPoint point = [touch locationInView:self];
    [self showIllabel:point];
}

- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    UITouch *touch=[touches anyObject];
    CGPoint point = [touch locationInView:self];
    [self showIllabel:point];
}

- (void)showIllabel:(CGPoint)point {
    if (self.model.projectPlanNo.length > 0) {
        if (point.x < 20) {
            NSString *firstY = self.pointYArray[0];
            self.illLabel.center = CGPointMake(20, firstY.floatValue - 30);
            KZWdayUpInvestIrrConfigModel *daymodel = self.model.dayUpInvestIrrConfigList[0];
            self.illLabel.text = [NSString stringWithFormat:@"%.1f%%\n第%ld期", daymodel.yearRate*100, daymodel.period];
        }else if (point.x > SCREEN_WIDTH - 15) {
            NSString *endY = self.pointYArray[self.pointYArray.count - 1];
            self.illLabel.center = CGPointMake(SCREEN_WIDTH - 15, endY.floatValue - 30);
            KZWdayUpInvestIrrConfigModel *daymodel = self.model.dayUpInvestIrrConfigList[self.pointYArray.count - 1];
            self.illLabel.text = [NSString stringWithFormat:@"%.1f%%\n第%ld期", daymodel.yearRate*100, daymodel.period];
        }else {
            CGFloat oneWidth = (SCREEN_WIDTH - 35)/(self.model.dayUpInvestIrrConfigList.count - 1);
            NSInteger which = (point.x - 30)/oneWidth;
            if (which < self.pointXArray.count  - 1) {
                NSString *whichY = self.pointYArray[which + 1];
                NSString *whichX = self.pointXArray[which + 1];
                self.illLabel.center = CGPointMake(whichX.floatValue, whichY.floatValue - 30);
                KZWdayUpInvestIrrConfigModel *daymodel = self.model.dayUpInvestIrrConfigList[which + 1];
                self.illLabel.text = [NSString stringWithFormat:@"%.1f%%\n第%ld期", daymodel.yearRate*100, daymodel.period];
            }
        }
    }
}

最后我们是加到tabeleView上的,手势有冲突,解决下:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{
    if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) {
        //满足条件拦截手势
        return YES;
    }
    return NO;
}

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{
    if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) {
        return NO;
    }
    return YES;
}

这样这个折线图就算完成了。

上完整代码:

//
//  KZWRollingView.m
//  kongzhongfinancial
//
//  Created by ouyang on 2018/8/9.
//  Copyright © 2018年 ouy. All rights reserved.
//

#import "KZWRollingView.h"

@interface KZWRollingView()

@property (nonatomic, assign) CGRect rollingFrame;
@property (nonatomic, strong) UIBezierPath *timeLinePath;
@property (nonatomic, strong) CAShapeLayer *timeLineLayer;
@property (nonatomic, strong) UIBezierPath *fillPath;
@property (nonatomic, strong) CAShapeLayer *fillColorLayer;
@property (nonatomic, assign) CGPoint xstartPoint;
@property (nonatomic, assign) CGPoint xendPoint;
@property (nonatomic, strong) CALayer *circleLayer;
@property (nonatomic, strong) UIButton *pointButton;

@property (nonatomic, strong) UILabel *illLabel;
@property (nonatomic, strong) NSMutableArray *pointYArray;
@property (nonatomic, strong) NSMutableArray *pointXArray;

@end

@implementation KZWRollingView

- (instancetype)initWithFrame:(CGRect)frame {
    if (self = [super initWithFrame:frame]) {
        self.pointYArray = [NSMutableArray array];
        self.pointXArray = [NSMutableArray array];
        self.rollingFrame = frame;
        self.xstartPoint = CGPointMake(20, 125);
        self.xendPoint = CGPointMake(SCREEN_WIDTH - 15, 125);
        [self addSubview:self.illLabel];
    }
    return self;
}

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{
    if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) {
        //满足条件拦截手势
        return YES;
    }
    return NO;
}

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{
    if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) {
        return NO;
    }
    return YES;
}

- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    UITouch *touch=[touches anyObject];
    CGPoint point = [touch locationInView:self];
    [self showIllabel:point];
}

- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    UITouch *touch=[touches anyObject];
    CGPoint point = [touch locationInView:self];
    [self showIllabel:point];
}

- (void)showIllabel:(CGPoint)point {
    if (self.model.projectPlanNo.length > 0) {
        if (point.x < 20) {
            NSString *firstY = self.pointYArray[0];
            self.illLabel.center = CGPointMake(20, firstY.floatValue - 30);
            KZWdayUpInvestIrrConfigModel *daymodel = self.model.dayUpInvestIrrConfigList[0];
            self.illLabel.text = [NSString stringWithFormat:@"%.1f%%\n第%ld期", daymodel.yearRate*100, daymodel.period];
        }else if (point.x > SCREEN_WIDTH - 15) {
            NSString *endY = self.pointYArray[self.pointYArray.count - 1];
            self.illLabel.center = CGPointMake(SCREEN_WIDTH - 15, endY.floatValue - 30);
            KZWdayUpInvestIrrConfigModel *daymodel = self.model.dayUpInvestIrrConfigList[self.pointYArray.count - 1];
            self.illLabel.text = [NSString stringWithFormat:@"%.1f%%\n第%ld期", daymodel.yearRate*100, daymodel.period];
        }else {
            CGFloat oneWidth = (SCREEN_WIDTH - 35)/(self.model.dayUpInvestIrrConfigList.count - 1);
            NSInteger which = (point.x - 30)/oneWidth;
            if (which < self.pointXArray.count  - 1) {
                NSString *whichY = self.pointYArray[which + 1];
                NSString *whichX = self.pointXArray[which + 1];
                self.illLabel.center = CGPointMake(whichX.floatValue, whichY.floatValue - 30);
                KZWdayUpInvestIrrConfigModel *daymodel = self.model.dayUpInvestIrrConfigList[which + 1];
                self.illLabel.text = [NSString stringWithFormat:@"%.1f%%\n第%ld期", daymodel.yearRate*100, daymodel.period];
            }
        }
    }
}

- (UILabel *)illLabel {
    if (!_illLabel) {
        _illLabel = [[UILabel alloc] initWithFrame:CGRectMake(8, 40, 45, 30)];
        _illLabel.backgroundColor = [UIColor baseColor];
        _illLabel.textColor = [UIColor whiteColor];
        _illLabel.textAlignment = NSTextAlignmentCenter;
        _illLabel.numberOfLines = 0;
        _illLabel.layer.cornerRadius = 3;
        _illLabel.layer.masksToBounds = YES;
        _illLabel.font = [UIFont systemFontOfSize:9];
        _illLabel.hidden = YES;
    }
    return _illLabel;
}

- (UIBezierPath *)timeLinePath {
    if (!_timeLinePath) {
        _timeLinePath = [[UIBezierPath alloc]init];
    }
    return _timeLinePath;
}

- (CAShapeLayer *)timeLineLayer {
    if (!_timeLineLayer) {
        _timeLineLayer = [[CAShapeLayer alloc]init];
        _timeLineLayer.strokeColor = [UIColor baseColor].CGColor;
        _timeLineLayer.lineWidth = 1.0f;
        _timeLineLayer.fillColor = [UIColor clearColor].CGColor;
    }
    return _timeLineLayer;
}

- (UIBezierPath *)fillPath {
    if (!_fillPath) {
        _fillPath = [[UIBezierPath alloc]init];
    }
    return _fillPath;
}

- (CAShapeLayer *)fillColorLayer {
    if (!_fillColorLayer) {
        _fillColorLayer = [[CAShapeLayer alloc]init];
        _fillColorLayer.fillColor = [[UIColor colorWithHexString:@"ff9933"] colorWithAlphaComponent:0.2].CGColor;
        _fillColorLayer.strokeColor = [UIColor clearColor].CGColor;
    }
    return _fillColorLayer;
}

- (void)drawTimeLine:(CGPoint)point toPoint:(CGPoint)toPoint {
    [self.timeLinePath moveToPoint:point];
    [self.timeLinePath addLineToPoint:toPoint];

    [self.fillPath moveToPoint:point];
    [self.fillPath addLineToPoint:toPoint];

    [self.fillPath addLineToPoint:self.xendPoint];
    [self.fillPath addLineToPoint:self.xstartPoint];

    self.fillColorLayer.path = self.fillPath.CGPath;

    [self.layer addSublayer:self.fillColorLayer];

    self.timeLineLayer.path = self.timeLinePath.CGPath;
    [self.layer addSublayer:self.timeLineLayer];
}

- (void)setupCircleLayer:(CGPoint)point tag:(NSInteger)tag{
    self.circleLayer = [[CALayer alloc] init];
    self.circleLayer.backgroundColor = [UIColor baseColor].CGColor;
    self.circleLayer.frame = CGRectMake(0, 0, 4, 4);
    self.circleLayer.cornerRadius = 2;
    self.circleLayer.position = point;
    self.circleLayer.masksToBounds = YES;
    [self.layer addSublayer:self.circleLayer];
}

- (void)drawLabelAtRect:(CGRect)rect textStr:(NSString*)textStr color:(UIColor *)color {
    CATextLayer *textLayer = [CATextLayer layer];
    textLayer.frame = rect;
    [self.layer addSublayer:textLayer];
    //set text attributes
    textLayer.foregroundColor = color.CGColor;
    textLayer.alignmentMode = kCAAlignmentCenter;
    textLayer.wrapped = YES;
    //choose a font
    UIFont *font = [UIFont systemFontOfSize:10];
    //set layer font
    CFStringRef fontName = (__bridge CFStringRef)font.fontName;
    CGFontRef fontRef = CGFontCreateWithFontName(fontName);
    textLayer.font = fontRef;
    textLayer.fontSize = font.pointSize;
    CGFontRelease(fontRef);
    textLayer.contentsScale = [UIScreen mainScreen].scale;
    //choose some text
    //set layer text
    textLayer.string = textStr;
}

- (void)setModel:(KZWRollingProjectModel *)model {
    if (_model == model) {
        return;
    }
    _model = model;

    [self.pointYArray removeAllObjects];
    [self.pointXArray removeAllObjects];

    NSInteger pointCount = model.dayUpInvestIrrConfigList.count;
    if (pointCount > 0) {
        CGPoint firstPoint = CGPointMake(20, 90);
        for (int i = 0; i < model.dayUpInvestIrrConfigList.count; i ++) {
            KZWdayUpInvestIrrConfigModel *daymdoel = model.dayUpInvestIrrConfigList[i];
            CGPoint point = CGPointMake(20 + i*(SCREEN_WIDTH - 35)/(pointCount - 1), 90 - (daymdoel.yearRate - model.baseIrrRate)/model.maxAddIrrRate*60);
            [self drawTimeLine:firstPoint toPoint:point];
            firstPoint = point;
            [self.pointYArray addObject:[NSString stringWithFormat:@"%.2f", point.y]];
            [self.pointXArray addObject:[NSString stringWithFormat:@"%.2f", point.x]];

            [self setupCircleLayer:point tag:i];
            if (daymdoel.desc.length > 0) {
                [self drawLabelAtRect:CGRectMake(point.x - 15, point.y - 15, 30, 10) textStr:[NSString stringWithFormat:@"%.1f%%", daymdoel.yearRate*100] color:[UIColor baseColor]];
                [self drawLabelAtRect:CGRectMake(point.x - 16, 125, 32, 36) textStr:[NSString stringWithFormat:@"%@\n%ld天", daymdoel.desc, model.cycleDuration] color:[UIColor colorWithHexString:FontColor666666]];
            }
        }
    }
    self.illLabel.hidden = NO;
    KZWdayUpInvestIrrConfigModel *firstdaymodel = self.model.dayUpInvestIrrConfigList[0];
    self.illLabel.text = [NSString stringWithFormat:@"%.1f%%\n第%ld期", firstdaymodel.yearRate*100, firstdaymodel.period];
}

@end

所以一些效果和动画真正难的是坐标和分析,而不是实现。

作者:moonCoder

链接:https://www.jianshu.com/p/303ecfab6f20


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK