UIBezierPath lineWidth 基于 UIPanGestureRecognizer 的速度
UIBezierPath lineWidth based on UIPanGestureRecognizer's velocity
我正在尝试弄清楚如何根据 UIPanGestureRecognizer
的速度构造有限范围的浮点值。我的最小值或起始值为 1.0,最大值为 3.0,以便为 UIBezierPath
的 lineWidth
属性 提供有限的范围。
我正在尝试弄清楚如何根据 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);
}
我很想知道哪个效果最好!让我知道。我还有很多功能,这些只是一些非常简单的功能,应该可以帮助您入门。
我正在尝试弄清楚如何根据 UIPanGestureRecognizer
的速度构造有限范围的浮点值。我的最小值或起始值为 1.0,最大值为 3.0,以便为 UIBezierPath
的 lineWidth
属性 提供有限的范围。
我正在尝试弄清楚如何根据 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);
}
我很想知道哪个效果最好!让我知道。我还有很多功能,这些只是一些非常简单的功能,应该可以帮助您入门。