如何在 PencilKit 中通过 PKInkingTool 设置恒定的笔画宽度
How to set constant width of strokes from PKInkingTool in PencilKit
当使用 finger/pencil 和 PencilKit API 在屏幕上绘图时,我想将笔画的宽度设置为常量。目前,say PKInkingTool
中的宽度设置只设置了用手指或铅笔绘图时的基线宽度,并且如果用他们的 finger/pencil.
进行慢速或快速笔划,宽度会有所不同
我不确定如何设置最小示例,有很多代码可以让 PencilKit 视图正常工作。您可以使用 Apple 的 this example 来设置一个简单的绘图应用程序。
这是我选择默认绘图工具的代码:
canvas.tool = PKInkingTool(.pen, color: .white, width: 10)
其中 canvas
是一个 PKCanvasView
对象。每个 InkType (link to docs) 中都有一个 validWidthRange
属性,但我不确定这是否可以帮助我实现我想要的。
我找到了解决方案(感谢 Will Bishop), however I'm not sure it's the best for everyone. I solve it by redrawing the stroke after its been completed with a constant width. Apple released new APIs for PKStroke
and PKStrokePoint
在 WWDC2020 上的 iOS 14。这是我代码的相关部分(newDrawing
是具有恒定笔划宽度的新绘图,而 canvasView
指的是我 PKCanvas
上的当前绘图):
var newDrawingStrokes = [PKStroke]()
for stroke in canvasView.drawing.strokes {
var newPoints = [PKStrokePoint]()
stroke.path.forEach { (point) in
let newPoint = PKStrokePoint(location: point.location,
timeOffset: point.timeOffset,
size: CGSize(width: 5,height: 5),
opacity: CGFloat(1), force: point.force,
azimuth: point.azimuth, altitude: point.altitude)
newPoints.append(newPoint)
}
let newPath = PKStrokePath(controlPoints: newPoints, creationDate: Date())
newDrawingStrokes.append(PKStroke(ink: PKInk(.pen, color: UIColor.white), path: newPath))
}
let newDrawing = PKDrawing(strokes: newDrawingStrokes)
这是我拼凑的一些初步代码,所以如果您找到任何 bugs/mistakes 请告诉我!
有一种方法可以通过 swizzling UITouch
force
和 timestamp
方法修复它。
您可以在您的项目中添加这个 Objective-C 类别:
#import <objc/runtime.h>
@implementation UITouch (UITouch_Overrides)
+ (void)load {
[super load];
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[self swizzleForce];
[self swizzleTimestamp];
});
}
+ (void)swizzleForce {
[self swizzle:@selector(force) with:@selector(ed_force)];
}
+ (void)swizzleTimestamp {
[self swizzle:@selector(timestamp) with:@selector(ed_timestamp)];
}
+ (void)swizzle:(SEL)originalSelector with:(SEL)swizzledSelector {
Class class = [self class];
Method originalMethod = class_getInstanceMethod(class, originalSelector);
Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
BOOL didAddMethod =
class_addMethod(class,
originalSelector,
method_getImplementation(swizzledMethod),
method_getTypeEncoding(swizzledMethod));
if (didAddMethod) {
class_replaceMethod(class,
swizzledSelector,
method_getImplementation(originalMethod),
method_getTypeEncoding(originalMethod));
} else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
}
- (CGFloat)ed_force {
return 1.0;
}
- (NSTimeInterval)ed_timestamp {
return 0;
}
@end
当使用 finger/pencil 和 PencilKit API 在屏幕上绘图时,我想将笔画的宽度设置为常量。目前,say PKInkingTool
中的宽度设置只设置了用手指或铅笔绘图时的基线宽度,并且如果用他们的 finger/pencil.
我不确定如何设置最小示例,有很多代码可以让 PencilKit 视图正常工作。您可以使用 Apple 的 this example 来设置一个简单的绘图应用程序。
这是我选择默认绘图工具的代码:
canvas.tool = PKInkingTool(.pen, color: .white, width: 10)
其中 canvas
是一个 PKCanvasView
对象。每个 InkType (link to docs) 中都有一个 validWidthRange
属性,但我不确定这是否可以帮助我实现我想要的。
我找到了解决方案(感谢 Will Bishop), however I'm not sure it's the best for everyone. I solve it by redrawing the stroke after its been completed with a constant width. Apple released new APIs for PKStroke
and PKStrokePoint
在 WWDC2020 上的 iOS 14。这是我代码的相关部分(newDrawing
是具有恒定笔划宽度的新绘图,而 canvasView
指的是我 PKCanvas
上的当前绘图):
var newDrawingStrokes = [PKStroke]()
for stroke in canvasView.drawing.strokes {
var newPoints = [PKStrokePoint]()
stroke.path.forEach { (point) in
let newPoint = PKStrokePoint(location: point.location,
timeOffset: point.timeOffset,
size: CGSize(width: 5,height: 5),
opacity: CGFloat(1), force: point.force,
azimuth: point.azimuth, altitude: point.altitude)
newPoints.append(newPoint)
}
let newPath = PKStrokePath(controlPoints: newPoints, creationDate: Date())
newDrawingStrokes.append(PKStroke(ink: PKInk(.pen, color: UIColor.white), path: newPath))
}
let newDrawing = PKDrawing(strokes: newDrawingStrokes)
这是我拼凑的一些初步代码,所以如果您找到任何 bugs/mistakes 请告诉我!
有一种方法可以通过 swizzling UITouch
force
和 timestamp
方法修复它。
您可以在您的项目中添加这个 Objective-C 类别:
#import <objc/runtime.h>
@implementation UITouch (UITouch_Overrides)
+ (void)load {
[super load];
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[self swizzleForce];
[self swizzleTimestamp];
});
}
+ (void)swizzleForce {
[self swizzle:@selector(force) with:@selector(ed_force)];
}
+ (void)swizzleTimestamp {
[self swizzle:@selector(timestamp) with:@selector(ed_timestamp)];
}
+ (void)swizzle:(SEL)originalSelector with:(SEL)swizzledSelector {
Class class = [self class];
Method originalMethod = class_getInstanceMethod(class, originalSelector);
Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
BOOL didAddMethod =
class_addMethod(class,
originalSelector,
method_getImplementation(swizzledMethod),
method_getTypeEncoding(swizzledMethod));
if (didAddMethod) {
class_replaceMethod(class,
swizzledSelector,
method_getImplementation(originalMethod),
method_getTypeEncoding(originalMethod));
} else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
}
- (CGFloat)ed_force {
return 1.0;
}
- (NSTimeInterval)ed_timestamp {
return 0;
}
@end