ios - UIBezierPath 在上一条路径之上绘制?

标签 ios objective-c graph draw uibezierpath

我正在尝试自定义 EChart,这是一个 Github 上的条形图库,用于我自己的目的。在这个文件中:https://github.com/zhuhuihuihui/EChart/blob/master/EChart/EColumn.m

我正在尝试修改 setGrade: 方法,这样它就不会从图表的底部向上重新绘制整个条形图,而是只会在条形图的顶部绘制到下一个所需的条形图图表中的 Y 位置。我在下面附上了一个 GIF 以显示我遇到的问题。

这是绘制此条形图的代码(连同其下方的 CABasicAnimation):

-(void)setGrade:(float)grade {
    _grade = grade;
    UIBezierPath *progressline = [UIBezierPath bezierPath];

    [progressline moveToPoint:CGPointMake(self.frame.size.width/2.0, self.frame.size.height)];
    [progressline addLineToPoint:CGPointMake(self.frame.size.width/2.0, (1 - grade) * self.frame.size.height)];
    _chartLine.path = progressline.CGPath;
    _chartLine.strokeEnd = 1.0;

    CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
    pathAnimation.duration = 1.0;
    pathAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    pathAnimation.fromValue = [NSNumber numberWithFloat:0.0f];
    pathAnimation.toValue = [NSNumber numberWithFloat:1.0f];
    [_chartLine addAnimation:pathAnimation forKey:@"strokeEndAnimation"];
}

此代码是从 EColumnChart.m ( https://github.com/zhuhuihuihui/EChart/blob/master/EChart/EColumnChart.m ) 调用的 这是相关的部分,第一个 if 只是第一次初始化一个柱,第二个我定制为只更新值,调用 setGrade: 方法

        if (nil == eColumn) {
            eColumn = [[EColumn alloc] initWithFrame:CGRectMake(widthOfTheColumnShouldBe * 0.5 + (i * widthOfTheColumnShouldBe * 1.5), 0, widthOfTheColumnShouldBe, self.frame.size.height)];
            eColumn.shouldAnimate = NO;
            eColumn.backgroundColor = [UIColor clearColor];
            eColumn.grade = eColumnDataModel.value / _fullValueOfTheGraph;
            eColumn.eColumnDataModel = eColumnDataModel;
            [eColumn setDelegate:self];
            [self addSubview:eColumn];
        } else {
            eColumn.shouldAnimate = YES;
            eColumn.grade = eColumnDataModel.value / _fullValueOfTheGraph;
        }
        [_eColumns setObject:eColumn forKey:[NSNumber numberWithInteger:currentIndex ]];

_fullValueOfTheGraph 有自己的算法来确定应该在图表上绘制多远的条形图。 eColumnDataModel.value 只是我给它的一个整数,它是条形列的 Y 值。

我对贝塞尔曲线路径非常陌生。是使贝塞尔曲线路径成为 ivar 并以某种方式跟踪顶部位置的技巧吗?

enter image description here

更新: 我曾尝试在 setGrade: 方法的开头部分使用此代码,但它只会在上次更新和当前更新之间产生细微差别。我添加了一个 prevGrade ivar,这是用于更新栏的最后一个等级。它很接近,但好像我需要组合贝塞尔曲线路径才能获得完整的条形。有什么想法吗?

         UIBezierPath *_progressline = [UIBezierPath bezierPath];
         if (_prevGrade != 0.0f) {
         if (grade < _prevGrade) { //Bar graph going down
         [_progressline moveToPoint:CGPointMake(self.frame.size.width/2.0, (1 + _prevGrade) * self.frame.size.height)];
         } else { //Bar graph going up
         [_progressline moveToPoint:CGPointMake(self.frame.size.width/2.0, (1 - _prevGrade) * self.frame.size.height)];
         }
         } else {
         [_progressline moveToPoint:CGPointMake(self.frame.size.width/2.0, self.frame.size.height)];
         }
         [_progressline addLineToPoint:CGPointMake(self.frame.size.width/2.0, (1 - grade) * self.frame.size.height)];

最佳答案

我认为您需要的是 CAShapeLayer 的动画 path 而不是 strokeEnd。我一直在测试您共享的代码库中的代码,并进行了一些更改以使 _chartLine 具有动画效果。

这是setGrade:方法的代码

-(void)setGrade:(float)grade
{
    _grade = grade;

    if(_chartLine.path == nil)
    {
        UIBezierPath *_progressline = [UIBezierPath bezierPath];
        if (_prevGrade != 0.0f) {
            if (grade < _prevGrade) { //Bar graph going down
                [_progressline moveToPoint:CGPointMake(self.frame.size.width/2.0, (1 + _prevGrade) * self.frame.size.height)];
            } else { //Bar graph going up
                [_progressline moveToPoint:CGPointMake(self.frame.size.width/2.0, (1 - _prevGrade) * self.frame.size.height)];
            }
        } else {
            [_progressline moveToPoint:CGPointMake(self.frame.size.width/2.0, self.frame.size.height)];
        }
        [_progressline addLineToPoint:CGPointMake(self.frame.size.width/2.0, (1 - grade) * self.frame.size.height)];

        _chartLine.path = _progressline.CGPath;
        _chartLine.strokeEnd = 1.0;
    }else
    {

        CAKeyframeAnimation *morph = [CAKeyframeAnimation animationWithKeyPath:@"path"];
        morph.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
        morph.values = [self getPathValuesForAnimation:_chartLine startGrade:_prevGrade neededGrade:_grade];
        morph.duration = 1;
        morph.removedOnCompletion = YES;
        morph.fillMode = kCAFillModeForwards;
        morph.delegate = self;
        [_chartLine addAnimation:morph forKey:@"pathAnimation"];
        _chartLine.path = (__bridge CGPathRef _Nullable)((id)[morph.values lastObject]);
    }

    _prevGrade = grade;
}


//this method return values for path animation

-(NSArray*)getPathValuesForAnimation:(CAShapeLayer*)layer startGrade:(float)currentGrade neededGrade:(float)neededGrade
{

    NSMutableArray * values = [NSMutableArray array];
    if(_prevGrade != 0.0f)
        [values addObject:(id)layer.path];

    UIBezierPath * finalPath = [UIBezierPath bezierPath];

    [finalPath moveToPoint:CGPointMake(self.frame.size.width/2.0, self.frame.size.height)];
    [finalPath addLineToPoint:CGPointMake(self.frame.size.width/2.0,(1 - neededGrade)*self.frame.size.height)];

    [values addObject:(id)[finalPath CGPath]];

    return values;
}

我希望这对你有帮助,因为我工作得很好,问候

这对我来说是这样的,(我的 gif 导出器不好,所以你看到的所有故障都是我的 gif 导出器的问题)

这是 _chartLine.lineCap = kCALineCapButt;

enter image description here

这是 _chartLine.lineCap = kCALineCapRound;

enter image description here

关于ios - UIBezierPath 在上一条路径之上绘制?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37663276/

相关文章:

ios - 在 Swift 5 中从数组创建字典

ios - Cordova/iOS:如何关闭使用InAppBrowser打开的 native 浏览器窗口?

ios - 在枚举时修改 NSMutableArray 中的 NSDictionary 项的正确方法是什么?

objective-c - 核心数据故障和内存警告

facebook - 在Facebook iOS SDK中获取Facebook用户 friend 姓名列表的最有效方法是什么?

ios - 如何摆脱 iOS 4 中 UIPopoverController 中奇怪的黑色导航栏

iOS : Touch Id is not shown when AppDelegate's open url is invoked

objective-c - 操作系统 X : always run app with root privileges

algorithm - 在图形节点之间画线有哪些好的算法?

mysql - facebook 中的图表和 MYSQL 数据库之间的区别?