UIBezierPath lineWidth 基于 UIPanGestureRecognizer 的速度

UIBezierPath lineWidth based on UIPanGestureRecognizer's velocity

我正在尝试弄清楚如何根据 UIPanGestureRecognizer 的速度构造有限范围的浮点值。我的最小值或起始值为 1.0,最大值为 3.0,以便为 UIBezierPathlineWidth 属性 提供有限的范围。

我正在尝试弄清楚如何根据 UIPanGestureRecognizer 的速度建立一个从 1.0 到 3.0 的指数范围,但是我在开始映射这些值时遇到了困难。组合的 x 和 y 速度越快,lineWidth 应该越小(低至 1.0),如果组合速度较慢,则分别相反,最高为 3.0。我还尝试通过存储 lastWidth 属性 来 taper/smooth 进行中的线宽,因此子路径之间的转换不明显。

如果能提供任何帮助,我将不胜感激。

基于答案的工作和最终代码:

@property (nonatomic, assign) CGFloat lastWidth;

if (recognizer.state == UIGestureRecognizerStateChanged)
{
    CGPoint velocity = [recognizer velocityInView:self.view];

    CGFloat absoluteVelocity = 1000.0 / sqrtf(pow(velocity.x, 2) + pow(velocity.y, 2));

    CGFloat clampedVel = MAX(MIN(absoluteVelocity, 3.0), 1.0);

    if (clampedVel > self.lastWidth)
    {
        clampedVel = self.lastWidth + 0.15;
    }
    else if (clampedVel < self.lastWidth)
    {
        clampedVel = self.lastWidth - 0.15;
    }

    self.lastWidth = clampedVel;

    UIBezierPath *path = [UIBezierPath bezierPath];
    path.lineCapStyle = kCGLineCapRound;
    path.lineWidth = self.lastWidth;
}

所以我会使用倒指数函数。

从你的速度 V(x,y) 开始。你的绝对速度显然是:

sqrt(pow(x, 2) + pow(y, 2));

我们称这个值为"v."

接下来,我们需要一个介于 1 和 3 之间的值,其中 1 是 "v" 非常高的宽度,3 是 "v" 非常低的宽度。

我们可以使用以下指数函数计算:

- (CGFloat)getExponentialWidthForVeloctity(CGFloat)v {
    if (v <= 1 / 3.0)
        return 3;
    CGFloat inverse = 1 / v;
    return 1 + inverse;
}

或者这个稍微平滑一点的函数

- (CGFloat)getExponentialRootWidthForVeloctity(CGFloat)v {
    //play with this value to get the feel right
    //The higher it is, the faster you'll have to go to get a thinner line
    CGFloat rootConstantYouCanAdjust = 2;
    if (pow(v, rootConstantYouCanAdjust) <= 1 / 3.0)
        return 3;
    CGFloat inverse = 1 / pow(v, rootConstantYouCanAdjust);
    return 1 + inverse;
}

如果感觉不对,请尝试线性解决方案:

- (CGFloat)getLinearWidthForVelocity(CGFloat)v {
    //Find this value by swiping your finger really quickly and seeing what the fastest velocity you can get is
    CGFloat myExpectedMaximumVelocity = 1000; 
    if (v > myExpectedMaximumVelocity)
        v = myExpectedMaximumVelocity;
    return 3 - 2 * (v / myExpectedMaximumVelocity);
}

最后,作为奖励,试试这个基于 sqrt 的函数,您可能会发现它运行良好:

- (CGFloat)getSqrtWidthForVelocity(CGFloat)v {
    //find the same way as above
    CGFloat myExpectedMaximumVelocity = 1000;
    if (v > myExpectedMaximumVelocity)
        return 1;
    return 3 - 2 * sqrt(v) / sqrt(myExpectedMaximumVelocity);
}

我很想知道哪个效果最好!让我知道。我还有很多功能,这些只是一些非常简单的功能,应该可以帮助您入门。