From ee0d1633f2facf7c5d69e8615a8e0d1fbafc199d Mon Sep 17 00:00:00 2001 From: frybitsinc Date: Fri, 16 Aug 2024 15:52:10 +0900 Subject: [PATCH 1/9] feat: add PencilKit interaction on/off toggle feature --- ios/Classes/FLPencilKit.swift | 7 +++++++ lib/src/pencil_kit.dart | 6 ++++++ 2 files changed, 13 insertions(+) diff --git a/ios/Classes/FLPencilKit.swift b/ios/Classes/FLPencilKit.swift index 00ca976..9f38215 100644 --- a/ios/Classes/FLPencilKit.swift +++ b/ios/Classes/FLPencilKit.swift @@ -78,6 +78,9 @@ class FLPencilKit: NSObject, FlutterPlatformView { case "setPKTool": pencilKitView.setPKTool(properties: call.arguments as! [String: Any]) result(nil) + case "setPencilKitEnabled": + pencilKitView.setPencilKitEnabled(enabled:call.arguments as! Bool) + result(nil) case "save": save(pencilKitView: pencilKitView, call: call, result: result) case "load": @@ -270,6 +273,10 @@ private class PencilKitView: UIView { canvasView.resignFirstResponder() } + func setPencilKitEnabled(enabled: Bool) { + canvasView.isUserInteractionEnabled = enabled + } + func setPKTool(properties: [String: Any]) { // toolType let inputToolType = properties["toolType"] as! String diff --git a/lib/src/pencil_kit.dart b/lib/src/pencil_kit.dart index 5367e75..df3408b 100644 --- a/lib/src/pencil_kit.dart +++ b/lib/src/pencil_kit.dart @@ -78,6 +78,7 @@ class PencilKit extends StatefulWidget { this.isRulerActive, this.drawingPolicy, this.isOpaque, + this.isPencilKitEnabled = true, this.backgroundColor, this.toolPickerVisibilityDidChange, this.toolPickerIsRulerActiveDidChange, @@ -118,6 +119,8 @@ class PencilKit extends StatefulWidget { /// You should always set the value of this property to false if the view is fully or partially transparent. final bool? isOpaque; + final bool? isPencilKitEnabled; + /// The view’s background color. The default is transparent final Color? backgroundColor; @@ -286,6 +289,9 @@ class PencilKitController { }); } + Future setPencilKitEnabled(bool enable) => + _channel.invokeMethod('setPencilKitEnabled', enable); + /// Clear all drawing data Future clear() => _channel.invokeMethod('clear'); From 7fc0d383dee014328d7f31c1f0b80610691c3020 Mon Sep 17 00:00:00 2001 From: frybitsinc Date: Fri, 16 Aug 2024 15:52:53 +0900 Subject: [PATCH 2/9] feat: update example --- example/lib/main.dart | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index cb5bc3a..91ef256 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -26,6 +26,7 @@ class _MyAppState extends State { double currentWidth = 1; Color currentColor = Colors.black; String base64Image = ''; + bool isPencilKitEnabled = true; @override Widget build(BuildContext context) { @@ -34,7 +35,7 @@ class _MyAppState extends State { textButtonTheme: const TextButtonThemeData( style: ButtonStyle( visualDensity: VisualDensity.compact, - padding: MaterialStatePropertyAll( + padding: WidgetStatePropertyAll( EdgeInsets.all(8), ), ), @@ -64,6 +65,13 @@ class _MyAppState extends State { icon: const Icon(Icons.refresh), onPressed: () => controller.clear(), ), + Switch( + value: isPencilKitEnabled, + onChanged: (bool value) { + setState(() => isPencilKitEnabled = value); + controller.setPencilKitEnabled(isPencilKitEnabled); + }, + ), ], ), body: Stack( From c0e1fe0da4f7378598284a812ca96e45975ff7c9 Mon Sep 17 00:00:00 2001 From: frybitsinc Date: Tue, 27 May 2025 17:58:14 +0900 Subject: [PATCH 3/9] feat: add finger long-press disable/enable feature --- ios/Classes/FLPencilKit.swift | 13 +++++++++++++ lib/src/pencil_kit.dart | 5 +++++ 2 files changed, 18 insertions(+) diff --git a/ios/Classes/FLPencilKit.swift b/ios/Classes/FLPencilKit.swift index 459b042..223d6d5 100644 --- a/ios/Classes/FLPencilKit.swift +++ b/ios/Classes/FLPencilKit.swift @@ -193,6 +193,15 @@ private func createCanvasView(delegate: PKCanvasViewDelegate) -> PKCanvasView { } v.backgroundColor = .clear v.isOpaque = false + v.isLongPressEnabled = false + // disable long-press finger touches + if let recognizers = v.gestureRecognizers { + for recognizer in recognizers { + if let lp = recognizer as? UILongPressGestureRecognizer,lp.allowedTouchTypes.contains(.direct) { + lp.isEnabled = false + } + } + } return v } @@ -404,6 +413,9 @@ private class PencilKitView: UIView { if let isOpaque = properties["isOpaque"] as? Bool { canvasView.isOpaque = isOpaque } + if let isLongPressEnabled = properties["isLongPressEnabled"] as? Bool { + canvasView.isLongPressEnabled = isLongPressEnabled + } if let backgroundColor = properties["backgroundColor"] as? Int { canvasView.backgroundColor = UIColor(hex: backgroundColor) } @@ -423,6 +435,7 @@ private class PencilKitView: UIView { new.drawingPolicy = old.drawingPolicy } new.isOpaque = old.isOpaque + new.isLongPressEnabled = old.isLongPressEnabled new.backgroundColor = old.backgroundColor if toolPicker?.isVisible == true { diff --git a/lib/src/pencil_kit.dart b/lib/src/pencil_kit.dart index 848905c..f745c9d 100644 --- a/lib/src/pencil_kit.dart +++ b/lib/src/pencil_kit.dart @@ -78,6 +78,7 @@ class PencilKit extends StatefulWidget { this.isRulerActive, this.drawingPolicy, this.isOpaque, + this.isLongPressEnabled, this.backgroundColor, this.toolPickerVisibilityDidChange, this.toolPickerIsRulerActiveDidChange, @@ -118,6 +119,9 @@ class PencilKit extends StatefulWidget { /// You should always set the value of this property to false if the view is fully or partially transparent. final bool? isOpaque; + /// A Boolean value that indicates whether a long-press with finger touch is enabled. + final bool? isLongPressEnabled; + /// The view’s background color. The default is transparent final Color? backgroundColor; @@ -282,6 +286,7 @@ class PencilKitController { 'isRulerActive': widget.isRulerActive, 'drawingPolicy': widget.drawingPolicy?.value, 'isOpaque': widget.isOpaque, + 'isLongPressEnabled': widget.isLongPressEnabled, // ignore: deprecated_member_use 'backgroundColor': widget.backgroundColor?.value, }); From d82375e623e46e76d42c08bced02c1bedc39b7b0 Mon Sep 17 00:00:00 2001 From: frybitsinc Date: Tue, 27 May 2025 19:39:56 +0900 Subject: [PATCH 4/9] feat: add finger long-press disable/enable feature --- example/ios/Runner.xcodeproj/project.pbxproj | 13 ++-- example/ios/Runner/Info.plist | 8 +- example/pubspec.lock | 78 ++++++++++---------- ios/Classes/FLPencilKit.swift | 24 ++++-- 4 files changed, 67 insertions(+), 56 deletions(-) diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index b7d8091..8f8900f 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -121,7 +121,6 @@ 0166A0AAE11E4F4B8A4FA748 /* Pods-Runner.release.xcconfig */, 84D36A9762489E2EA873AEB7 /* Pods-Runner.profile.xcconfig */, ); - name = Pods; path = Pods; sourceTree = ""; }; @@ -359,14 +358,14 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = 6837H68H5B; + DEVELOPMENT_TEAM = RZKUDB56GR; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = happy.mjstudio.flutter.pencilkit.pencilKitExample; + PRODUCT_BUNDLE_IDENTIFIER = happy.mjstudio.pencilKitExample; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; @@ -488,14 +487,14 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = 6837H68H5B; + DEVELOPMENT_TEAM = RZKUDB56GR; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = happy.mjstudio.flutter.pencilkit.pencilKitExample; + PRODUCT_BUNDLE_IDENTIFIER = happy.mjstudio.pencilKitExample; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -511,14 +510,14 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = 6837H68H5B; + DEVELOPMENT_TEAM = RZKUDB56GR; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = happy.mjstudio.flutter.pencilkit.pencilKitExample; + PRODUCT_BUNDLE_IDENTIFIER = happy.mjstudio.pencilKitExample; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; diff --git a/example/ios/Runner/Info.plist b/example/ios/Runner/Info.plist index e37bce7..1b59362 100644 --- a/example/ios/Runner/Info.plist +++ b/example/ios/Runner/Info.plist @@ -2,6 +2,8 @@ + CADisableMinimumFrameDurationOnPhone + CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleDisplayName @@ -24,6 +26,8 @@ $(FLUTTER_BUILD_NUMBER) LSRequiresIPhoneOS + UIApplicationSupportsIndirectInputEvents + UILaunchStoryboardName LaunchScreen UIMainStoryboardFile @@ -43,9 +47,5 @@ UIViewControllerBasedStatusBarAppearance - CADisableMinimumFrameDurationOnPhone - - UIApplicationSupportsIndirectInputEvents - diff --git a/example/pubspec.lock b/example/pubspec.lock index 4a0874d..fecf1df 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -5,42 +5,42 @@ packages: dependency: transitive description: name: async - sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63 + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" url: "https://pub.dev" source: hosted - version: "2.12.0" + version: "2.11.0" boolean_selector: dependency: transitive description: name: boolean_selector - sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.1" characters: dependency: transitive description: name: characters - sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" url: "https://pub.dev" source: hosted - version: "1.4.0" + version: "1.3.0" clock: dependency: transitive description: name: clock - sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf url: "https://pub.dev" source: hosted - version: "1.1.2" + version: "1.1.1" collection: dependency: transitive description: name: collection - sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" + sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf url: "https://pub.dev" source: hosted - version: "1.19.1" + version: "1.19.0" cupertino_icons: dependency: "direct main" description: @@ -53,18 +53,18 @@ packages: dependency: transitive description: name: fake_async - sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc" + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" url: "https://pub.dev" source: hosted - version: "1.3.2" + version: "1.3.1" ffi: dependency: transitive description: name: ffi - sha256: "289279317b4b16eb2bb7e271abccd4bf84ec9bdcbe999e278a94b804f5630418" + sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6" url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.1.3" flutter: dependency: "direct main" description: flutter @@ -100,18 +100,18 @@ packages: dependency: transitive description: name: leak_tracker - sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec + sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06" url: "https://pub.dev" source: hosted - version: "10.0.8" + version: "10.0.7" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 + sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379" url: "https://pub.dev" source: hosted - version: "3.0.9" + version: "3.0.8" leak_tracker_testing: dependency: transitive description: @@ -132,10 +132,10 @@ packages: dependency: transitive description: name: matcher - sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb url: "https://pub.dev" source: hosted - version: "0.12.17" + version: "0.12.16+1" material_color_utilities: dependency: transitive description: @@ -148,18 +148,18 @@ packages: dependency: transitive description: name: meta - sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c + sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 url: "https://pub.dev" source: hosted - version: "1.16.0" + version: "1.15.0" path: dependency: transitive description: name: path - sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.9.0" path_provider: dependency: "direct main" description: @@ -240,50 +240,50 @@ packages: dependency: transitive description: name: source_span - sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" url: "https://pub.dev" source: hosted - version: "1.10.1" + version: "1.10.0" stack_trace: dependency: transitive description: name: stack_trace - sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" + sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377" url: "https://pub.dev" source: hosted - version: "1.12.1" + version: "1.12.0" stream_channel: dependency: transitive description: name: stream_channel - sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.1.2" string_scanner: dependency: transitive description: name: string_scanner - sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" + sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3" url: "https://pub.dev" source: hosted - version: "1.4.1" + version: "1.3.0" term_glyph: dependency: transitive description: name: term_glyph - sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 url: "https://pub.dev" source: hosted - version: "1.2.2" + version: "1.2.1" test_api: dependency: transitive description: name: test_api - sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd + sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c" url: "https://pub.dev" source: hosted - version: "0.7.4" + version: "0.7.3" vector_math: dependency: transitive description: @@ -296,10 +296,10 @@ packages: dependency: transitive description: name: vm_service - sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14" + sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b url: "https://pub.dev" source: hosted - version: "14.3.1" + version: "14.3.0" web: dependency: transitive description: @@ -317,5 +317,5 @@ packages: source: hosted version: "1.1.0" sdks: - dart: ">=3.7.0 <4.0.0" + dart: ">=3.6.0 <4.0.0" flutter: ">=3.27.0" diff --git a/ios/Classes/FLPencilKit.swift b/ios/Classes/FLPencilKit.swift index a543cc5..4c567f7 100644 --- a/ios/Classes/FLPencilKit.swift +++ b/ios/Classes/FLPencilKit.swift @@ -2,6 +2,13 @@ import Flutter import PencilKit import UIKit +extension UIView { + /// Returns this view and every subview, recursively. + var allSubviewsRecursive: [UIView] { + return subviews + subviews.flatMap { $0.allSubviewsRecursive } + } +} + class FLPencilKitFactory: NSObject, FlutterPlatformViewFactory { private var messenger: FlutterBinaryMessenger @@ -196,15 +203,24 @@ private func createCanvasView(delegate: PKCanvasViewDelegate) -> PKCanvasView { } v.backgroundColor = .clear v.isOpaque = false - v.isLongPressEnabled = false // disable long-press finger touches if let recognizers = v.gestureRecognizers { for recognizer in recognizers { - if let lp = recognizer as? UILongPressGestureRecognizer,lp.allowedTouchTypes.contains(.direct) { + if let lp = recognizer as? UILongPressGestureRecognizer, + lp.allowedTouchTypes.contains(NSNumber(value: UITouch.TouchType.direct.rawValue)) { lp.isEnabled = false } } } + + // Remove PencilKit’s new edit-menu interactions (iOS 16+) + if #available(iOS 16.0, *) { + for view in [v] + v.allSubviewsRecursive { + for interaction in view.interactions where interaction is UIEditMenuInteraction { + view.removeInteraction(interaction) + } + } + } return v } @@ -420,9 +436,6 @@ private class PencilKitView: UIView { if let isOpaque = properties["isOpaque"] as? Bool { canvasView.isOpaque = isOpaque } - if let isLongPressEnabled = properties["isLongPressEnabled"] as? Bool { - canvasView.isLongPressEnabled = isLongPressEnabled - } if let backgroundColor = properties["backgroundColor"] as? Int { canvasView.backgroundColor = UIColor(hex: backgroundColor) } @@ -442,7 +455,6 @@ private class PencilKitView: UIView { new.drawingPolicy = old.drawingPolicy } new.isOpaque = old.isOpaque - new.isLongPressEnabled = old.isLongPressEnabled new.backgroundColor = old.backgroundColor if toolPicker?.isVisible == true { From ad276a2cbc942959ad0063460872853eeedfb797 Mon Sep 17 00:00:00 2001 From: frybitsinc Date: Wed, 28 May 2025 13:21:52 +0900 Subject: [PATCH 5/9] feat: set finger long-press disable/enable by given parameter 'isLongPressEnabled' --- ios/Classes/FLPencilKit.swift | 90 ++++++++++++++++++++++------------- 1 file changed, 56 insertions(+), 34 deletions(-) diff --git a/ios/Classes/FLPencilKit.swift b/ios/Classes/FLPencilKit.swift index 4c567f7..d769539 100644 --- a/ios/Classes/FLPencilKit.swift +++ b/ios/Classes/FLPencilKit.swift @@ -203,24 +203,6 @@ private func createCanvasView(delegate: PKCanvasViewDelegate) -> PKCanvasView { } v.backgroundColor = .clear v.isOpaque = false - // disable long-press finger touches - if let recognizers = v.gestureRecognizers { - for recognizer in recognizers { - if let lp = recognizer as? UILongPressGestureRecognizer, - lp.allowedTouchTypes.contains(NSNumber(value: UITouch.TouchType.direct.rawValue)) { - lp.isEnabled = false - } - } - } - - // Remove PencilKit’s new edit-menu interactions (iOS 16+) - if #available(iOS 16.0, *) { - for view in [v] + v.allSubviewsRecursive { - for interaction in view.interactions where interaction is UIEditMenuInteraction { - view.removeInteraction(interaction) - } - } - } return v } @@ -436,31 +418,71 @@ private class PencilKitView: UIView { if let isOpaque = properties["isOpaque"] as? Bool { canvasView.isOpaque = isOpaque } + if let isLongPressEnabled = properties["isLongPressEnabled"] as? Bool { + if isLongPressEnabled == false { + disableIsLongPress(v: canvasView) + } + } if let backgroundColor = properties["backgroundColor"] as? Int { canvasView.backgroundColor = UIColor(hex: backgroundColor) } } - - private func synchronizeCanvasViewProperties(old: PKCanvasView, new: PKCanvasView) { - if let toolPicker { - toolPicker.removeObserver(old) - toolPicker.addObserver(new) - toolPicker.setVisible(true, forFirstResponder: new) + + private func disableIsLongPress(v: PKCanvasView) { + // disable long-press finger touches + if let recognizers = v.gestureRecognizers { + for recognizer in recognizers { + if let lp = recognizer as? UILongPressGestureRecognizer, + lp.allowedTouchTypes.contains(NSNumber(value: UITouch.TouchType.direct.rawValue)) { + lp.isEnabled = false + } + } + } + + // Remove PencilKit’s new edit-menu interactions (iOS 16+) + if #available(iOS 16.0, *) { + for view in [v] + v.allSubviewsRecursive { + for interaction in view.interactions where interaction is UIEditMenuInteraction { + view.removeInteraction(interaction) + } + } + } } - new.alwaysBounceVertical = old.alwaysBounceVertical - new.alwaysBounceHorizontal = old.alwaysBounceHorizontal - new.isRulerActive = old.isRulerActive - if #available(iOS 14.0, *) { - new.drawingPolicy = old.drawingPolicy +private func synchronizeCanvasViewProperties(old: PKCanvasView, new: PKCanvasView) { + if let toolPicker { + toolPicker.removeObserver(old) + toolPicker.addObserver(new) + toolPicker.setVisible(true, forFirstResponder: new) + } + + new.alwaysBounceVertical = old.alwaysBounceVertical + new.alwaysBounceHorizontal = old.alwaysBounceHorizontal + new.isRulerActive = old.isRulerActive + if #available(iOS 14.0, *) { + new.drawingPolicy = old.drawingPolicy + } + new.isOpaque = old.isOpaque + new.backgroundColor = old.backgroundColor + + // Synchronize long-press settings by checking if old canvas had disabled long-press + if let oldRecognizers = old.gestureRecognizers { + let hasDisabledLongPress = oldRecognizers.contains { recognizer in + if let lp = recognizer as? UILongPressGestureRecognizer, + lp.allowedTouchTypes.contains(NSNumber(value: UITouch.TouchType.direct.rawValue)) { + return !lp.isEnabled + } + return false } - new.isOpaque = old.isOpaque - new.backgroundColor = old.backgroundColor - - if toolPicker?.isVisible == true { - new.becomeFirstResponder() + if hasDisabledLongPress { + disableIsLongPress(v: new) } } + + if toolPicker?.isVisible == true { + new.becomeFirstResponder() + } + } } @available(iOS 13.0, *) From b01bb12519d9f2718e49046f75e33643782ac5b2 Mon Sep 17 00:00:00 2001 From: frybitsinc Date: Wed, 28 May 2025 13:27:32 +0900 Subject: [PATCH 6/9] fix: set isLongPressEnabled value to true by default --- lib/src/pencil_kit.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/pencil_kit.dart b/lib/src/pencil_kit.dart index 6632f4c..06f6c57 100644 --- a/lib/src/pencil_kit.dart +++ b/lib/src/pencil_kit.dart @@ -78,7 +78,7 @@ class PencilKit extends StatefulWidget { this.isRulerActive, this.drawingPolicy, this.isOpaque, - this.isLongPressEnabled, + this.isLongPressEnabled = true, this.isPencilKitEnabled = true, this.backgroundColor, this.toolPickerVisibilityDidChange, From 79c9034c1a33bf4a4b1116a7c41ff6625dbdc2a9 Mon Sep 17 00:00:00 2001 From: frybitsinc Date: Wed, 28 May 2025 13:29:54 +0900 Subject: [PATCH 7/9] chore: add docs --- lib/src/pencil_kit.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/pencil_kit.dart b/lib/src/pencil_kit.dart index 06f6c57..3fbadc2 100644 --- a/lib/src/pencil_kit.dart +++ b/lib/src/pencil_kit.dart @@ -120,10 +120,10 @@ class PencilKit extends StatefulWidget { /// You should always set the value of this property to false if the view is fully or partially transparent. final bool? isOpaque; - /// A Boolean value that indicates whether a long-press with finger touch is enabled. + /// A Boolean value that indicates whether a long-press with finger touch is enabled. The default value of this property is true. final bool? isLongPressEnabled; - /// A Boolean value that indicates whether a pencilkit is enabled. + /// A Boolean value that indicates whether a PencilKit is enabled. The default value of this property is true. final bool? isPencilKitEnabled; /// The view’s background color. The default is transparent From 9358f76c2edffd3ed035a9af33808be6c116088d Mon Sep 17 00:00:00 2001 From: frybitsinc Date: Wed, 28 May 2025 13:51:02 +0900 Subject: [PATCH 8/9] feat: update example --- example/lib/main.dart | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index 7de754b..a76fe92 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -27,6 +27,7 @@ class _MyAppState extends State { Color currentColor = Colors.black; String base64Image = ''; bool isPencilKitEnabled = true; + bool isLongPressEnabled = true; @override Widget build(BuildContext context) { @@ -185,6 +186,14 @@ class _MyAppState extends State { }, tooltip: "Get base64 jpeg data", ), + Spacer(), + Text("isLongPressEnabled"), + Switch( + value: isLongPressEnabled, + onChanged: (bool value) { + setState(() => isLongPressEnabled = value); + }, + ), ], ), ), @@ -376,9 +385,10 @@ class _MyAppState extends State { alwaysBounceVertical: false, alwaysBounceHorizontal: true, isRulerActive: false, - drawingPolicy: PencilKitIos14DrawingPolicy.anyInput, + drawingPolicy: PencilKitIos14DrawingPolicy.onlyPencil, backgroundColor: Colors.yellow.withValues(alpha: 0.1), isOpaque: false, + isLongPressEnabled: isLongPressEnabled, toolPickerVisibilityDidChange: (isVisible) => print('toolPickerVisibilityDidChange $isVisible'), toolPickerIsRulerActiveDidChange: (isRulerActive) => print( From bf40fd9bd26e890b819fac311fb1fbec9320e8bd Mon Sep 17 00:00:00 2001 From: frybitsinc Date: Wed, 28 May 2025 14:29:31 +0900 Subject: [PATCH 9/9] fix: lint --- example/lib/main.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index a76fe92..691735c 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -186,8 +186,8 @@ class _MyAppState extends State { }, tooltip: "Get base64 jpeg data", ), - Spacer(), - Text("isLongPressEnabled"), + Spacer(), + Text("isLongPressEnabled"), Switch( value: isLongPressEnabled, onChanged: (bool value) {