├── references.d.ts ├── .gradle ├── vcs-1 │ └── gc.properties └── checksums │ ├── checksums.lock │ ├── md5-checksums.bin │ └── sha1-checksums.bin ├── .vscode └── settings.json ├── .github ├── FUNDING.yml ├── issue_template.md └── workflows │ └── release.yml ├── src-native ├── android │ ├── gesturehandler │ │ ├── .gitignore │ │ ├── src │ │ │ └── main │ │ │ │ ├── java │ │ │ │ ├── res │ │ │ │ └── AndroidManifest.xml │ │ ├── .settings │ │ │ └── org.eclipse.buildship.core.prefs │ │ ├── gradle │ │ │ └── wrapper │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ ├── .classpath │ │ ├── local.properties │ │ ├── proguard-rules.pro │ │ ├── .project │ │ ├── build.gradle │ │ ├── gradlew.bat │ │ └── gradlew │ ├── settings.gradle │ ├── .vscode │ │ └── settings.json │ ├── .gitignore │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── .settings │ │ └── org.eclipse.buildship.core.prefs │ ├── README.md │ ├── build.gradle │ ├── .project │ ├── build.sh │ ├── gradle.properties │ ├── gradlew.bat │ └── gradlew ├── ios │ ├── GestureHandler │ ├── build.sh │ └── GestureHandler.xcodeproj │ │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ │ ├── xcuserdata │ │ └── mguillon.xcuserdatad │ │ │ └── xcschemes │ │ │ └── xcschememanagement.plist │ │ └── xcshareddata │ │ └── xcschemes │ │ ├── test.xcscheme │ │ ├── universal.xcscheme │ │ ├── GestureHandler.xcscheme │ │ ├── GestureHandlerLib.xcscheme │ │ └── GestureHandlerApp.xcscheme └── .vscode │ └── settings.json ├── pnpm-workspace.yaml ├── packages └── gesturehandler │ ├── platforms │ ├── android │ │ ├── sync │ │ ├── native-api-usage.json │ │ ├── AndroidManifest.xml │ │ ├── java │ │ │ └── com │ │ │ │ ├── swmansion │ │ │ │ └── gesturehandler │ │ │ │ │ ├── GestureHandlerRegistry.java │ │ │ │ │ ├── OnTouchEventListener.java │ │ │ │ │ ├── ViewConfigurationHelper.java │ │ │ │ │ ├── GestureHandlerInteractionController.java │ │ │ │ │ ├── PointerEvents.java │ │ │ │ │ ├── PointerEventsSpec.java │ │ │ │ │ ├── PointerEventsConfig.java │ │ │ │ │ ├── BaseGestureHandlerInteractionController.java │ │ │ │ │ ├── GestureUtils.java │ │ │ │ │ ├── LongPressGestureHandler.java │ │ │ │ │ ├── RotationGestureHandler.java │ │ │ │ │ ├── GestureHandlerRegistryImpl.java │ │ │ │ │ ├── FlingGestureHandler.java │ │ │ │ │ ├── PinchGestureHandler.java │ │ │ │ │ ├── RotationGestureDetector.java │ │ │ │ │ ├── TapGestureHandler.java │ │ │ │ │ └── NativeViewGestureHandler.java │ │ │ │ └── nativescript │ │ │ │ └── gesturehandler │ │ │ │ ├── RootViewGestureHandler.java │ │ │ │ └── GestureHandlerInteractionController.java │ │ ├── res │ │ │ └── values │ │ │ │ └── config.xml │ │ └── include.gradle │ └── ios │ │ └── src │ │ ├── module.modulemap │ │ ├── FlingHandler.h │ │ ├── ForceTouchHandler.h │ │ ├── GestureHandlerDirection.h │ │ ├── PinchHandler.h │ │ ├── RotationHandler.h │ │ ├── GestureHandlerState.h │ │ ├── LongPressHandler.h │ │ ├── RootViewGestureRecognizer.h │ │ ├── NativeViewHandler.h │ │ ├── TapHandler.h │ │ ├── GestureHandlerRegistry.h │ │ ├── GestureHandlerHeader.h │ │ ├── GestureHandlerManager.h │ │ ├── GestureHandlerEvents.h │ │ ├── PinchHandler.m │ │ ├── RotationHandler.m │ │ ├── GestureHandlerRegistry.m │ │ ├── PanHandler.h │ │ ├── RootViewGestureRecognizer.m │ │ ├── LongPressHandler.m │ │ ├── GestureHandlerEvents.m │ │ ├── GestureHandler.h │ │ ├── ForceTouchHandler.m │ │ ├── FlingHandler.m │ │ ├── NativeViewHandler.m │ │ ├── GestureHandlerManager.m │ │ └── TapHandler.m │ ├── .npmignore │ ├── tsconfig.json │ ├── package.json │ └── blueprint.md ├── .prettierignore ├── .eslintrc.js ├── images └── demo.gif ├── .yarnrc.yml ├── config.json ├── docs ├── .nojekyll ├── assets │ ├── navigation.js │ ├── hierarchy.js │ └── highlight.css ├── media │ └── Basic.vue ├── variables │ ├── GestureHandlerStateEvent.html │ └── GestureHandlerTouchEvent.html └── functions │ └── install.html ├── .prettierrc.js ├── src └── gesturehandler │ ├── references.d.ts │ ├── vue │ └── index.ts │ ├── typings │ └── extensions.android.d.ts │ └── gesturehandler.d.ts ├── .gitmodules ├── demo-snippets ├── package.json └── vue │ ├── ModalView.vue │ ├── install.ts │ └── Basic.vue ├── tsconfig.json ├── tsconfig.vue3.json ├── .npmrc ├── .gitattributes ├── .settings └── org.eclipse.buildship.core.prefs ├── CONTRIBUTING.md ├── svelte.config.js ├── .classpath ├── lerna.json ├── .gitignore ├── .project └── package.json /references.d.ts: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gradle/vcs-1/gc.properties: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | } -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [farfromrefug] 2 | -------------------------------------------------------------------------------- /src-native/android/gesturehandler/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - packages/* 3 | - demo-* -------------------------------------------------------------------------------- /src-native/ios/GestureHandler: -------------------------------------------------------------------------------- 1 | ../../plugin/platforms/ios/src -------------------------------------------------------------------------------- /packages/gesturehandler/platforms/android/sync: -------------------------------------------------------------------------------- 1 | force livesync 2 | -------------------------------------------------------------------------------- /src-native/android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':gesturehandler' 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | package-lock.json 2 | node_modules/ 3 | plugin/ 4 | docs/ 5 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: './tools/.eslintrc.js' 3 | }; 4 | -------------------------------------------------------------------------------- /src-native/android/gesturehandler/src/main/java: -------------------------------------------------------------------------------- 1 | ../../../../../plugin/platforms/android/java -------------------------------------------------------------------------------- /src-native/android/gesturehandler/src/main/res: -------------------------------------------------------------------------------- 1 | ../../../../../plugin/platforms/android/res -------------------------------------------------------------------------------- /images/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nativescript-community/gesturehandler/HEAD/images/demo.gif -------------------------------------------------------------------------------- /src-native/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "java.configuration.updateBuildConfiguration": "disabled" 3 | } -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | compressionLevel: mixed 2 | 3 | nmHoistingLimits: workspaces 4 | 5 | nodeLinker: node-modules 6 | -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "readme": true, 3 | "angular": true, 4 | "demos": [ 5 | "ng" 6 | ] 7 | } -------------------------------------------------------------------------------- /src-native/android/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "java.configuration.updateBuildConfiguration": "disabled" 3 | } -------------------------------------------------------------------------------- /.gradle/checksums/checksums.lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nativescript-community/gesturehandler/HEAD/.gradle/checksums/checksums.lock -------------------------------------------------------------------------------- /.gradle/checksums/md5-checksums.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nativescript-community/gesturehandler/HEAD/.gradle/checksums/md5-checksums.bin -------------------------------------------------------------------------------- /src-native/android/gesturehandler/.settings/org.eclipse.buildship.core.prefs: -------------------------------------------------------------------------------- 1 | connection.project.dir=.. 2 | eclipse.preferences.version=1 3 | -------------------------------------------------------------------------------- /.gradle/checksums/sha1-checksums.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nativescript-community/gesturehandler/HEAD/.gradle/checksums/sha1-checksums.bin -------------------------------------------------------------------------------- /packages/gesturehandler/platforms/android/native-api-usage.json: -------------------------------------------------------------------------------- 1 | { 2 | "uses": [ 3 | "com.swmansion.gesturehandler*:*" 4 | ] 5 | } -------------------------------------------------------------------------------- /packages/gesturehandler/.npmignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | tsconfig.json 3 | node_modules/ 4 | pnpm-global/ 5 | CHANGELOG.md 6 | blueprint.md 7 | *.aar 8 | *.jar -------------------------------------------------------------------------------- /docs/.nojekyll: -------------------------------------------------------------------------------- 1 | TypeDoc added this file to prevent GitHub Pages from using Jekyll. You can turn off this behavior by setting the `githubPages` option to false. -------------------------------------------------------------------------------- /src-native/android/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | printWidth: 200, 3 | semi: true, 4 | tabWidth: 4, 5 | trailingComma: 'none', 6 | singleQuote: true 7 | }; 8 | -------------------------------------------------------------------------------- /packages/gesturehandler/platforms/ios/src/module.modulemap: -------------------------------------------------------------------------------- 1 | module GestureHandler { 2 | umbrella header "GestureHandlerHeader.h" 3 | export * 4 | module * { export * } 5 | } -------------------------------------------------------------------------------- /src-native/android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nativescript-community/gesturehandler/HEAD/src-native/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /src/gesturehandler/references.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | /// 4 | -------------------------------------------------------------------------------- /src-native/android/gesturehandler/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nativescript-community/gesturehandler/HEAD/src-native/android/gesturehandler/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /src/gesturehandler/vue/index.ts: -------------------------------------------------------------------------------- 1 | const Plugin = { 2 | install(Vue) { 3 | Vue.registerElement('GestureRootView', () => require('..').GestureRootView, {}); 4 | } 5 | }; 6 | 7 | export default Plugin; 8 | -------------------------------------------------------------------------------- /packages/gesturehandler/platforms/android/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "tools"] 2 | path = tools 3 | url = https://github.com/nativescript-community/plugin-seed-tools.git 4 | [submodule "demo-vue"] 5 | path = demo-vue 6 | url = https://github.com/nativescript-community/plugin-seed-demo-vue.git 7 | -------------------------------------------------------------------------------- /packages/gesturehandler/platforms/ios/src/FlingHandler.h: -------------------------------------------------------------------------------- 1 | #import "GestureHandler.h" 2 | 3 | @interface FlingGestureHandler : GestureHandler 4 | - (void) setDirection:(NSInteger) value; 5 | - (void) setNumberOfTouchesRequired:(NSInteger) value; 6 | @end 7 | -------------------------------------------------------------------------------- /demo-snippets/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@nativescript-community/template-snippet", 3 | "private": true, 4 | "version": "0.0.1", 5 | "dependencies": { 6 | "@nativescript-community/gesturehandler": "link:../packages/gesturehandler" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src-native/android/gesturehandler/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /packages/gesturehandler/platforms/ios/src/ForceTouchHandler.h: -------------------------------------------------------------------------------- 1 | #import "GestureHandler.h" 2 | 3 | @interface ForceTouchHandler : GestureHandler 4 | - (void) setMaxForce:(NSInteger) value; 5 | - (void) setMinForce:(NSInteger) value; 6 | - (void) setFeedbackOnActivation:(Boolean) value; 7 | @end 8 | -------------------------------------------------------------------------------- /src-native/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Sep 02 07:50:15 EEST 2016 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.7-all.zip 7 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tools/tsconfig", 3 | "compilerOptions": { 4 | "paths": { 5 | "@nativescript-community/gesturehandler": ["src/gesturehandler"], 6 | "@nativescript-community/gesturehandler/*": ["src/gesturehandler/*"] 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /tsconfig.vue3.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "composite": true, 5 | "paths": { 6 | "nativescript-vue": ["./node_modules/nativescript-vue3"] 7 | } 8 | }, 9 | "include": [ 10 | "./demo-snippets/vue3" 11 | ] 12 | } -------------------------------------------------------------------------------- /src-native/ios/build.sh: -------------------------------------------------------------------------------- 1 | set -e 2 | set -o pipefail 3 | 4 | CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 5 | 6 | SOURCE_NAME="GestureHandler" 7 | IOS_SOURCE_DIR="$CURRENT_DIR" 8 | 9 | cd $IOS_SOURCE_DIR 10 | xcodebuild -project GestureHandler.xcodeproj -scheme universal -sdk iphonesimulator 11 | -------------------------------------------------------------------------------- /src-native/android/gesturehandler/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Dec 28 10:00:20 PST 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip 7 | -------------------------------------------------------------------------------- /packages/gesturehandler/platforms/ios/src/GestureHandlerDirection.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | typedef NS_ENUM(NSInteger, GestureHandlerDirection) { 4 | GestureHandlerDirectionRight = 1, 5 | GestureHandlerDirectionLeft = 2, 6 | GestureHandlerDirectionUp = 4, 7 | GestureHandlerDirectionDown = 8, 8 | }; 9 | -------------------------------------------------------------------------------- /src-native/ios/GestureHandler.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /packages/gesturehandler/platforms/ios/src/PinchHandler.h: -------------------------------------------------------------------------------- 1 | // 2 | // RNPinchHandler.h 3 | // GestureHandler 4 | // 5 | // Created by Krzysztof Magiera on 12/10/2017. 6 | // Copyright © 2017 Software Mansion. All rights reserved. 7 | // 8 | 9 | #import "GestureHandler.h" 10 | 11 | @interface PinchGestureHandler : GestureHandler 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /packages/gesturehandler/platforms/ios/src/RotationHandler.h: -------------------------------------------------------------------------------- 1 | // 2 | // RotationHandler.h 3 | // GestureHandler 4 | // 5 | // Created by Krzysztof Magiera on 12/10/2017. 6 | // Copyright © 2017 Software Mansion. All rights reserved. 7 | // 8 | 9 | #import "GestureHandler.h" 10 | 11 | @interface RotationGestureHandler : GestureHandler 12 | @end 13 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | shamefully-hoist=true 2 | public-hoist-pattern[]=*eslint* 3 | public-hoist-pattern[]=source-map-support 4 | public-hoist-pattern[]=ts-patch 5 | public-hoist-pattern[]=typescript 6 | public-hoist-pattern[]=cpy-cli 7 | strict-peer-dependencies=false 8 | shell-emulator=true 9 | auto-install-peers=false 10 | loglevel=error 11 | engine-strict=true 12 | -------------------------------------------------------------------------------- /src-native/ios/GestureHandler.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /packages/gesturehandler/platforms/ios/src/GestureHandlerState.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | typedef NS_ENUM(NSInteger, GestureHandlerState) { 4 | GestureHandlerStateUndetermined = 0, 5 | GestureHandlerStateFailed, 6 | GestureHandlerStateBegan, 7 | GestureHandlerStateCancelled, 8 | GestureHandlerStateActive, 9 | GestureHandlerStateEnd, 10 | }; 11 | -------------------------------------------------------------------------------- /src-native/android/gesturehandler/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /demo-snippets/vue/ModalView.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 18 | -------------------------------------------------------------------------------- /demo-snippets/vue/install.ts: -------------------------------------------------------------------------------- 1 | import Vue from 'nativescript-vue'; 2 | import { GestureRootView, install } from '@nativescript-community/gesturehandler'; 3 | import Basic from './Basic.vue'; 4 | 5 | export function installPlugin() { 6 | install(true); 7 | Vue.registerElement('GestureRootView', () => GestureRootView); 8 | } 9 | 10 | export const demos = [{ name: 'Basic', path: 'basic', component: Basic }]; 11 | -------------------------------------------------------------------------------- /packages/gesturehandler/platforms/android/java/com/swmansion/gesturehandler/GestureHandlerRegistry.java: -------------------------------------------------------------------------------- 1 | package com.swmansion.gesturehandler; 2 | 3 | import android.view.View; 4 | import android.view.ViewGroup; 5 | 6 | import java.util.ArrayList; 7 | 8 | public interface GestureHandlerRegistry { 9 | ArrayList getHandlersForView(View view); 10 | ArrayList getAllHandlers(); 11 | 12 | } 13 | -------------------------------------------------------------------------------- /packages/gesturehandler/platforms/ios/src/LongPressHandler.h: -------------------------------------------------------------------------------- 1 | // 2 | // LongPressHandler.h 3 | // GestureHandler 4 | // 5 | // Created by Krzysztof Magiera on 12/10/2017. 6 | // Copyright © 2017 Software Mansion. All rights reserved. 7 | // 8 | 9 | #import "GestureHandler.h" 10 | 11 | @interface LongPressGestureHandler : GestureHandler 12 | 13 | - (void) setMinDurationMs:(CGFloat) value; 14 | - (void) setMaxDist:(CGFloat) value; 15 | @end 16 | -------------------------------------------------------------------------------- /packages/gesturehandler/platforms/android/java/com/swmansion/gesturehandler/OnTouchEventListener.java: -------------------------------------------------------------------------------- 1 | package com.swmansion.gesturehandler; 2 | 3 | import android.view.MotionEvent; 4 | 5 | public interface OnTouchEventListener { 6 | boolean shouldStartGesture(T handler, MotionEvent event); 7 | 8 | void onTouchEvent(T handler, MotionEvent event); 9 | 10 | void onStateChange(T handler, int newState, int oldState); 11 | } 12 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /src-native/android/gesturehandler/local.properties: -------------------------------------------------------------------------------- 1 | ## This file must *NOT* be checked into Version Control Systems, 2 | # as it contains information specific to your local configuration. 3 | # 4 | # Location of the SDK. This is only used by Gradle. 5 | # For customization when using a Version Control System, please read the 6 | # header note. 7 | #Sun Oct 07 14:14:19 CEST 2018 8 | ndk.dir=/Volumes/data/dev/androidSDK/ndk-bundle 9 | sdk.dir=/Volumes/data/dev/androidSDK 10 | -------------------------------------------------------------------------------- /.settings/org.eclipse.buildship.core.prefs: -------------------------------------------------------------------------------- 1 | arguments= 2 | auto.sync=false 3 | build.scans.enabled=false 4 | connection.gradle.distribution=GRADLE_DISTRIBUTION(VERSION(6.3)) 5 | connection.project.dir= 6 | eclipse.preferences.version=1 7 | gradle.user.home= 8 | java.home=/Library/Java/JavaVirtualMachines/jdk1.8.0_271.jdk/Contents/Home 9 | jvm.arguments= 10 | offline.mode=false 11 | override.workspace.settings=true 12 | show.console.view=true 13 | show.executions.view=true 14 | -------------------------------------------------------------------------------- /packages/gesturehandler/platforms/android/java/com/swmansion/gesturehandler/ViewConfigurationHelper.java: -------------------------------------------------------------------------------- 1 | package com.swmansion.gesturehandler; 2 | 3 | import android.view.View; 4 | import android.view.ViewGroup; 5 | 6 | public interface ViewConfigurationHelper { 7 | PointerEventsConfig getPointerEventsConfigForView(View view); 8 | 9 | View getChildInDrawingOrderAtIndex(ViewGroup parent, int index); 10 | 11 | boolean isViewClippingChildren(ViewGroup view); 12 | } 13 | -------------------------------------------------------------------------------- /src-native/android/.settings/org.eclipse.buildship.core.prefs: -------------------------------------------------------------------------------- 1 | arguments= 2 | auto.sync=false 3 | build.scans.enabled=false 4 | connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER) 5 | connection.project.dir= 6 | eclipse.preferences.version=1 7 | gradle.user.home= 8 | java.home=/Library/Java/JavaVirtualMachines/jdk1.8.0_141.jdk/Contents/Home 9 | jvm.arguments= 10 | offline.mode=false 11 | override.workspace.settings=true 12 | show.console.view=true 13 | show.executions.view=true 14 | -------------------------------------------------------------------------------- /packages/gesturehandler/platforms/ios/src/RootViewGestureRecognizer.h: -------------------------------------------------------------------------------- 1 | // 2 | // RootViewGestureRecognizer.h 3 | // GestureHandler 4 | // 5 | // Created by Krzysztof Magiera on 12/10/2017. 6 | // Copyright © 2017 Software Mansion. All rights reserved. 7 | // 8 | 9 | #import "GestureHandler.h" 10 | 11 | @interface RootViewGestureRecognizer : UIGestureRecognizer 12 | 13 | @property (nullable, nonatomic, weak) id delegate; 14 | 15 | - (void)blockOtherRecognizers; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | 2 | ### clean up typings 3 | 4 | * regexp: ```/export class .*?JNI {(.|[\r\n])*?}//``` 5 | * regexp: ```/export module .*? {([\t\r\n])*?}//``` twice 6 | * regexp: ```/declare module com {([\t\r\n])*?}/``` 7 | 8 | ## ios typings 9 | 10 | run in the demo app 11 | ``` 12 | TNS_TYPESCRIPT_DECLARATIONS_PATH="$(pwd)/typings" tns build ios --bundle 13 | ``` 14 | 15 | ### clean up typings 16 | 17 | * regexp: ```/description\(\): string;//``` 18 | * regexp: ```/hash\(\): number;//``` 19 | * regexp: ```/var:/variant:/``` -------------------------------------------------------------------------------- /packages/gesturehandler/platforms/ios/src/NativeViewHandler.h: -------------------------------------------------------------------------------- 1 | // 2 | // NativeViewHandler.h 3 | // GestureHandler 4 | // 5 | // Created by Krzysztof Magiera on 12/10/2017. 6 | // Copyright © 2017 Software Mansion. All rights reserved. 7 | // 8 | 9 | #import "GestureHandler.h" 10 | 11 | @interface DummyGestureRecognizer : UIGestureRecognizer 12 | @end 13 | 14 | @interface NativeViewGestureHandler : GestureHandler 15 | - (void)setShouldActivateOnStart:(Boolean)value; 16 | - (void)setDisallowInterruption:(Boolean)value; 17 | @end 18 | -------------------------------------------------------------------------------- /svelte.config.js: -------------------------------------------------------------------------------- 1 | const sveltePreprocess = require('svelte-preprocess'); 2 | // const svelteNativePreprocessor = require('svelte-native-preprocessor'); 3 | 4 | module.exports = { 5 | compilerOptions: { 6 | namespace: 'foreign' 7 | }, 8 | preprocess: [ 9 | sveltePreprocess({ 10 | typescript: { 11 | compilerOptions: { 12 | target: 'es2020' 13 | } 14 | } 15 | }) 16 | // svelteNativePreprocessor() 17 | ] 18 | }; 19 | -------------------------------------------------------------------------------- /src-native/android/README.md: -------------------------------------------------------------------------------- 1 | ### Android 2 | 3 | This directory contains an Android Studio project. 4 | 5 | ### How to open? 6 | * In Android Studio choose: File -> Open 7 | * Navigate to `tns-core-modules-widgets/android/` folder 8 | * On the left side of the screen choose the Project tab and select `widgets` 9 | 10 | ### How to build? 11 | * On the right side of the screen choose the Gradle tab 12 | * Navigate to `android/widgets/Tasks/build/` 13 | * Execute the `assembleRelease` task 14 | * Output will be in `./android/widgets/build/outputs/` 15 | -------------------------------------------------------------------------------- /docs/assets/navigation.js: -------------------------------------------------------------------------------- 1 | window.navigationData = "eJyVls1PAjEQxf+XnolEVGI4Gvw4+EGQeDEexmWAxqXdtLMoMf7vBtjYLW2n63ne+73ZXd6E129B+EViJG5KqZZjabAgqZXoiQpoJUYCVb22fX96sqJ1KXriQ6q5GF3+9P4ot2ipNvhMQHjMaM/ShDtQ8xLNbFsFgNYo7b8Ci49ActOyFyVYi7bvZr7/dNAm7J+1WbaJDFEREcvUpsCZrotVFpxQcvRGOdWaXiR+htAjAcdKLtZhj3utlhOD1uYeMiHk2A+gYBljNQPOe/jmuyfPLZZScvQJqBw2kLA8qfI/k4iIY041wa65OWxcx5FnUOWggeSf7XuqditZB5aK0CygiPewkfshg4thhzqySbyHi2tfvusNKhoDQTQkquyA3u/VCe0rOXSHd9L9FSQaz8F5Cxd2aPHE6AoNbbmMqDKPDg9EPiTp4eKCw8HlpMRsQHhH2IiknAuJXxUuh3VwUcGt4VJS4g6FawyuqC5gA0bCe+kqF2h9/tkgiXdlzeOdlsFLZQnK0tEWtdr/pbP9ZuSbh+cts/LKEmP4igD19guxUq/+" -------------------------------------------------------------------------------- /packages/gesturehandler/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "../../src/gesturehandler", 5 | "outDir": "./", 6 | "paths": { 7 | "tns-core-modules": ["./node_modules/@nativescript/core"], 8 | "tns-core-modules/*": ["./node_modules/@nativescript/core/*"] 9 | } 10 | }, 11 | "include": ["../../src/gesturehandler/**/*", "../../references.d.ts", "../../tools/references.d.ts", "../../src/references.d.ts"], 12 | "exclude": ["../../src/gesturehandler/angular/**"] 13 | } 14 | -------------------------------------------------------------------------------- /docs/assets/hierarchy.js: -------------------------------------------------------------------------------- 1 | window.hierarchyData = "eJydlD9vgzAQxb/LzdcGn8EExg5ph6qNqqhL1cECJ0ElJrJJO0T57hVN/xCl2A4LA9zTe++HfXswTdNayF+Io6BXBKOWtSraqtEW8j0Q755abhTkcCOtepBt9a4A4a3SJeSMpgg7U0MORS2tVXbyN3W9bjc14PEL5NDa8qqTXR1fIBTrqi6N0pC/pNHrAUFQz+5O6rJW5nF7TPNjSYn4sax0q8xSFspOTocHnX8Vp+4sSpEJQiKGJARyxpAnAnk2xZhnXbQ0Oo/mwvA9cgkDRoQszZA4Q0oFcmLIRYJxJDBOvgCxKO3FWMjtrbLtzqiLWA3JAqh1EYhcEVxMzoY9dDq3kyMxl3pM4SFZYOE0c0VwFT4b9hcmYj2340V6rtTHmN4edVh94iGBXBSGNAEwhOh53zd6NTfK2jEs3OJAFGlAHBeJAYkfBGf9nzCrK70aA2FYGAaAkyeGq/w/4wHFkz7yeaWL9agNMCgMLC4SdwznFjgfDyieTXuOT00ru7hjuju1YfXjSHjDuAj8r/BDiHl/9c4aU6hFsxt3BDzqQBBJFBDIeQsGND4Yh8MnhVdGmw==" -------------------------------------------------------------------------------- /packages/gesturehandler/platforms/android/java/com/swmansion/gesturehandler/GestureHandlerInteractionController.java: -------------------------------------------------------------------------------- 1 | package com.swmansion.gesturehandler; 2 | 3 | public interface GestureHandlerInteractionController { 4 | boolean shouldWaitForHandlerFailure(GestureHandler handler, GestureHandler otherHandler); 5 | 6 | boolean shouldRequireHandlerToWaitForFailure(GestureHandler handler, GestureHandler otherHandler); 7 | 8 | boolean shouldRecognizeSimultaneously(GestureHandler handler, GestureHandler otherHandler); 9 | 10 | boolean shouldHandlerBeCancelledBy(GestureHandler handler, GestureHandler otherHandler); 11 | } 12 | -------------------------------------------------------------------------------- /packages/gesturehandler/platforms/android/java/com/swmansion/gesturehandler/PointerEvents.java: -------------------------------------------------------------------------------- 1 | package com.swmansion.gesturehandler; 2 | 3 | public enum PointerEvents { 4 | 5 | /** 6 | * Neither the container nor its children receive events. 7 | */ 8 | NONE, 9 | 10 | /** 11 | * Container doesn't get events but all of its children do. 12 | */ 13 | BOX_NONE, 14 | 15 | /** 16 | * Container gets events but none of its children do. 17 | */ 18 | BOX_ONLY, 19 | 20 | /** 21 | * Container and all of its children receive touch events (like pointerEvents is 22 | * unspecified). 23 | */ 24 | AUTO,; 25 | } 26 | -------------------------------------------------------------------------------- /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /packages/gesturehandler/platforms/android/java/com/swmansion/gesturehandler/PointerEventsSpec.java: -------------------------------------------------------------------------------- 1 | package com.swmansion.gesturehandler; 2 | 3 | public enum PointerEventsSpec { 4 | 5 | /** 6 | * Neither the container nor its children receive events. 7 | */ 8 | NONE, 9 | 10 | /** 11 | * Container doesn't get events but all of its children do. 12 | */ 13 | BOX_NONE, 14 | 15 | /** 16 | * Container gets events but none of its children do. 17 | */ 18 | BOX_ONLY, 19 | 20 | /** 21 | * Container and all of its children receive touch events (like pointerEvents is 22 | * unspecified). 23 | */ 24 | AUTO,; 25 | } 26 | -------------------------------------------------------------------------------- /packages/gesturehandler/platforms/android/java/com/swmansion/gesturehandler/PointerEventsConfig.java: -------------------------------------------------------------------------------- 1 | package com.swmansion.gesturehandler; 2 | 3 | public enum PointerEventsConfig { 4 | 5 | /** 6 | * Neither the container nor its children receive events. 7 | */ 8 | NONE, 9 | 10 | /** 11 | * Container doesn't get events but all of its children do. 12 | */ 13 | BOX_NONE, 14 | 15 | /** 16 | * Container gets events but none of its children do. 17 | */ 18 | BOX_ONLY, 19 | 20 | /** 21 | * Container and all of its children receive touch events (like pointerEvents is 22 | * unspecified). 23 | */ 24 | AUTO,; 25 | } 26 | -------------------------------------------------------------------------------- /packages/gesturehandler/platforms/ios/src/TapHandler.h: -------------------------------------------------------------------------------- 1 | // 2 | // TapHandler.h 3 | // GestureHandler 4 | // 5 | // Created by Krzysztof Magiera on 12/10/2017. 6 | // Copyright © 2017 Software Mansion. All rights reserved. 7 | // 8 | 9 | #import "GestureHandler.h" 10 | 11 | @interface TapGestureHandler : GestureHandler 12 | -(void)resetStored; 13 | - (void)setMaxDist:(CGFloat)value; 14 | - (void)setNumberOfTaps:(NSUInteger)value; 15 | - (void)setMaxDelayMs:(CGFloat)value; 16 | - (void)setMaxDurationMs:(CGFloat)value; 17 | - (void)setMaxDeltaX:(CGFloat)value; 18 | - (void)setMaxDeltaY:(CGFloat)value; 19 | - (void)setMinPointers:(NSInteger)value; 20 | @end 21 | -------------------------------------------------------------------------------- /src-native/android/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | google() 6 | mavenCentral() 7 | } 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:3.1.3' 10 | 11 | // NOTE: Do not place your application dependencies here; they belong 12 | // in the individual module build.gradle files 13 | } 14 | } 15 | 16 | allprojects { 17 | repositories { 18 | google() 19 | mavenCentral() 20 | } 21 | } 22 | 23 | task clean(type: Delete) { 24 | delete rootProject.buildDir 25 | } 26 | -------------------------------------------------------------------------------- /packages/gesturehandler/platforms/ios/src/GestureHandlerRegistry.h: -------------------------------------------------------------------------------- 1 | // 2 | // GestureHandlerRegistry.h 3 | // GestureHandler 4 | // 5 | // Created by Krzysztof Magiera on 12/10/2017. 6 | // Copyright © 2017 Software Mansion. All rights reserved. 7 | // 8 | 9 | #import "GestureHandler.h" 10 | 11 | @interface GestureHandlerRegistry : NSObject 12 | 13 | - (nullable GestureHandler *)handlerWithTag:(nonnull NSNumber *)handlerTag; 14 | - (void)registerGestureHandler:(nonnull GestureHandler *)gestureHandler; 15 | - (void)attachHandlerWithTag:(nonnull NSNumber *)handlerTag toView:(nonnull UIView *)view; 16 | - (void)dropHandlerWithTag:(nonnull NSNumber *)handlerTag; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /packages/gesturehandler/platforms/android/java/com/swmansion/gesturehandler/BaseGestureHandlerInteractionController.java: -------------------------------------------------------------------------------- 1 | package com.swmansion.gesturehandler; 2 | 3 | public abstract class BaseGestureHandlerInteractionController implements GestureHandlerInteractionController { 4 | 5 | @Override 6 | public boolean shouldWaitForHandlerFailure(GestureHandler handler, GestureHandler otherHandler) { 7 | return false; 8 | } 9 | 10 | @Override 11 | public boolean shouldRequireHandlerToWaitForFailure(GestureHandler handler, GestureHandler otherHandler) { 12 | return false; 13 | } 14 | 15 | @Override 16 | public boolean shouldRecognizeSimultaneously(GestureHandler handler, GestureHandler otherHandler) { 17 | return false; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src-native/android/gesturehandler/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /home/plamen5kov/tools/android-sdk-linux/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /packages/gesturehandler/platforms/ios/src/GestureHandlerHeader.h: -------------------------------------------------------------------------------- 1 | 2 | #import 3 | 4 | //! Project version number for GestureHandler. 5 | FOUNDATION_EXPORT double GestureHandlerVersionNumber; 6 | 7 | //! Project version string for GestureHandler. 8 | FOUNDATION_EXPORT const unsigned char GestureHandlerVersionString[]; 9 | 10 | #import "GestureHandler.h" 11 | #import "GestureHandlerManager.h" 12 | #import "GestureHandlerRegistry.h" 13 | #import "GestureHandlerState.h" 14 | #import "GestureHandlerEvents.h" 15 | #import "GestureHandlerDirection.h" 16 | #import "FlingHandler.h" 17 | #import "ForceTouchHandler.h" 18 | #import "LongPressHandler.h" 19 | #import "NativeViewHandler.h" 20 | #import "PinchHandler.h" 21 | #import "PanHandler.h" 22 | #import "RotationHandler.h" 23 | #import "TapHandler.h" 24 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.38", 3 | "$schema": "node_modules/@lerna-lite/cli/schemas/lerna-schema.json", 4 | "packages": [ 5 | "packages/*" 6 | ], 7 | "npmClient": "yarn", 8 | "useWorkspaces": true, 9 | "command": { 10 | "publish": { 11 | "cleanupTempFiles": true 12 | } 13 | }, 14 | "npmClientArgs": [ 15 | "--no-package-lock" 16 | ], 17 | "commitHooks": false, 18 | "createRelease": "github", 19 | "conventionalCommits": true, 20 | "private": false, 21 | "message": "chore(release): publish new version %v", 22 | "changelogPreset": "conventional-changelog-conventionalcommits", 23 | "ignoreChanges": [ 24 | "**/__fixtures__/**", 25 | "**/__tests__/**", 26 | "**/*.md" 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /src-native/android/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | android 4 | Project android created by Buildship. 5 | 6 | 7 | 8 | 9 | org.eclipse.buildship.core.gradleprojectbuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.buildship.core.gradleprojectnature 16 | 17 | 18 | 19 | 1599418663171 20 | 21 | 30 22 | 23 | org.eclipse.core.resources.regexFilterMatcher 24 | node_modules|.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /packages/gesturehandler/platforms/android/res/values/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 12 | 27mm 13 | -------------------------------------------------------------------------------- /src-native/android/build.sh: -------------------------------------------------------------------------------- 1 | set -e 2 | set -o pipefail 3 | 4 | CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 5 | 6 | SOURCE_NAME="gesturehandler" 7 | ANDROID_SOURCE_DIR="$CURRENT_DIR" 8 | 9 | PROJECT_NAME="$SOURCE_NAME" 10 | 11 | BUILD_OUTPUT_DIR="$ANDROID_SOURCE_DIR/$PROJECT_NAME/build/outputs/aar/" 12 | 13 | PLUGIN_TARGET_DIR="$CURRENT_DIR/../../plugin/platforms" 14 | PLUGIN_TARGET_SUBDIR="$PLUGIN_TARGET_DIR/android" 15 | 16 | cd $ANDROID_SOURCE_DIR 17 | 18 | ./gradlew clean assembleRelease 19 | 20 | echo "$PROJECT_NAME-release.aar was built in $BUILD_OUTPUT_DIR" 21 | 22 | if [ ! -d $PLUGIN_TARGET_DIR ]; then 23 | mkdir $PLUGIN_TARGET_DIR 24 | fi 25 | 26 | if [ ! -d $PLUGIN_TARGET_SUBDIR ]; then 27 | mkdir $PLUGIN_TARGET_SUBDIR 28 | fi 29 | 30 | # cp -R "$BUILD_OUTPUT_DIR/$PROJECT_NAME-release.aar" $PLUGIN_TARGET_SUBDIR 31 | 32 | # echo "force livesync" > "$PLUGIN_TARGET_SUBDIR/sync" 33 | 34 | # echo "Android library was copied to $PLUGIN_TARGET_SUBDIR" 35 | 36 | cd $CURRENT_DIR 37 | -------------------------------------------------------------------------------- /packages/gesturehandler/platforms/ios/src/GestureHandlerManager.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @class GestureHandler; 5 | @interface GestureHandlerManager : NSObject 6 | 7 | - (nonnull instancetype)init; 8 | 9 | - (GestureHandler*)createGestureHandler:(nonnull NSString *)handlerName 10 | tag:(nonnull NSNumber *)handlerTag 11 | config:(nonnull NSDictionary *)config; 12 | 13 | - (void)attachGestureHandler:(nonnull NSNumber *)handlerTag 14 | toView:(nonnull UIView *)view; 15 | 16 | - (void)updateGestureHandler:(nonnull NSNumber *)handlerTag config:(nonnull NSDictionary *)config; 17 | 18 | - (void)dropGestureHandler:(nonnull NSNumber *)handlerTag; 19 | - (void)registerGestureHandler:(nonnull GestureHandler *)gestureHandler; 20 | 21 | //- (void)handleSetJSResponder:(nonnull UIView *)view 22 | // blockNativeResponder:(nonnull NSNumber *)blockNativeResponder; 23 | 24 | //- (void)handleClearJSResponder; 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # NativeScript 2 | hooks/ 3 | node_modules/ 4 | platforms 5 | 6 | # NativeScript Template 7 | *.js.map 8 | !ngcc.config.js 9 | !webpack.config.js 10 | 11 | # Logs 12 | logs 13 | *.log 14 | npm-debug.log* 15 | yarn-debug.log* 16 | yarn-error.log* 17 | 18 | # General 19 | .DS_Store 20 | .AppleDouble 21 | .LSOverride 22 | .idea 23 | .cloud 24 | .gradle 25 | .project 26 | .yarn 27 | .cxx 28 | tmp/ 29 | 30 | !.eslintrc.js 31 | !.prettierrc.js 32 | 33 | !e2e/*.js 34 | !detox.config.js 35 | devices.js 36 | 37 | *.framework 38 | *.xcframework 39 | **/*.js.map 40 | src/**/*.js 41 | packages/**/*.js 42 | packages/**/*.d.ts 43 | bin 44 | build 45 | Pods 46 | !packages/*/platforms 47 | /packages/**/*.aar 48 | /packages/**/*.framework 49 | /packages/**/*.xcframework 50 | /demo-snippets/**/*.aar 51 | *.xcuserdatad 52 | /packages/README.md 53 | packages/**/*js.map 54 | packages/**/*js 55 | packages/angular 56 | packages/typings 57 | packages/**/angular/*.json 58 | packages/**/*.ngsummary.json 59 | packages/**/*.metadata.json 60 | 61 | .vscode/settings.json 62 | 63 | /blueprint.md -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | nativescript-gesturehandler 4 | Project nativescript-gesturehandler created by Buildship. 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.buildship.core.gradleprojectbuilder 15 | 16 | 17 | 18 | 19 | 20 | org.eclipse.jdt.core.javanature 21 | org.eclipse.buildship.core.gradleprojectnature 22 | 23 | 24 | 25 | 1604680591551 26 | 27 | 30 28 | 29 | org.eclipse.core.resources.regexFilterMatcher 30 | node_modules|.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /packages/gesturehandler/platforms/ios/src/GestureHandlerEvents.h: -------------------------------------------------------------------------------- 1 | 2 | #import 3 | #import 4 | 5 | #import "GestureHandlerState.h" 6 | 7 | #define SAFE_VELOCITY(velocity) @(isnan(velocity) ? 0 : velocity) 8 | 9 | 10 | @interface GestureHandlerEvent : NSObject 11 | @property (readonly) UIView *view; 12 | 13 | - (instancetype)initWithView:(UIView *)view 14 | handlerTag:(NSNumber *)handlerTag 15 | state:(GestureHandlerState)state 16 | extraData:(NSMutableDictionary*)extraData NS_DESIGNATED_INITIALIZER; 17 | 18 | @end 19 | 20 | 21 | @interface GestureHandlerStateChange : NSObject 22 | @property (readonly) UIView *view; 23 | 24 | - (instancetype)initWithView:(UIView *)view 25 | handlerTag:(NSNumber *)handlerTag 26 | state:(GestureHandlerState)state 27 | prevState:(GestureHandlerState)prevState 28 | extraData:(NSMutableDictionary*)extraData NS_DESIGNATED_INITIALIZER; 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /src-native/android/gesturehandler/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | gesturehandler 4 | Project additions created by Buildship. 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.buildship.core.gradleprojectbuilder 15 | 16 | 17 | 18 | 19 | 20 | org.eclipse.jdt.core.javanature 21 | org.eclipse.buildship.core.gradleprojectnature 22 | 23 | 24 | 25 | 1599418663193 26 | 27 | 30 28 | 29 | org.eclipse.core.resources.regexFilterMatcher 30 | node_modules|.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /packages/gesturehandler/platforms/ios/src/PinchHandler.m: -------------------------------------------------------------------------------- 1 | // 2 | // PinchHandler.m 3 | // GestureHandler 4 | // 5 | // Created by Krzysztof Magiera on 12/10/2017. 6 | // Copyright © 2017 Software Mansion. All rights reserved. 7 | // 8 | 9 | #import "PinchHandler.h" 10 | 11 | @implementation PinchGestureHandler 12 | 13 | - (instancetype)initWithTag:(NSNumber *)tag 14 | { 15 | if ((self = [super initWithTag:tag])) { 16 | #if !TARGET_OS_TV 17 | _recognizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(handleGesture:)]; 18 | #endif 19 | } 20 | return self; 21 | } 22 | 23 | #if !TARGET_OS_TV 24 | - (NSMutableDictionary *)eventExtraData:(UIPinchGestureRecognizer *)recognizer 25 | { 26 | NSMutableDictionary* result = [super eventExtraData:recognizer]; 27 | [result setObject:@(recognizer.scale) forKey:@"scale"]; 28 | [result setObject:SAFE_VELOCITY(recognizer.velocity) forKey:@"velocity"]; 29 | [result setObject:[result objectForKey:@"x"] forKey:@"focalX"]; 30 | [result setObject:[result objectForKey:@"y"] forKey:@"focalY"]; 31 | return result; 32 | } 33 | #endif 34 | 35 | @end 36 | 37 | -------------------------------------------------------------------------------- /packages/gesturehandler/platforms/ios/src/RotationHandler.m: -------------------------------------------------------------------------------- 1 | // 2 | // RotationHandler.m 3 | // GestureHandler 4 | // 5 | // Created by Krzysztof Magiera on 12/10/2017. 6 | // Copyright © 2017 Software Mansion. All rights reserved. 7 | // 8 | 9 | #import "RotationHandler.h" 10 | 11 | @implementation RotationGestureHandler 12 | 13 | - (instancetype)initWithTag:(NSNumber *)tag 14 | { 15 | if ((self = [super initWithTag:tag])) { 16 | #if !TARGET_OS_TV 17 | _recognizer = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(handleGesture:)]; 18 | #endif 19 | } 20 | return self; 21 | } 22 | 23 | #if !TARGET_OS_TV 24 | - (NSMutableDictionary *)eventExtraData:(UIRotationGestureRecognizer *)recognizer 25 | { 26 | NSMutableDictionary* result = [super eventExtraData:recognizer]; 27 | [result setObject:@(recognizer.velocity) forKey:@"velocity"]; 28 | [result setObject:@(recognizer.rotation) forKey:@"rotation"]; 29 | [result setObject:[result objectForKey:@"x"] forKey:@"anchorX"]; 30 | [result setObject:[result objectForKey:@"y"] forKey:@"anchorY"]; 31 | return result; 32 | } 33 | #endif 34 | 35 | @end 36 | 37 | -------------------------------------------------------------------------------- /src-native/android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true 19 | 20 | # Due to a known issue with Android Gradle Plugin versions 3.0.* and 3.1.*, 21 | # the configuration on demand should be disabled. 22 | # https://developer.android.com/studio/known-issues 23 | org.gradle.configureondemand=false -------------------------------------------------------------------------------- /docs/media/Basic.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 38 | 39 | 49 | -------------------------------------------------------------------------------- /demo-snippets/vue/Basic.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 38 | 39 | 49 | -------------------------------------------------------------------------------- /.github/issue_template.md: -------------------------------------------------------------------------------- 1 | ### Make sure to check the demo app(s) for sample usage 2 | 3 | ### Make sure to check the existing issues in this repository 4 | 5 | ### If the demo apps cannot help and there is no issue for your problem, tell us about it 6 | Please, ensure your title is less than 63 characters long and starts with a capital 7 | letter. 8 | 9 | ### Which platform(s) does your issue occur on? 10 | - iOS/Android/Both 11 | - iOS/Android versions 12 | - emulator or device. What type of device? 13 | 14 | ### Please, provide the following version numbers that your issue occurs with: 15 | 16 | - CLI: (run `tns --version` to fetch it) 17 | - Cross-platform modules: (check the 'version' attribute in the 18 | `node_modules/@nativescript/core/package.json` file in your project) 19 | - Runtime(s): (look for the `"tns-android"` and `"tns-ios"` properties in the `package.json` file of your project) 20 | - Plugin(s): (look for the version numbers in the `package.json` file of your 21 | project and paste your dependencies and devDependencies here) 22 | 23 | ### Please, tell us how to recreate the issue in as much detail as possible. 24 | Describe the steps to reproduce it. 25 | 26 | ### Is there any code involved? 27 | - provide a code example to recreate the problem 28 | - (EVEN BETTER) provide a .zip with application or refer to a repository with application where the problem is reproducible. 29 | -------------------------------------------------------------------------------- /src/gesturehandler/typings/extensions.android.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-unnecessary-qualifier */ 2 | declare namespace com { 3 | export namespace nativescript { 4 | export namespace gesturehandler { 5 | class GestureHandlerInteractionController extends com.swmansion.gesturehandler.GestureHandlerInteractionController { 6 | configureInteractions(handler: com.swmansion.gesturehandler.GestureHandler, waitFor: number[], simultaneousHandlers: number[]); 7 | } 8 | class RootViewGestureHandler extends com.swmansion.gesturehandler.GestureHandler {} 9 | class PageLayout extends org.nativescript.widgets.GridLayout { 10 | constructor(context, rootGestureTag); 11 | initialize(); 12 | tearDown(); 13 | registry(): com.swmansion.gesturehandler.GestureHandlerRegistryImpl; 14 | getRootGestureTag(): number; 15 | } 16 | } 17 | } 18 | } 19 | 20 | // TODO: to be removed once @nativescript/types-android is fixed https://github.com/NativeScript/NativeScript/pull/10791 21 | declare namespace org { 22 | namespace nativescript { 23 | namespace widgets { 24 | interface GridLayout { 25 | addRow(itemSpec: ItemSpec): void; 26 | addColumn(itemSpec: ItemSpec): void; 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /packages/gesturehandler/platforms/ios/src/GestureHandlerRegistry.m: -------------------------------------------------------------------------------- 1 | // 2 | // RNGestureHandlerRegistry.m 3 | // RNGestureHandler 4 | // 5 | // Created by Krzysztof Magiera on 12/10/2017. 6 | // Copyright © 2017 Software Mansion. All rights reserved. 7 | // 8 | 9 | #import "GestureHandlerRegistry.h" 10 | 11 | 12 | @implementation GestureHandlerRegistry { 13 | NSMutableDictionary *_handlers; 14 | } 15 | 16 | - (instancetype)init 17 | { 18 | if ((self = [super init])) { 19 | _handlers = [NSMutableDictionary new]; 20 | } 21 | return self; 22 | } 23 | 24 | - (GestureHandler *)handlerWithTag:(NSNumber *)handlerTag 25 | { 26 | return _handlers[handlerTag]; 27 | } 28 | 29 | - (void)registerGestureHandler:(GestureHandler *)gestureHandler 30 | { 31 | if ([_handlers objectForKey:gestureHandler.tag] == nil) { 32 | _handlers[gestureHandler.tag] = gestureHandler; 33 | } 34 | } 35 | 36 | - (void)attachHandlerWithTag:(NSNumber *)handlerTag toView:(UIView *)view 37 | { 38 | GestureHandler *handler = _handlers[handlerTag]; 39 | NSAssert(handler != nil, @"Handler for tag %@ does not exists", handlerTag); 40 | [handler unbindFromView]; 41 | [handler bindToView:view]; 42 | } 43 | 44 | - (void)dropHandlerWithTag:(NSNumber *)handlerTag 45 | { 46 | GestureHandler *handler = _handlers[handlerTag]; 47 | [handler unbindFromView]; 48 | [_handlers removeObjectForKey:handlerTag]; 49 | } 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /packages/gesturehandler/platforms/ios/src/PanHandler.h: -------------------------------------------------------------------------------- 1 | // 2 | // PanHandler.h 3 | // GestureHandler 4 | // 5 | // Created by Krzysztof Magiera on 12/10/2017. 6 | // Copyright © 2017 Software Mansion. All rights reserved. 7 | // 8 | 9 | #import "GestureHandler.h" 10 | 11 | @interface PanGestureHandler : GestureHandler 12 | 13 | //@property (nonatomic) CGFloat minDist; 14 | //@property (nonatomic) CGFloat minVelocityX; 15 | //@property (nonatomic) CGFloat minVelocityY; 16 | //@property (nonatomic) CGFloat activeOffsetXStart; 17 | //@property (nonatomic) CGFloat activeOffsetXEnd; 18 | //@property (nonatomic) CGFloat failOffsetXStart; 19 | //@property (nonatomic) CGFloat failOffsetXEnd; 20 | //@property (nonatomic) CGFloat activeOffsetYStart; 21 | //@property (nonatomic) CGFloat activeOffsetYEnd; 22 | //@property (nonatomic) CGFloat failOffsetYStart; 23 | //@property (nonatomic) CGFloat failOffsetYEnd; 24 | 25 | - (void)setMinDist:(CGFloat)value; 26 | - (void)setMinVelocityX:(CGFloat)value; 27 | - (void)setMinVelocityY:(CGFloat)value; 28 | - (void)setMinVelocitySq:(CGFloat)value; 29 | - (void)setActiveOffsetXStart:(CGFloat)value; 30 | - (void)setActiveOffsetXEnd:(CGFloat)value; 31 | - (void)setFailOffsetXStart:(CGFloat)value; 32 | - (void)setFailOffsetXEnd:(CGFloat)value; 33 | - (void)setActiveOffsetYStart:(CGFloat)value; 34 | - (void)setActiveOffsetYEnd:(CGFloat)value; 35 | - (void)setFailOffsetYStart:(CGFloat)value; 36 | - (void)setFailOffsetYEnd:(CGFloat)value; 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /src-native/ios/GestureHandler.xcodeproj/xcuserdata/mguillon.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | GestureHandler.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 3 11 | 12 | GestureHandlerApp.xcscheme_^#shared#^_ 13 | 14 | orderHint 15 | 2 16 | 17 | GestureHandlerLib.xcscheme_^#shared#^_ 18 | 19 | orderHint 20 | 0 21 | 22 | test.xcscheme_^#shared#^_ 23 | 24 | orderHint 25 | 5 26 | 27 | universal.xcscheme_^#shared#^_ 28 | 29 | orderHint 30 | 1 31 | 32 | 33 | SuppressBuildableAutocreation 34 | 35 | BF6DBD7F1C109B9800FC37E0 36 | 37 | primary 38 | 39 | 40 | BF6DBD8C1C109BD100FC37E0 41 | 42 | primary 43 | 44 | 45 | D5BCF18022A7A30A00134E09 46 | 47 | primary 48 | 49 | 50 | D5BCF1D522A7AA4400134E09 51 | 52 | primary 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /packages/gesturehandler/platforms/android/java/com/nativescript/gesturehandler/RootViewGestureHandler.java: -------------------------------------------------------------------------------- 1 | package com.nativescript.gesturehandler; 2 | 3 | import android.content.Context; 4 | import android.view.MotionEvent; 5 | import com.swmansion.gesturehandler.GestureHandler; 6 | import android.os.SystemClock; 7 | import android.view.View; 8 | import android.util.Log; 9 | 10 | public class RootViewGestureHandler extends GestureHandler { 11 | private static final String TAG = "RootViewGestureHandler"; 12 | public RootViewGestureHandler() { 13 | super(); 14 | } 15 | 16 | public PageLayout getView() { 17 | return (PageLayout)super.getView(); 18 | } 19 | protected void onHandle(MotionEvent event) { 20 | final int currentState = getState(); 21 | if (currentState == GestureHandler.STATE_UNDETERMINED) { 22 | begin(); 23 | getView().setShouldIntercept(false); 24 | } 25 | if (event.getActionMasked() == MotionEvent.ACTION_UP) { 26 | end(); 27 | } 28 | } 29 | 30 | protected void onCancel() { 31 | if (GestureHandler.debug) { 32 | Log.d("JS", "RootViewGestureHandler onCancel"); 33 | } 34 | getView().setShouldIntercept(true); 35 | final long time = SystemClock.uptimeMillis(); 36 | final MotionEvent event = MotionEvent.obtain(time, time, MotionEvent.ACTION_CANCEL, 0, 0, 0); 37 | event.setAction(MotionEvent.ACTION_CANCEL); 38 | getView().setDispatchToOrchestra(false); 39 | getView().dispatchTouchEvent(event); 40 | getView().setDispatchToOrchestra(true); 41 | event.recycle(); 42 | } 43 | // public boolean shouldRecognizeSimultaneously(GestureHandler handler) { 44 | // return true; 45 | // } 46 | } -------------------------------------------------------------------------------- /src-native/android/gesturehandler/build.gradle: -------------------------------------------------------------------------------- 1 | 2 | 3 | apply plugin: 'com.android.library' 4 | 5 | def computeCompileSdkVersion () { 6 | if(project.hasProperty("compileSdk")) { 7 | return compileSdk 8 | } 9 | else { 10 | return 27 11 | } 12 | } 13 | 14 | def computeBuildToolsVersion() { 15 | if(project.hasProperty("buildToolsVersion")) { 16 | return buildToolsVersion 17 | } 18 | else { 19 | return "27.0.3" 20 | } 21 | } 22 | 23 | def computeSupportVersion() { 24 | if(project.hasProperty("supportVersion")) { 25 | return supportVersion 26 | } 27 | else { 28 | return "27.1.1" 29 | } 30 | } 31 | 32 | def computeTargetSdkVersion() { 33 | if(project.hasProperty("targetSdk")) { 34 | return targetSdk 35 | } 36 | else { 37 | return 27 38 | } 39 | } 40 | 41 | android { 42 | compileSdkVersion computeCompileSdkVersion() 43 | buildToolsVersion computeBuildToolsVersion() 44 | 45 | defaultConfig { 46 | minSdkVersion 16 47 | targetSdkVersion computeTargetSdkVersion() 48 | versionCode 1 49 | versionName "1.0" 50 | } 51 | buildTypes { 52 | release { 53 | minifyEnabled false 54 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 55 | } 56 | } 57 | } 58 | 59 | 60 | dependencies { 61 | compile(name:'widgets-release', ext:'aar') 62 | implementation "androidx.annotation:annotation:1.1.0" 63 | } 64 | repositories { 65 | mavenCentral() 66 | flatDir { 67 | dirs '../../../node_modules/@nativescript/core/platforms/android' 68 | } 69 | } 70 | 71 | task cleanBuildDir (type: Delete) { 72 | delete "../build/" 73 | } 74 | 75 | task copyAar << { 76 | copy { 77 | from "build/outputs/aar/gesturehandler-release.aar" 78 | into "../build/" 79 | } 80 | } 81 | 82 | assemble.dependsOn(cleanBuildDir) 83 | copyAar.dependsOn(assemble) 84 | build.dependsOn(copyAar) -------------------------------------------------------------------------------- /packages/gesturehandler/platforms/android/java/com/swmansion/gesturehandler/GestureUtils.java: -------------------------------------------------------------------------------- 1 | package com.swmansion.gesturehandler; 2 | 3 | import android.view.MotionEvent; 4 | 5 | public class GestureUtils { 6 | public static float getLastPointerX(MotionEvent event, boolean averageTouches) { 7 | float offset = event.getRawX() - event.getX(); 8 | int excludeIndex = event.getActionMasked() == MotionEvent.ACTION_POINTER_UP ? event.getActionIndex() : -1; 9 | 10 | if (averageTouches) { 11 | float sum = 0f; 12 | int count = 0; 13 | for (int i = 0, size = event.getPointerCount(); i < size; i++) { 14 | if (i != excludeIndex) { 15 | sum += event.getX(i) + offset; 16 | count++; 17 | } 18 | } 19 | return sum / count; 20 | } else { 21 | int lastPointerIdx = event.getPointerCount() - 1; 22 | if (lastPointerIdx == excludeIndex) { 23 | lastPointerIdx--; 24 | } 25 | return event.getX(lastPointerIdx) + offset; 26 | } 27 | } 28 | 29 | public static float getLastPointerY(MotionEvent event, boolean averageTouches) { 30 | float offset = event.getRawY() - event.getY(); 31 | int excludeIndex = event.getActionMasked() == MotionEvent.ACTION_POINTER_UP ? event.getActionIndex() : -1; 32 | 33 | if (averageTouches) { 34 | float sum = 0f; 35 | int count = 0; 36 | for (int i = 0, size = event.getPointerCount(); i < size; i++) { 37 | if (i != excludeIndex) { 38 | sum += event.getY(i) + offset; 39 | count++; 40 | } 41 | } 42 | return sum / count; 43 | } else { 44 | int lastPointerIdx = event.getPointerCount() - 1; 45 | if (lastPointerIdx == excludeIndex) { 46 | lastPointerIdx -= 1; 47 | } 48 | return event.getY(lastPointerIdx) + offset; 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /packages/gesturehandler/platforms/android/include.gradle: -------------------------------------------------------------------------------- 1 | import groovy.json.JsonSlurper 2 | 3 | dependencies { 4 | implementation "androidx.annotation:annotation:1.1.0" 5 | 6 | if (project.hasProperty("tempBuild")) { 7 | // we need to copy the code in both places as N main gradle system does not support top level code 8 | // for now we support only @nativescript/core and @akylas/nativescript 9 | // we should have a more generic way 10 | def widgetsDir = "$USER_PROJECT_ROOT/node_modules/@nativescript/core/platforms/android" 11 | def appPackageJsonFile = file("$USER_PROJECT_ROOT/package.json") 12 | if (appPackageJsonFile.exists()) { 13 | def appPackageJson = new JsonSlurper().parseText(appPackageJsonFile.text) 14 | if (appPackageJson.dependencies['@akylas/nativescript'] != null) { 15 | widgetsDir = "$USER_PROJECT_ROOT/node_modules/@akylas/nativescript/platforms/android" 16 | } 17 | } 18 | 19 | // if ui-mobile-base is provided as source the name is nativescript.aar 20 | //else use widget-release.aar 21 | if (file("$widgetsDir/widgets-release.aar").exists()) { 22 | implementation(name:'widgets-release', ext:'aar') 23 | } else { 24 | implementation(name:'nativescript', ext:'aar') 25 | } 26 | } 27 | } 28 | repositories { 29 | if (project.hasProperty("tempBuild")) { 30 | // we need to copy the code in both places as N main gradle system does not support top level code 31 | // for now we support only @nativescript/core and @akylas/nativescript 32 | // we should have a more generic way 33 | def widgetsDir = "$USER_PROJECT_ROOT/node_modules/@nativescript/core/platforms/android" 34 | def appPackageJsonFile = file("$USER_PROJECT_ROOT/package.json") 35 | if (appPackageJsonFile.exists()) { 36 | def appPackageJson = new JsonSlurper().parseText(appPackageJsonFile.text) 37 | if (appPackageJson.dependencies['@akylas/nativescript'] != null) { 38 | widgetsDir = "$USER_PROJECT_ROOT/node_modules/@akylas/nativescript/platforms/android" 39 | } 40 | } 41 | flatDir { 42 | dirs "$widgetsDir" 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /packages/gesturehandler/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@nativescript-community/gesturehandler", 3 | "version": "2.0.38", 4 | "description": "Declarative API exposing platform native touch and gesture system to NativeScript.", 5 | "main": "gesturehandler", 6 | "sideEffects": false, 7 | "typings": "gesturehandler.d.ts", 8 | "scripts": { 9 | "build": "npm run tsc", 10 | "build.win": "npm run tsc.win && npm run readme", 11 | "build.all": "npm run build", 12 | "build.all.win": "npm run build .win", 13 | "build.angular": "ng-packagr -p ../../src/gesturehandler/angular/package.json -c ../../src/gesturehandler/angular/tsconfig.json && rm angular/.npmignore", 14 | "build.angular.win": ".ng-packagr -p ..\\..\\src\\gesturehandler\\angular\\package.json -c ..\\..\\src\\gesturehandler\\angular\\tsconfig.json", 15 | "readme": "readme generate -c ../../tools/readme/blueprint.json", 16 | "tsc": "cpy '**/*.d.ts' '../../packages/gesturehandler' --parents --cwd=../../src/gesturehandler && tsc -skipLibCheck -d", 17 | "tsc.win": ".cpy '**\\*.d.ts' '..\\..\\packages\\gesturehandler' --parents --cwd=..\\..\\src\\gesturehandler && .tsc -skipLibCheck -d", 18 | "clean": "rimraf ./*.d.ts ./*.js ./*.js.map", 19 | "clean.win": ".rimraf .\\*.d.ts .\\*.js .\\*.js.map" 20 | }, 21 | "nativescript": { 22 | "platforms": { 23 | "android": "6.2.1", 24 | "ios": "6.2.1" 25 | } 26 | }, 27 | "keywords": [ 28 | "NativeScript", 29 | "JavaScript", 30 | "iOS", 31 | "Android", 32 | "Vue", 33 | "preview|https://raw.githubusercontent.com/nativescript-community/gesturehandler/master/images/demo.gif" 34 | ], 35 | "author": { 36 | "name": "Martin Guillon", 37 | "email": "martin.guillon@akylas.fr" 38 | }, 39 | "bugs": { 40 | "url": "https://github.com/nativescript-community/gesturehandler/issues" 41 | }, 42 | "license": "Apache-2.0", 43 | "repository": { 44 | "type": "git", 45 | "url": "https://github.com/nativescript-community/gesturehandler" 46 | }, 47 | "bootstrapper": "nativescript-plugin-seed", 48 | "dependencies": { 49 | "@nativescript-community/observable": "^2.0.10" 50 | }, 51 | "gitHead": "531e9068c445832a6faf6bb8e227b738baa6ef18" 52 | } 53 | -------------------------------------------------------------------------------- /packages/gesturehandler/platforms/android/java/com/swmansion/gesturehandler/LongPressGestureHandler.java: -------------------------------------------------------------------------------- 1 | package com.swmansion.gesturehandler; 2 | 3 | import android.content.Context; 4 | import android.os.Handler; 5 | import android.view.MotionEvent; 6 | 7 | public class LongPressGestureHandler extends GestureHandler { 8 | 9 | private static final long DEFAULT_MIN_DURATION_MS = 500; // 1 sec 10 | private static float DEFAULT_MAX_DIST_DP = 10; // 20dp 11 | 12 | private long mMinDurationMs = DEFAULT_MIN_DURATION_MS; 13 | private float mMaxDistSq; 14 | private float mStartX, mStartY; 15 | private Handler mHandler; 16 | 17 | public LongPressGestureHandler(Context context) { 18 | setShouldCancelWhenOutside(true); 19 | mMaxDistSq = DEFAULT_MAX_DIST_DP * context.getResources().getDisplayMetrics().density; 20 | } 21 | 22 | public void setMinDurationMs(long minDurationMs) { 23 | mMinDurationMs = minDurationMs; 24 | } 25 | 26 | public LongPressGestureHandler setMaxDist(float maxDist) { 27 | mMaxDistSq = maxDist * maxDist; 28 | return this; 29 | } 30 | 31 | @Override 32 | protected void onHandle(MotionEvent event) { 33 | if (getState() == STATE_UNDETERMINED) { 34 | begin(); 35 | mStartX = event.getRawX(); 36 | mStartY = event.getRawY(); 37 | mHandler = new Handler(); 38 | if (mMinDurationMs > 0) { 39 | mHandler.postDelayed(new Runnable() { 40 | @Override 41 | public void run() { 42 | activate(); 43 | } 44 | }, mMinDurationMs); 45 | } else if (mMinDurationMs == 0) { 46 | activate(); 47 | } 48 | } 49 | if (event.getActionMasked() == MotionEvent.ACTION_UP) { 50 | if (mHandler != null) { 51 | mHandler.removeCallbacksAndMessages(null); 52 | mHandler = null; 53 | } 54 | if (getState() == STATE_ACTIVE) { 55 | end(); 56 | } else { 57 | fail(); 58 | } 59 | } else { 60 | // calculate distance from start 61 | float deltaX = event.getRawX() - mStartX; 62 | float deltaY = event.getRawY() - mStartY; 63 | float distSq = (float)Math.sqrt((double)(deltaX * deltaX + deltaY * deltaY)); 64 | if (distSq > mMaxDistSq) { 65 | if (getState() == STATE_ACTIVE) { 66 | cancel(); 67 | } else { 68 | fail(); 69 | } 70 | } 71 | } 72 | } 73 | 74 | @Override 75 | protected void onStateChange(int newState, int previousState) { 76 | if (mHandler != null) { 77 | mHandler.removeCallbacksAndMessages(null); 78 | mHandler = null; 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src-native/android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /src-native/android/gesturehandler/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /packages/gesturehandler/blueprint.md: -------------------------------------------------------------------------------- 1 | {{ load:../../tools/readme/edit-warning.md }} 2 | {{ template:title }} 3 | {{ template:badges }} 4 | {{ template:description }} 5 | 6 | {{ template:toc }} 7 | 8 | ## Installation 9 | 10 | Run the following command from the root of your project: 11 | 12 | `ns plugin add {{ pkg.name }}` 13 | 14 | ## API 15 | 16 | We need to do some wiring when your app starts, so open `app.ts` and add this before creating any View/App/Frame: 17 | 18 | ##### TypeScript 19 | 20 | ```ts 21 | import { install } from '@nativescript-community/gesturehandler'; 22 | install(); 23 | ``` 24 | 25 | You create a gesture handler using something like this: 26 | 27 | ```typescript 28 | import { GestureHandlerTouchEvent, GestureHandlerStateEvent, GestureStateEventData, GestureTouchEventData, HandlerType, Manager } from '@nativescript-community/gesturehandler'; 29 | 30 | function onGestureTouch(args: GestureTouchEventData) { 31 | const { state, extraData, view } = args.data; 32 | view.translateX = extraData.translationX; 33 | view.translateY = extraData.translationY; 34 | } 35 | function onGestureState(args: GestureStateEventData) { 36 | const { state, prevState, extraData, view } = args.data; 37 | console.log('onGestureState', state, prevState, view, extraData); 38 | } 39 | const manager = Manager.getInstance(); 40 | const gestureHandler = manager.createGestureHandler(HandlerType.PAN, 10, { 41 | shouldCancelWhenOutside: false 42 | }); 43 | gestureHandler.on(GestureHandlerTouchEvent, onGestureTouch, this); 44 | gestureHandler.on(GestureHandlerStateEvent, onGestureState, this); 45 | gestureHandler.attachToView(view); 46 | ``` 47 | 48 | Right now you must not forget to store the `gestureHandler` somewhere or the gesture won't work on iOS (native object being released). This will be fixed in future versions. 49 | 50 | Now about the API. All the gestures for the react counterpart exist with the same options and the same event `extraData`. 51 | 52 | ## GestureRootView 53 | 54 | For the gestures to work correctly we need a `root` view which knows how to handle the gestures. 55 | If using `Page` (thus `Frame`) you don't need to do anything. 56 | In case you don't (drawer root view, modals, ...) then you can wrap your views in a `GestureRootView` which inherits `GridLayout` 57 | 58 | ## Overriding Nativescript gestures 59 | 60 | This plugin can also override N gestures completely. This would give much more control over gestures and especially would allow to correctly handle simultaneous gestures likes `tap` and `longpress`. 61 | 62 | To do that 63 | 64 | ## Credits 65 | 66 | This is a port of [react-native-gesturehandler](https://kmagiera.github.io/react-native-gesture-handler/). 67 | The source is based on the source code by [Krzysztof Magiera](https://github.com/kmagiera). Don't hesitate to go and thank him for his work! 68 | 69 | ### Examples: 70 | 71 | - [Basic](demo-snippets/vue/Basic.vue) 72 | - A basic example showing that overriding N gestures works, even in modals 73 | 74 | {{ load:../../tools/readme/demos-and-development.md }} 75 | {{ load:../../tools/readme/questions.md }} 76 | -------------------------------------------------------------------------------- /packages/gesturehandler/platforms/ios/src/RootViewGestureRecognizer.m: -------------------------------------------------------------------------------- 1 | // 2 | // RNRootViewGestureRecognizer.m 3 | // RNGestureHandler 4 | // 5 | // Created by Krzysztof Magiera on 12/10/2017. 6 | // Copyright © 2017 Software Mansion. All rights reserved. 7 | // 8 | 9 | #import "RootViewGestureRecognizer.h" 10 | 11 | #import 12 | 13 | 14 | @implementation RootViewGestureRecognizer 15 | { 16 | BOOL _active; 17 | } 18 | 19 | @dynamic delegate; 20 | 21 | - (instancetype)init 22 | { 23 | if (self = [super init]) { 24 | self.delaysTouchesEnded = NO; 25 | self.delaysTouchesBegan = NO; 26 | } 27 | return self; 28 | } 29 | 30 | - (BOOL)shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer 31 | { 32 | // This method is used to implement "enabled" feature for gesture handlers. We enforce gesture 33 | // recognizers that are connected with "disabled" handlers to wait for the root gesture 34 | // recognizer to fail and this way we block them from acting. 35 | GestureHandler *otherHandler = [GestureHandler 36 | findGestureHandlerByRecognizer:otherGestureRecognizer]; 37 | if (otherHandler != nil && otherHandler.enabled == NO) { 38 | return YES; 39 | } 40 | return NO; 41 | } 42 | 43 | - (BOOL)canPreventGestureRecognizer:(UIGestureRecognizer *)preventedGestureRecognizer 44 | { 45 | return false; 46 | // return ![preventedGestureRecognizer isKindOfClass:[RCTTouchHandler class]]; 47 | } 48 | 49 | - (BOOL)canBePreventedByGestureRecognizer:(UIGestureRecognizer *)preventingGestureRecognizer 50 | { 51 | // When this method is called it means that one of handlers has activated, in this case we want 52 | // to send an info to JS so that it cancells all JS responders 53 | [self.delegate gestureRecognizer:preventingGestureRecognizer didActivateInRootView:self.view]; 54 | return [super canBePreventedByGestureRecognizer:preventingGestureRecognizer]; 55 | } 56 | 57 | - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 58 | { 59 | _active = YES; 60 | self.state = UIGestureRecognizerStatePossible; 61 | } 62 | 63 | - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event 64 | { 65 | self.state = UIGestureRecognizerStatePossible; 66 | } 67 | 68 | - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event 69 | { 70 | if (self.state == UIGestureRecognizerStateBegan || self.state == UIGestureRecognizerStateChanged) { 71 | self.state = UIGestureRecognizerStateEnded; 72 | } else { 73 | self.state = UIGestureRecognizerStateFailed; 74 | } 75 | [self reset]; 76 | _active = NO; 77 | } 78 | 79 | - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event 80 | { 81 | self.state = UIGestureRecognizerStateCancelled; 82 | [self reset]; 83 | _active = NO; 84 | } 85 | 86 | - (void)blockOtherRecognizers 87 | { 88 | if (_active) { 89 | self.state = UIGestureRecognizerStateBegan; 90 | } 91 | } 92 | 93 | @end 94 | -------------------------------------------------------------------------------- /src-native/ios/GestureHandler.xcodeproj/xcshareddata/xcschemes/test.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 52 | 53 | 59 | 60 | 66 | 67 | 68 | 69 | 71 | 72 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /src-native/ios/GestureHandler.xcodeproj/xcshareddata/xcschemes/universal.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 52 | 53 | 59 | 60 | 66 | 67 | 68 | 69 | 71 | 72 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /packages/gesturehandler/platforms/android/java/com/swmansion/gesturehandler/RotationGestureHandler.java: -------------------------------------------------------------------------------- 1 | package com.swmansion.gesturehandler; 2 | 3 | import android.view.MotionEvent; 4 | 5 | public class RotationGestureHandler extends GestureHandler { 6 | 7 | private static final double ROTATION_RECOGNITION_THRESHOLD = Math.PI / 36.; // 5 deg in radians 8 | 9 | private RotationGestureDetector mRotationGestureDetector; 10 | private double mLastRotation; 11 | private double mLastVelocity; 12 | 13 | private RotationGestureDetector.OnRotationGestureListener mGestureListener = new RotationGestureDetector.OnRotationGestureListener() { 14 | 15 | @Override 16 | public boolean onRotation(RotationGestureDetector detector) { 17 | double prevRotation = mLastRotation; 18 | mLastRotation += detector.getRotation(); 19 | long delta = detector.getTimeDelta(); 20 | if (delta > 0) { 21 | mLastVelocity = (mLastRotation - prevRotation) / delta; 22 | } 23 | if (Math.abs(mLastRotation) >= ROTATION_RECOGNITION_THRESHOLD && getState() == STATE_BEGAN) { 24 | activate(); 25 | } 26 | return true; 27 | } 28 | 29 | @Override 30 | public boolean onRotationBegin(RotationGestureDetector detector) { 31 | return true; 32 | } 33 | 34 | @Override 35 | public void onRotationEnd(RotationGestureDetector detector) { 36 | end(); 37 | } 38 | }; 39 | 40 | public RotationGestureHandler() { 41 | setShouldCancelWhenOutside(false); 42 | } 43 | 44 | @Override 45 | protected void onHandle(MotionEvent event) { 46 | int state = getState(); 47 | int activePointers = event.getPointerCount(); 48 | if (state == STATE_UNDETERMINED) { 49 | mLastVelocity = 0f; 50 | mLastRotation = 0f; 51 | if (mRotationGestureDetector == null) { 52 | mRotationGestureDetector = new RotationGestureDetector(mGestureListener); 53 | 54 | } 55 | 56 | begin(); 57 | } 58 | 59 | if (mRotationGestureDetector != null) { 60 | mRotationGestureDetector.onTouchEvent(event); 61 | } 62 | 63 | if (event.getActionMasked() == MotionEvent.ACTION_UP) { 64 | if (state == STATE_ACTIVE) { 65 | end(); 66 | } else { 67 | fail(); 68 | } 69 | } 70 | } 71 | 72 | @Override 73 | protected void onReset() { 74 | mRotationGestureDetector = null; 75 | mLastVelocity = 0f; 76 | mLastRotation = 0f; 77 | } 78 | 79 | public double getRotation() { 80 | return mLastRotation; 81 | } 82 | 83 | public double getVelocity() { 84 | return mLastVelocity; 85 | } 86 | 87 | public float getAnchorX() { 88 | if (mRotationGestureDetector == null) { 89 | return Float.NaN; 90 | } 91 | return mRotationGestureDetector.getAnchorX(); 92 | } 93 | 94 | public float getAnchorY() { 95 | if (mRotationGestureDetector == null) { 96 | return Float.NaN; 97 | } 98 | return mRotationGestureDetector.getAnchorY(); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src-native/ios/GestureHandler.xcodeproj/xcshareddata/xcschemes/GestureHandler.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 52 | 53 | 59 | 60 | 66 | 67 | 68 | 69 | 71 | 72 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /src-native/ios/GestureHandler.xcodeproj/xcshareddata/xcschemes/GestureHandlerLib.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 41 | 42 | 52 | 53 | 59 | 60 | 61 | 62 | 68 | 69 | 71 | 72 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /packages/gesturehandler/platforms/ios/src/LongPressHandler.m: -------------------------------------------------------------------------------- 1 | // 2 | // LongPressHandler.m 3 | // GestureHandler 4 | // 5 | // Created by Krzysztof Magiera on 12/10/2017. 6 | // Copyright © 2017 Software Mansion. All rights reserved. 7 | // 8 | 9 | #import "LongPressHandler.h" 10 | 11 | #import 12 | 13 | 14 | @interface BetterLongPressGestureRecognizer : UILongPressGestureRecognizer 15 | 16 | - (id)initWithGestureHandler:(GestureHandler*)gestureHandler; 17 | 18 | @end 19 | 20 | @implementation BetterLongPressGestureRecognizer { 21 | __weak GestureHandler *_gestureHandler; 22 | } 23 | 24 | - (id)initWithGestureHandler:(GestureHandler*)gestureHandler 25 | { 26 | if ((self = [super initWithTarget:gestureHandler action:@selector(handleGesture:)])) { 27 | _gestureHandler = gestureHandler; 28 | } 29 | return self; 30 | } 31 | 32 | - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event 33 | { 34 | [super touchesMoved:touches withEvent:event]; 35 | if (_gestureHandler.shouldCancelWhenOutside && ![_gestureHandler containsPointInView]) { 36 | self.enabled = NO; 37 | self.enabled = YES; 38 | } 39 | } 40 | 41 | @end 42 | 43 | 44 | @implementation LongPressGestureHandler 45 | 46 | - (instancetype)initWithTag:(NSNumber *)tag 47 | { 48 | if ((self = [super initWithTag:tag])) { 49 | _recognizer = [[BetterLongPressGestureRecognizer alloc] initWithGestureHandler:self]; 50 | self.shouldCancelWhenOutside = YES; 51 | } 52 | return self; 53 | } 54 | 55 | - (void)configure:(NSDictionary *)config 56 | { 57 | [super configure:config]; 58 | UILongPressGestureRecognizer *recognizer = (UILongPressGestureRecognizer *)_recognizer; 59 | 60 | id prop = config[@"minDurationMs"]; 61 | if (prop != nil) { 62 | recognizer.minimumPressDuration = [prop floatValue] / 1000.0; 63 | } 64 | 65 | prop = config[@"maxDist"]; 66 | if (prop != nil) { 67 | recognizer.allowableMovement = [prop floatValue]; 68 | } 69 | } 70 | 71 | // 72 | - (void) setMinDurationMs:(CGFloat) value { 73 | ((UILongPressGestureRecognizer *)_recognizer).minimumPressDuration = value / 1000.0; 74 | } 75 | // 76 | //- (NSNumber *) minDurationMs { 77 | // return [NSNumber numberWithFloat: ((UILongPressGestureRecognizer *)_recognizer).minimumPressDuration * 1000.0]; 78 | //} 79 | // 80 | - (void) setMaxDist:(CGFloat) value { 81 | ((UILongPressGestureRecognizer *)_recognizer).allowableMovement = value; 82 | } 83 | // 84 | //- (NSNumber *) maxDist { 85 | // return [NSNumber numberWithFloat: ((UILongPressGestureRecognizer *)_recognizer).allowableMovement]; 86 | //} 87 | 88 | - (GestureHandlerState)state 89 | { 90 | // For long press recognizer we treat "Began" state as "active" 91 | // as it changes its state to "Began" as soon as the the minimum 92 | // hold duration timeout is reached, whereas state "Changed" is 93 | // only set after "Began" phase if there is some movement. 94 | if (_recognizer.state == UIGestureRecognizerStateBegan) { 95 | return GestureHandlerStateActive; 96 | } 97 | return [super state]; 98 | } 99 | @end 100 | 101 | -------------------------------------------------------------------------------- /packages/gesturehandler/platforms/android/java/com/nativescript/gesturehandler/GestureHandlerInteractionController.java: -------------------------------------------------------------------------------- 1 | package com.nativescript.gesturehandler; 2 | 3 | import android.content.Context; 4 | import android.view.ViewGroup; 5 | import android.os.IBinder; 6 | import android.view.View; 7 | import android.view.KeyEvent; 8 | import android.util.AttributeSet; 9 | import android.view.inputmethod.InputMethodManager; 10 | import android.util.Log; 11 | 12 | import com.swmansion.gesturehandler.GestureHandler; 13 | 14 | import java.util.HashMap; 15 | 16 | public class GestureHandlerInteractionController implements com.swmansion.gesturehandler.GestureHandlerInteractionController { 17 | private HashMap mWaitForRelations = new HashMap(); 18 | private HashMap mSimultaneousRelations = new HashMap(); 19 | 20 | public GestureHandlerInteractionController() { 21 | super(); 22 | } 23 | 24 | public void dropRelationsForHandlerWithTag(int handlerTag) { 25 | mWaitForRelations.remove(handlerTag); 26 | mSimultaneousRelations.remove(handlerTag); 27 | } 28 | 29 | public void configureInteractions(com.swmansion.gesturehandler.GestureHandler handler, int[] waitFor, 30 | int[] simultaneousHandlers) { 31 | handler.setInteractionController(this); 32 | if (waitFor != null) { 33 | mWaitForRelations.put(handler.getTag(), waitFor); 34 | } 35 | if (simultaneousHandlers != null) { 36 | mSimultaneousRelations.put(handler.getTag(), simultaneousHandlers); 37 | } 38 | } 39 | 40 | public boolean shouldWaitForHandlerFailure(GestureHandler handler, GestureHandler otherHandler) { 41 | int[] waitForTags = mWaitForRelations.get(handler.getTag()); 42 | if (waitForTags != null) { 43 | for (int i = 0; i < waitForTags.length; i++) { 44 | if (waitForTags[i] == otherHandler.getTag()) { 45 | return true; 46 | } 47 | } 48 | } 49 | return false; 50 | } 51 | 52 | public boolean shouldRequireHandlerToWaitForFailure(GestureHandler handler, GestureHandler otherHandler) { 53 | return false; 54 | } 55 | 56 | public boolean shouldHandlerBeCancelledBy(GestureHandler handler, GestureHandler otherHandler) { 57 | return false; 58 | } 59 | 60 | public boolean shouldRecognizeSimultaneously(GestureHandler handler, GestureHandler otherHandler) { 61 | int[] simultHandlerTags = mSimultaneousRelations.get(handler.getTag()); 62 | if (GestureHandler.debug) { 63 | Log.d("JS", "GestureHandlerInteractionController shouldRecognizeSimultaneously " + handler + " " + otherHandler + " " + simultHandlerTags); 64 | } 65 | if (simultHandlerTags != null) { 66 | for (int i = 0; i < simultHandlerTags.length; i++) { 67 | if (simultHandlerTags[i] == otherHandler.getTag()) { 68 | return true; 69 | } 70 | } 71 | } 72 | return false; 73 | } 74 | 75 | public void reset() { 76 | mWaitForRelations.clear(); 77 | mSimultaneousRelations.clear(); 78 | } 79 | } -------------------------------------------------------------------------------- /docs/assets/highlight.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --light-hl-0: #AF00DB; 3 | --dark-hl-0: #C586C0; 4 | --light-hl-1: #000000; 5 | --dark-hl-1: #D4D4D4; 6 | --light-hl-2: #001080; 7 | --dark-hl-2: #9CDCFE; 8 | --light-hl-3: #A31515; 9 | --dark-hl-3: #CE9178; 10 | --light-hl-4: #795E26; 11 | --dark-hl-4: #DCDCAA; 12 | --light-hl-5: #0000FF; 13 | --dark-hl-5: #569CD6; 14 | --light-hl-6: #267F99; 15 | --dark-hl-6: #4EC9B0; 16 | --light-hl-7: #0070C1; 17 | --dark-hl-7: #4FC1FF; 18 | --light-hl-8: #098658; 19 | --dark-hl-8: #B5CEA8; 20 | --light-hl-9: #008000; 21 | --dark-hl-9: #6A9955; 22 | --light-hl-10: #000000; 23 | --dark-hl-10: #C8C8C8; 24 | --light-code-background: #FFFFFF; 25 | --dark-code-background: #1E1E1E; 26 | } 27 | 28 | @media (prefers-color-scheme: light) { :root { 29 | --hl-0: var(--light-hl-0); 30 | --hl-1: var(--light-hl-1); 31 | --hl-2: var(--light-hl-2); 32 | --hl-3: var(--light-hl-3); 33 | --hl-4: var(--light-hl-4); 34 | --hl-5: var(--light-hl-5); 35 | --hl-6: var(--light-hl-6); 36 | --hl-7: var(--light-hl-7); 37 | --hl-8: var(--light-hl-8); 38 | --hl-9: var(--light-hl-9); 39 | --hl-10: var(--light-hl-10); 40 | --code-background: var(--light-code-background); 41 | } } 42 | 43 | @media (prefers-color-scheme: dark) { :root { 44 | --hl-0: var(--dark-hl-0); 45 | --hl-1: var(--dark-hl-1); 46 | --hl-2: var(--dark-hl-2); 47 | --hl-3: var(--dark-hl-3); 48 | --hl-4: var(--dark-hl-4); 49 | --hl-5: var(--dark-hl-5); 50 | --hl-6: var(--dark-hl-6); 51 | --hl-7: var(--dark-hl-7); 52 | --hl-8: var(--dark-hl-8); 53 | --hl-9: var(--dark-hl-9); 54 | --hl-10: var(--dark-hl-10); 55 | --code-background: var(--dark-code-background); 56 | } } 57 | 58 | :root[data-theme='light'] { 59 | --hl-0: var(--light-hl-0); 60 | --hl-1: var(--light-hl-1); 61 | --hl-2: var(--light-hl-2); 62 | --hl-3: var(--light-hl-3); 63 | --hl-4: var(--light-hl-4); 64 | --hl-5: var(--light-hl-5); 65 | --hl-6: var(--light-hl-6); 66 | --hl-7: var(--light-hl-7); 67 | --hl-8: var(--light-hl-8); 68 | --hl-9: var(--light-hl-9); 69 | --hl-10: var(--light-hl-10); 70 | --code-background: var(--light-code-background); 71 | } 72 | 73 | :root[data-theme='dark'] { 74 | --hl-0: var(--dark-hl-0); 75 | --hl-1: var(--dark-hl-1); 76 | --hl-2: var(--dark-hl-2); 77 | --hl-3: var(--dark-hl-3); 78 | --hl-4: var(--dark-hl-4); 79 | --hl-5: var(--dark-hl-5); 80 | --hl-6: var(--dark-hl-6); 81 | --hl-7: var(--dark-hl-7); 82 | --hl-8: var(--dark-hl-8); 83 | --hl-9: var(--dark-hl-9); 84 | --hl-10: var(--dark-hl-10); 85 | --code-background: var(--dark-code-background); 86 | } 87 | 88 | .hl-0 { color: var(--hl-0); } 89 | .hl-1 { color: var(--hl-1); } 90 | .hl-2 { color: var(--hl-2); } 91 | .hl-3 { color: var(--hl-3); } 92 | .hl-4 { color: var(--hl-4); } 93 | .hl-5 { color: var(--hl-5); } 94 | .hl-6 { color: var(--hl-6); } 95 | .hl-7 { color: var(--hl-7); } 96 | .hl-8 { color: var(--hl-8); } 97 | .hl-9 { color: var(--hl-9); } 98 | .hl-10 { color: var(--hl-10); } 99 | pre, code { background: var(--code-background); } 100 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "homepage": "https://github.com/nativescript-community/gesturehandler#readme", 4 | "bugs": { 5 | "url": "https://github.com/nativescript-community/gesturehandler/issues" 6 | }, 7 | "repository": { 8 | "type": "git", 9 | "url": "git+https://github.com/nativescript-community/gesturehandler.git" 10 | }, 11 | "license": "ISC", 12 | "author": "", 13 | "scripts": { 14 | "build": "lerna run build", 15 | "build.watch": "lerna run build.watch --parallel", 16 | "build.all": "lerna run build.all", 17 | "build.angular": "lerna run build.angular", 18 | "clean": "rimraf 'packages/**/*.d.ts' 'packages/**/*.js' 'packages/**/*.js.map' 'packages/**/*.metada' 'packages/**/angular/ng-package.json'", 19 | "commitmsg": "commitlint -e $GIT_PARAMS", 20 | "demo.ng.android": "cd ./demo-ng && ns run android --no-hmr --env.watchNodeModules", 21 | "demo.ng.clean": "cd ./demo-ng && ns clean", 22 | "demo.ng.ios": "cd ./demo-ng && ns run ios --no-hmr --env.watchNodeModules", 23 | "postinstall": "npm run setup", 24 | "publish": "npm run setup && npm run clean && npm run build.all && npm run readme && npm run doc && npm run commit_readme_doc_changes && lerna publish", 25 | "readme": "lerna run readme && node ./tools/readme.js", 26 | "setup": "npm run submodules && ts-patch install", 27 | "start": "./node_modules/.bin/ntl -A -s 15 -o", 28 | "submodules": "git submodule update --init", 29 | "sync": "node ./tools/sync.js", 30 | "sync.test": "node ./tools/sync.js", 31 | "tsc": "cpy '**/*.d.ts' '../plugin' --parents --cwd=src && tsc -skipLibCheck -d", 32 | "update": "node ./tools/update.js", 33 | "doc": "node tools/builddoc.mjs", 34 | "fullclean": "npm run clean && rimraf 'packages/**/node_modules' 'demo-*/hooks' 'demo-*/node_modules' 'package-lock.json' 'pnpm-lock.yaml' 'node_modules'", 35 | "commit_readme_doc_changes": "git add docs/** *.md ; git commit -m \"readme/doc\" ; echo \"commit readme doc done\"" 36 | }, 37 | "commitlint": { 38 | "extends": [ 39 | "@commitlint/config-conventional" 40 | ] 41 | }, 42 | "dependencies": { 43 | "@nativescript-community/observable": "2.0.11", 44 | "@nativescript-community/plugin-seed-tools": "portal:tools", 45 | "@nativescript-community/template-snippet": "file:demo-snippets" 46 | }, 47 | "ntl": { 48 | "descriptions": { 49 | "build": "Build the plugin", 50 | "build.angular": "Build the plugin for Angular", 51 | "build.all": "Build the plugin for all platforms", 52 | "clean": "Clean the local environment.", 53 | "demo.ng.android": "Runs the Angular demo on Android.", 54 | "demo.ng.ios": "Runs the Angular demo on iOS.", 55 | "watch": "Watch for changes in the plugin source and re-build." 56 | } 57 | }, 58 | "workspaces": [ 59 | "packages/*", 60 | "demo*" 61 | ], 62 | "engines": { 63 | "npm": "please use yarn or pnpm", 64 | "yarn": ">=1.19.1", 65 | "pnpm": ">=7.0.0", 66 | "node": "^14.20.0 || ^16.13.0 || >=18.10.0" 67 | }, 68 | "packageManager": "yarn@4.10.2" 69 | } 70 | -------------------------------------------------------------------------------- /packages/gesturehandler/platforms/ios/src/GestureHandlerEvents.m: -------------------------------------------------------------------------------- 1 | #import "GestureHandlerEvents.h" 2 | 3 | #define SAFE_VELOCITY(velocity) @(isnan(velocity) ? 0 : velocity) 4 | 5 | @implementation GestureHandlerEvent 6 | { 7 | NSNumber *_handlerTag; 8 | GestureHandlerState _state; 9 | NSDictionary *_extraData; 10 | } 11 | 12 | @synthesize view = _view; 13 | 14 | - (instancetype)initWithView:(UIView *)view 15 | handlerTag:(NSNumber *)handlerTag 16 | state:(GestureHandlerState)state 17 | extraData:(NSDictionary *)extraData 18 | { 19 | if ((self = [super init])) { 20 | _view = view; 21 | _handlerTag = handlerTag; 22 | _state = state; 23 | _extraData = extraData; 24 | } 25 | return self; 26 | } 27 | 28 | 29 | - (NSString *)eventName 30 | { 31 | return @"onGestureHandlerEvent"; 32 | } 33 | 34 | - (BOOL)canCoalesce 35 | { 36 | // TODO: event coalescing 37 | return NO; 38 | } 39 | 40 | //- (id)coalesceWithEvent:(id)newEvent; 41 | //{ 42 | // return newEvent; 43 | //} 44 | 45 | //+ (NSString *)moduleDotMethod 46 | //{ 47 | // return @"RCTEventEmitter.receiveEvent"; 48 | //} 49 | 50 | - (NSArray *)arguments 51 | { 52 | NSMutableDictionary *body = [NSMutableDictionary dictionaryWithDictionary:_extraData]; 53 | [body setObject:self.view forKey:@"target"]; 54 | [body setObject:_handlerTag forKey:@"handlerTag"]; 55 | [body setObject:@(_state) forKey:@"state"]; 56 | return @[self.view, @"onGestureHandlerEvent", body]; 57 | } 58 | 59 | @end 60 | 61 | 62 | @implementation GestureHandlerStateChange 63 | { 64 | NSNumber *_handlerTag; 65 | UIView *_view; 66 | GestureHandlerState _state; 67 | GestureHandlerState _prevState; 68 | NSDictionary *_extraData; 69 | } 70 | 71 | @synthesize view = _view; 72 | 73 | - (instancetype)initWithView:(UIView *)view 74 | handlerTag:(NSNumber *)handlerTag 75 | state:(GestureHandlerState)state 76 | prevState:(GestureHandlerState)prevState 77 | extraData:(NSDictionary *)extraData 78 | { 79 | if ((self = [super init])) { 80 | _view = view; 81 | _handlerTag = handlerTag; 82 | _state = state; 83 | _prevState = prevState; 84 | _extraData = extraData; 85 | } 86 | return self; 87 | } 88 | 89 | //RCT_NOT_IMPLEMENTED(- (instancetype)init) 90 | 91 | - (NSString *)eventName 92 | { 93 | return @"onGestureHandlerStateChange"; 94 | } 95 | 96 | - (BOOL)canCoalesce 97 | { 98 | // TODO: event coalescing 99 | return NO; 100 | } 101 | 102 | //- (id)coalesceWithEvent:(id)newEvent; 103 | //{ 104 | // return newEvent; 105 | //} 106 | 107 | //+ (NSString *)moduleDotMethod 108 | //{ 109 | // return @"RCTEventEmitter.receiveEvent"; 110 | //} 111 | 112 | - (NSArray *)argumentsx 113 | { 114 | NSMutableDictionary *body = [NSMutableDictionary dictionaryWithDictionary:_extraData]; 115 | [body setObject:_view forKey:@"target"]; 116 | [body setObject:_handlerTag forKey:@"handlerTag"]; 117 | [body setObject:@(_state) forKey:@"state"]; 118 | [body setObject:@(_prevState) forKey:@"oldState"]; 119 | return @[self.view, @"onGestureHandlerStateChange", body]; 120 | } 121 | 122 | @end 123 | -------------------------------------------------------------------------------- /src-native/ios/GestureHandler.xcodeproj/xcshareddata/xcschemes/GestureHandlerApp.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 41 | 42 | 52 | 54 | 60 | 61 | 62 | 63 | 69 | 71 | 77 | 78 | 79 | 80 | 82 | 83 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: 'release' 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | release_type: 7 | type: choice 8 | default: auto 9 | description: What kind of version upgrade 10 | options: 11 | - auto 12 | - patch 13 | - minor 14 | - major 15 | 16 | jobs: 17 | release: 18 | runs-on: ubuntu-latest 19 | steps: 20 | - name: Checkout repository 21 | uses: actions/checkout@v4 22 | with: 23 | fetch-depth: "0" 24 | submodules: true 25 | 26 | - name: setup node 27 | uses: actions/setup-node@v4 28 | with: 29 | node-version: lts/* 30 | registry-url: 'https://registry.npmjs.org' 31 | 32 | 33 | - uses: oNaiPs/secrets-to-env-action@v1 34 | with: 35 | secrets: ${{ toJSON(secrets) }} 36 | 37 | 38 | - uses: oleksiyrudenko/gha-git-credentials@v2-latest 39 | with: 40 | token: '${{ secrets.GITHUB_TOKEN }}' 41 | name: Martin Guillon 42 | email: dev@akylas.fr 43 | 44 | - name: install jq 45 | run: sudo apt install jq 46 | 47 | - name: Enable CorePack 48 | run: | 49 | corepack enable 50 | yarn config get globalFolder # the yarn command will ensure the correct yarn version is downloaded and installed 51 | 52 | - name: Get yarn cache directory path 53 | id: yarn-cache-dir-path 54 | run: echo "::set-output name=dir::$(yarn config get globalFolder)" 55 | 56 | - name: Remove package.json resolutions 57 | run: echo "`jq 'delpaths([["resolutions"]])' package.json`" > package.json 58 | 59 | - uses: actions/cache@v4 60 | name: Handle node_modules Cache 61 | id: yarn-node_modules # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`) 62 | with: 63 | path: node_modules 64 | key: ${{ runner.os }}-yarn-node_modules-${{ hashFiles('**/yarn.lock') }} 65 | restore-keys: | 66 | ${{ runner.os }}-node_modules- 67 | 68 | - uses: actions/cache@v4 69 | if: steps.yarn-node_modules.outputs.cache-hit != 'true' 70 | name: Handle Yarn cache 71 | id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`) 72 | with: 73 | path: ${{ steps.yarn-cache-dir-path.outputs.dir }} 74 | key: ${{ runner.os }}-yarn-cache-${{ hashFiles('**/yarn.lock') }} 75 | restore-keys: | 76 | ${{ runner.os }}-yarn- 77 | 78 | - name: Install deps 79 | if: steps.yarn-node_modules.outputs.cache-hit != 'true' 80 | uses: bahmutov/npm-install@v1 81 | with: 82 | install-command: corepack yarn --silent 83 | env: 84 | YARN_ENABLE_IMMUTABLE_INSTALLS: false 85 | 86 | - name: run setup 87 | run: | 88 | npm run setup 89 | 90 | - name: "NPM Identity" 91 | env: 92 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 93 | run: | 94 | echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" > .npmrc 95 | 96 | - name: publish auto 97 | if: github.event.inputs.release_type == 'auto' 98 | run: | 99 | npm run publish -- --force-publish --no-verify-access --no-private --no-commit-hooks --yes 100 | env: 101 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 102 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 103 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 104 | 105 | - name: publish 106 | if: github.event.inputs.release_type != 'auto' 107 | run: | 108 | npm run publish -- --force-publish --no-verify-access --no-private --no-commit-hooks --yes --bump ${{ github.event.inputs.release_type }} 109 | env: 110 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 111 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 112 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} -------------------------------------------------------------------------------- /packages/gesturehandler/platforms/ios/src/GestureHandler.h: -------------------------------------------------------------------------------- 1 | // 2 | // GestureHandler.h 3 | // GestureHandler 4 | // 5 | // Created by Martin Guillon on 6/5/19. 6 | // Copyright © 2019 Stefan Dragnev. All rights reserved. 7 | // 8 | 9 | #import "GestureHandlerState.h" 10 | #import "GestureHandlerDirection.h" 11 | #import "GestureHandlerEvents.h" 12 | 13 | #import 14 | #import 15 | 16 | #define VEC_LEN_SQ(pt) (pt.x * pt.x + pt.y * pt.y) 17 | #define TEST_MIN_IF_NOT_NAN(value, limit) \ 18 | (!isnan(limit) && ((limit < 0 && value <= limit) || (limit >= 0 && value >= limit))) 19 | 20 | #define TEST_MAX_IF_NOT_NAN(value, max) \ 21 | (!isnan(max) && ((max < 0 && value < max) || (max >= 0 && value > max))) 22 | 23 | #define APPLY_PROP(recognizer, config, type, prop, propName) do { \ 24 | id value = config[propName]; \ 25 | if (value != nil) recognizer.prop = [value type]; \ 26 | } while(0) 27 | 28 | #define APPLY_FLOAT_PROP(prop) do { APPLY_PROP(recognizer, config, floatValue, prop, @#prop); } while(0) 29 | #define APPLY_INT_PROP(prop) do { APPLY_PROP(recognizer, config, integerValue, prop, @#prop); } while(0) 30 | #define APPLY_NAMED_INT_PROP(prop, propName) do { APPLY_PROP(recognizer, config, integerValue, prop, propName); } while(0) 31 | 32 | //@protocol GestureHandlerEventEmitter 33 | // 34 | //- (void)sendTouchEvent:(nonnull GestureHandlerEvent *)event; 35 | // 36 | //- (void)sendStateChangeEvent:(nonnull GestureHandlerStateChange *)event; 37 | // 38 | //@end 39 | 40 | 41 | @protocol RootViewGestureRecognizerDelegate 42 | 43 | @required 44 | - (BOOL)gestureRecognizer:(nullable UIGestureRecognizer *)gestureRecognizer 45 | didActivateInRootView:(nullable UIView *)rootView; 46 | 47 | @end 48 | 49 | 50 | @class GestureHandler; 51 | @protocol GestureHandlerDelegate 52 | 53 | @optional 54 | - (BOOL)gestureHandler:(nullable GestureHandler *)gestureHandler shouldActivateForEvent:(nullable NSDictionary *)data; 55 | 56 | @required 57 | - (void)gestureHandler:(nullable GestureHandler *)gestureHandler 58 | didChangeState:(GestureHandlerState)state prevState:(GestureHandlerState)state extraData:(nullable NSDictionary *)data view:(nullable UIView *)view; 59 | 60 | @required 61 | - (void)gestureHandler:(nullable GestureHandler *)gestureHandler 62 | touchEventOnView:(nullable UIView *)view state:(GestureHandlerState)state extraData:(nullable NSDictionary *)data; 63 | 64 | @end 65 | 66 | @interface GestureHandler : NSObject { 67 | 68 | @protected UIGestureRecognizer *_recognizer; 69 | @protected GestureHandlerState _lastState; 70 | 71 | } 72 | 73 | + (nullable GestureHandler *)findGestureHandlerByRecognizer:(nonnull UIGestureRecognizer *)recognizer; 74 | 75 | - (nonnull instancetype)initWithTag:(nonnull NSNumber *)tag; 76 | 77 | @property (nonatomic, readonly, nonnull) NSNumber *tag; 78 | //@property (nonatomic, weak, nullable) id emitter; 79 | @property (nonatomic, readonly, nullable) UIGestureRecognizer *recognizer; 80 | @property (nonatomic) BOOL enabled; 81 | @property (nonatomic) BOOL activateOnBegin; 82 | @property(nonatomic) BOOL shouldCancelWhenOutside; 83 | @property (nullable, nonatomic, weak) id delegate; 84 | 85 | - (void)setEnabled:(BOOL)enabled; 86 | - (void)setShouldCancelWhenOutside:(BOOL)value; 87 | 88 | - (void)bindToView:(nonnull UIView *)view; 89 | - (void)unbindFromView; 90 | - (void)configure:(nullable NSDictionary *)config NS_REQUIRES_SUPER; 91 | - (void)handleGesture:(nonnull id)recognizer; 92 | - (BOOL)containsPointInView; 93 | - (GestureHandlerState)state; 94 | - (nullable NSMutableDictionary *)eventExtraData:(nonnull id)recognizer; 95 | 96 | - (CGPoint) locationInView:(UIView*)view; 97 | - (CGPoint) locationOfTouch:(NSUInteger)index inView:(UIView*)view; 98 | - (void)reset; 99 | - (void)cancel; 100 | - (void)sendEventsInState:(GestureHandlerState)state 101 | forView:(nonnull UIView *)view 102 | withExtraData:(nullable NSDictionary*)extraData; 103 | 104 | @end 105 | -------------------------------------------------------------------------------- /packages/gesturehandler/platforms/android/java/com/swmansion/gesturehandler/GestureHandlerRegistryImpl.java: -------------------------------------------------------------------------------- 1 | package com.swmansion.gesturehandler; 2 | 3 | import android.util.SparseArray; 4 | import android.view.View; 5 | 6 | import com.swmansion.gesturehandler.GestureHandler; 7 | import com.swmansion.gesturehandler.GestureHandlerRegistry; 8 | 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | import java.util.WeakHashMap; 12 | 13 | import androidx.annotation.Nullable; 14 | 15 | public class GestureHandlerRegistryImpl implements GestureHandlerRegistry { 16 | 17 | private final SparseArray mHandlers = new SparseArray<>(); 18 | private final SparseArray mAttachedTo = new SparseArray<>(); 19 | // private final SparseArray> mHandlersForView = new 20 | // SparseArray<>(); 21 | private WeakHashMap> mHandlersForView = new WeakHashMap<>(); 22 | 23 | public synchronized void registerHandler(GestureHandler handler) { 24 | mHandlers.put(handler.getTag(), handler); 25 | } 26 | 27 | public synchronized @Nullable GestureHandler getHandler(int handlerTag) { 28 | return mHandlers.get(handlerTag); 29 | } 30 | 31 | public synchronized ArrayList getAllHandlers() { 32 | if (mHandlers == null) 33 | return null; 34 | ArrayList arrayList = new ArrayList(mHandlers.size()); 35 | for (int i = 0; i < mHandlers.size(); i++) { 36 | arrayList.add(mHandlers.valueAt(i)); 37 | } 38 | return arrayList; 39 | } 40 | 41 | public synchronized boolean attachHandlerToView(int handlerTag, android.view.View view) { 42 | GestureHandler handler = mHandlers.get(handlerTag); 43 | if (handler != null) { 44 | detachHandler(handler); 45 | registerHandlerForView(view, handler); 46 | return true; 47 | } else { 48 | return false; 49 | } 50 | } 51 | 52 | public synchronized void registerHandlerForView(android.view.View view, GestureHandler handler) { 53 | if (mAttachedTo.get(handler.getTag()) != null) { 54 | throw new IllegalStateException("Handler " + handler + " already attached"); 55 | } 56 | mAttachedTo.put(handler.getTag(), view); 57 | ArrayList listToAdd = mHandlersForView.get(view); 58 | if (listToAdd == null) { 59 | listToAdd = new ArrayList<>(1); 60 | listToAdd.add(handler); 61 | mHandlersForView.put(view, listToAdd); 62 | } else { 63 | listToAdd.add(handler); 64 | } 65 | } 66 | 67 | public synchronized void detachHandler(GestureHandler handler) { 68 | View attachedToView = mAttachedTo.get(handler.getTag()); 69 | if (attachedToView != null) { 70 | mAttachedTo.remove(handler.getTag()); 71 | ArrayList attachedHandlers = mHandlersForView.get(attachedToView); 72 | if (attachedHandlers != null) { 73 | attachedHandlers.remove(handler); 74 | if (attachedHandlers.size() == 0) { 75 | mHandlersForView.remove(attachedToView); 76 | } 77 | } 78 | } 79 | if (handler.getView() != null) { 80 | // Handler is in "prepared" state which means it is registered in the 81 | // orchestrator and can 82 | // receive touch events. This means that before we remove it from the registry 83 | // we need to 84 | // "cancel" it so that orchestrator does no longer keep a reference to it. 85 | handler.cancel(); 86 | } 87 | } 88 | 89 | public synchronized void dropHandler(int handlerTag) { 90 | GestureHandler handler = mHandlers.get(handlerTag); 91 | if (handler != null) { 92 | detachHandler(handler); 93 | mHandlers.remove(handlerTag); 94 | } 95 | } 96 | 97 | public synchronized void dropAllHandlers() { 98 | mHandlers.clear(); 99 | mAttachedTo.clear(); 100 | mHandlersForView.clear(); 101 | } 102 | 103 | @Override 104 | public synchronized ArrayList getHandlersForView(android.view.View view) { 105 | return mHandlersForView.get(view); 106 | } 107 | 108 | } -------------------------------------------------------------------------------- /packages/gesturehandler/platforms/android/java/com/swmansion/gesturehandler/FlingGestureHandler.java: -------------------------------------------------------------------------------- 1 | package com.swmansion.gesturehandler; 2 | 3 | import android.os.Handler; 4 | import android.view.MotionEvent; 5 | import android.util.Log; 6 | 7 | public class FlingGestureHandler extends GestureHandler { 8 | private static final String TAG = "FlingGestureHandler"; 9 | private static final long DEFAULT_MAX_DURATION_MS = 800; 10 | private static final long DEFAULT_MIN_ACCEPTABLE_DELTA = 160; 11 | private static final int DEFAULT_DIRECTION = DIRECTION_RIGHT | DIRECTION_LEFT | DIRECTION_UP | DIRECTION_DOWN; 12 | private static final int DEFAULT_NUMBER_OF_TOUCHES_REQUIRED = 1; 13 | 14 | private long mMaxDurationMs = DEFAULT_MAX_DURATION_MS; 15 | private long mMinAcceptableDelta = DEFAULT_MIN_ACCEPTABLE_DELTA; 16 | private int mDirection = DEFAULT_DIRECTION; 17 | private int mNumberOfPointersRequired = DEFAULT_NUMBER_OF_TOUCHES_REQUIRED; 18 | private float mStartX, mStartY; 19 | private int mLastDirection = -1; 20 | private Handler mHandler; 21 | private int mMaxNumberOfPointersSimultaneously; 22 | 23 | private final Runnable mFailDelayed = new Runnable() { 24 | @Override 25 | public void run() { 26 | fail(); 27 | } 28 | }; 29 | 30 | public void setNumberOfPointersRequired(int numberOfPointersRequired) { 31 | mNumberOfPointersRequired = numberOfPointersRequired; 32 | } 33 | 34 | public void setDirection(int direction) { 35 | mDirection = direction; 36 | } 37 | 38 | public int getRecognizedDirection() { 39 | return mLastDirection; 40 | } 41 | 42 | private void startFling(MotionEvent event) { 43 | mStartX = event.getRawX(); 44 | mStartY = event.getRawY(); 45 | begin(); 46 | mMaxNumberOfPointersSimultaneously = 1; 47 | if (mHandler == null) { 48 | mHandler = new Handler(); 49 | } else { 50 | mHandler.removeCallbacksAndMessages(null); 51 | } 52 | mHandler.postDelayed(mFailDelayed, mMaxDurationMs); 53 | } 54 | 55 | private boolean tryEndFling(MotionEvent event) { 56 | mLastDirection = -1; 57 | if (mMaxNumberOfPointersSimultaneously == mNumberOfPointersRequired) { 58 | if ((mDirection & DIRECTION_RIGHT) != 0 && event.getRawX() - mStartX > mMinAcceptableDelta) { 59 | mLastDirection = DIRECTION_RIGHT; 60 | } else if ((mDirection & DIRECTION_LEFT) != 0 && mStartX - event.getRawX() > mMinAcceptableDelta) { 61 | mLastDirection = DIRECTION_LEFT; 62 | } else if ((mDirection & DIRECTION_UP) != 0 && mStartY - event.getRawY() > mMinAcceptableDelta) { 63 | mLastDirection = DIRECTION_UP; 64 | } else if ((mDirection & DIRECTION_DOWN) != 0 && event.getRawY() - mStartY > mMinAcceptableDelta) { 65 | mLastDirection = DIRECTION_DOWN; 66 | } 67 | } 68 | if (mLastDirection != -1) { 69 | mHandler.removeCallbacksAndMessages(null); 70 | activate(); 71 | end(); 72 | return true; 73 | } else { 74 | return false; 75 | } 76 | } 77 | 78 | private void endFling(MotionEvent event) { 79 | if (GestureHandler.debug) { 80 | Log.d("JS", "FlingGestureHandler endFling"); 81 | } 82 | if (!tryEndFling(event)) { 83 | fail(); 84 | } 85 | 86 | } 87 | 88 | @Override 89 | protected void onHandle(MotionEvent event) { 90 | int state = getState(); 91 | 92 | if (state == STATE_UNDETERMINED) { 93 | startFling(event); 94 | } 95 | 96 | if (state == STATE_BEGAN) { 97 | tryEndFling(event); 98 | if (event.getPointerCount() > mMaxNumberOfPointersSimultaneously) { 99 | mMaxNumberOfPointersSimultaneously = event.getPointerCount(); 100 | } 101 | 102 | int action = event.getActionMasked(); 103 | if (action == MotionEvent.ACTION_UP) { 104 | endFling(event); 105 | } 106 | } 107 | } 108 | 109 | @Override 110 | protected void onCancel() { 111 | if (GestureHandler.debug) { 112 | Log.d("JS", "FlingGestureHandler onCancel"); 113 | } 114 | if (mHandler != null) { 115 | mHandler.removeCallbacksAndMessages(null); 116 | } 117 | } 118 | 119 | @Override 120 | protected void onReset() { 121 | if (mHandler != null) { 122 | mHandler.removeCallbacksAndMessages(null); 123 | } 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /packages/gesturehandler/platforms/android/java/com/swmansion/gesturehandler/PinchGestureHandler.java: -------------------------------------------------------------------------------- 1 | package com.swmansion.gesturehandler; 2 | 3 | import android.content.Context; 4 | import android.view.MotionEvent; 5 | import android.view.ViewConfiguration; 6 | 7 | public class PinchGestureHandler extends GestureHandler { 8 | 9 | private ScaleGestureDetector mScaleGestureDetector; 10 | private double mLastScaleFactor; 11 | private double mLastVelocity; 12 | 13 | private float mStartingSpan; 14 | private int mSpanSlop = -1; 15 | private int mMinSpan = -1; 16 | 17 | private ScaleGestureDetector.OnScaleGestureListener mGestureListener = new ScaleGestureDetector.OnScaleGestureListener() { 18 | 19 | @Override 20 | public boolean onScale(ScaleGestureDetector detector) { 21 | double prevScaleFactor = mLastScaleFactor; 22 | mLastScaleFactor *= detector.getScaleFactor(); 23 | long delta = detector.getTimeDelta(); 24 | if (delta > 0) { 25 | mLastVelocity = (mLastScaleFactor - prevScaleFactor) / delta; 26 | } 27 | if (Math.abs(mStartingSpan - detector.getCurrentSpan()) >= mSpanSlop && getState() == STATE_BEGAN) { 28 | activate(); 29 | } 30 | return true; 31 | } 32 | 33 | @Override 34 | public boolean onScaleBegin(ScaleGestureDetector detector) { 35 | mStartingSpan = detector.getCurrentSpan(); 36 | return true; 37 | } 38 | 39 | @Override 40 | public void onScaleEnd(ScaleGestureDetector detector) { 41 | // ScaleGestureDetector thinks that when fingers are 27mm away that's a 42 | // sufficiently good 43 | // reason to trigger this method giving us no other choice but to ignore it 44 | // completely. 45 | } 46 | }; 47 | 48 | public PinchGestureHandler() { 49 | setShouldCancelWhenOutside(false); 50 | } 51 | 52 | @Override 53 | protected void onHandle(MotionEvent event) { 54 | int activePointers = event.getPointerCount(); 55 | 56 | if (getState() == STATE_UNDETERMINED) { 57 | if (mScaleGestureDetector == null) { 58 | Context context = getView().getContext(); 59 | mLastVelocity = 0f; 60 | mLastScaleFactor = 1f; 61 | mScaleGestureDetector = new ScaleGestureDetector(context, mGestureListener); 62 | if (mSpanSlop != -1) { 63 | mScaleGestureDetector.setSpanSlop(mSpanSlop); 64 | } 65 | if (mMinSpan != -1) { 66 | mScaleGestureDetector.setMinSpan(mMinSpan); 67 | } 68 | } 69 | begin(); 70 | } 71 | 72 | 73 | if (mScaleGestureDetector != null) { 74 | mScaleGestureDetector.onTouchEvent(event); 75 | } 76 | 77 | if (event.getActionMasked() == MotionEvent.ACTION_POINTER_UP) { 78 | activePointers -= 1; 79 | } 80 | 81 | if (getState() == STATE_ACTIVE && activePointers < 2) { 82 | end(); 83 | } else if (event.getActionMasked() == MotionEvent.ACTION_UP) { 84 | fail(); 85 | } 86 | } 87 | 88 | @Override 89 | protected void onReset() { 90 | mScaleGestureDetector = null; 91 | mLastVelocity = 0f; 92 | mLastScaleFactor = 1f; 93 | } 94 | 95 | public double getScale() { 96 | return mLastScaleFactor; 97 | } 98 | 99 | public double getVelocity() { 100 | return mLastVelocity; 101 | } 102 | 103 | public float getMinSpan() { 104 | return (float) mMinSpan; 105 | } 106 | 107 | public PinchGestureHandler setMinSpan(float value) { 108 | mMinSpan = (int) value; 109 | if (mScaleGestureDetector != null) { 110 | mScaleGestureDetector.setMinSpan(mMinSpan); 111 | } 112 | return this; 113 | } 114 | 115 | public float getSpanSlop() { 116 | return (float) mSpanSlop; 117 | } 118 | 119 | public PinchGestureHandler setSpanSlop(float value) { 120 | mSpanSlop = (int) value; 121 | if (mScaleGestureDetector != null) { 122 | mScaleGestureDetector.setSpanSlop(mSpanSlop); 123 | } 124 | return this; 125 | } 126 | 127 | public float getFocalPointX() { 128 | if (mScaleGestureDetector == null) { 129 | return Float.NaN; 130 | } 131 | return mScaleGestureDetector.getFocusX(); 132 | } 133 | 134 | public float getFocalPointY() { 135 | if (mScaleGestureDetector == null) { 136 | return Float.NaN; 137 | } 138 | return mScaleGestureDetector.getFocusY(); 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /docs/variables/GestureHandlerStateEvent.html: -------------------------------------------------------------------------------- 1 | GestureHandlerStateEvent | @nativescript-community/gesturehandler

Variable GestureHandlerStateEventConst

GestureHandlerStateEvent: "GestureHandlerStateEvent"
2 | -------------------------------------------------------------------------------- /docs/variables/GestureHandlerTouchEvent.html: -------------------------------------------------------------------------------- 1 | GestureHandlerTouchEvent | @nativescript-community/gesturehandler

Variable GestureHandlerTouchEventConst

GestureHandlerTouchEvent: "GestureHandlerTouchEvent"
2 | -------------------------------------------------------------------------------- /packages/gesturehandler/platforms/ios/src/ForceTouchHandler.m: -------------------------------------------------------------------------------- 1 | #import "ForceTouchHandler.h" 2 | 3 | #import 4 | 5 | 6 | @interface ForceTouchGestureRecognizer : UIGestureRecognizer 7 | 8 | @property (nonatomic) CGFloat maxForce; 9 | @property (nonatomic) CGFloat minForce; 10 | @property (nonatomic) CGFloat force; 11 | @property (nonatomic) BOOL feedbackOnActivation; 12 | 13 | - (id)initWithGestureHandler:(GestureHandler*)gestureHandler; 14 | 15 | @end 16 | 17 | @implementation ForceTouchGestureRecognizer { 18 | __weak GestureHandler *_gestureHandler; 19 | UITouch *_firstTouch; 20 | } 21 | 22 | 23 | - (id)initWithGestureHandler:(GestureHandler*)gestureHandler 24 | { 25 | if ((self = [super initWithTarget:gestureHandler action:@selector(handleGesture:)])) { 26 | _gestureHandler = gestureHandler; 27 | _force = 0; 28 | _minForce = 0.2; 29 | _maxForce = NAN; 30 | _feedbackOnActivation = NO; 31 | } 32 | return self; 33 | } 34 | 35 | - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 36 | { 37 | if (_firstTouch) { 38 | // ignore rest of fingers 39 | return; 40 | } 41 | [super touchesBegan:touches withEvent:event]; 42 | _firstTouch = [touches anyObject]; 43 | [self handleForceWithTouches:touches]; 44 | self.state = UIGestureRecognizerStatePossible; 45 | } 46 | 47 | - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event 48 | { 49 | if (![touches containsObject:_firstTouch]) { 50 | // Considered only the very first touch 51 | return; 52 | } 53 | [super touchesMoved:touches withEvent:event]; 54 | 55 | [self handleForceWithTouches:touches]; 56 | 57 | if ([self shouldFail]) { 58 | self.state = UIGestureRecognizerStateFailed; 59 | return; 60 | } 61 | 62 | if (self.state == UIGestureRecognizerStatePossible && [self shouldActivate]) { 63 | [self performFeedbackIfRequired]; 64 | self.state = UIGestureRecognizerStateBegan; 65 | } 66 | } 67 | 68 | - (BOOL)shouldActivate { 69 | return (_force >= _minForce); 70 | } 71 | 72 | - (BOOL)shouldFail { 73 | return TEST_MAX_IF_NOT_NAN(_force, _maxForce); 74 | } 75 | 76 | - (void)performFeedbackIfRequired 77 | { 78 | #if !TARGET_OS_TV 79 | if (_feedbackOnActivation) { 80 | if (@available(iOS 10.0, *)) { 81 | [[[UIImpactFeedbackGenerator alloc] initWithStyle:(UIImpactFeedbackStyleMedium)] impactOccurred]; 82 | } 83 | } 84 | #endif 85 | } 86 | 87 | - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event 88 | { 89 | if (![touches containsObject:_firstTouch]) { 90 | // Considered only the very first touch 91 | return; 92 | } 93 | [super touchesEnded:touches withEvent:event]; 94 | if (self.state == UIGestureRecognizerStateBegan || self.state == UIGestureRecognizerStateChanged) { 95 | self.state = UIGestureRecognizerStateEnded; 96 | } else { 97 | self.state = UIGestureRecognizerStateFailed; 98 | } 99 | } 100 | 101 | - (void)handleForceWithTouches:(NSSet *)touches { 102 | _force = _firstTouch.force / _firstTouch.maximumPossibleForce; 103 | } 104 | 105 | - (void)reset { 106 | [super reset]; 107 | _force = 0; 108 | _firstTouch = NULL; 109 | } 110 | 111 | @end 112 | 113 | @implementation ForceTouchHandler 114 | 115 | - (instancetype)initWithTag:(NSNumber *)tag 116 | { 117 | if ((self = [super initWithTag:tag])) { 118 | _recognizer = [[ForceTouchGestureRecognizer alloc] initWithGestureHandler:self]; 119 | } 120 | return self; 121 | } 122 | 123 | - (void)configure:(NSDictionary *)config 124 | { 125 | [super configure:config]; 126 | ForceTouchGestureRecognizer *recognizer = (ForceTouchGestureRecognizer *)_recognizer; 127 | 128 | APPLY_FLOAT_PROP(maxForce); 129 | APPLY_FLOAT_PROP(minForce); 130 | 131 | id prop = config[@"feedbackOnActivation"]; 132 | if (prop != nil) { 133 | recognizer.feedbackOnActivation = [prop boolValue]; 134 | } 135 | } 136 | 137 | // 138 | - (void) setMaxForce:(NSInteger) value { 139 | ((ForceTouchGestureRecognizer *)_recognizer).maxForce = value; 140 | } 141 | // 142 | //- (NSNumber *) maxForce { 143 | // return [NSNumber numberWithInteger: ((ForceTouchGestureRecognizer *)_recognizer).maxForce]; 144 | //} 145 | // 146 | - (void) setMinForce:(NSInteger) value { 147 | ((ForceTouchGestureRecognizer *)_recognizer).minForce = value; 148 | } 149 | // 150 | //- (NSNumber *) minForce { 151 | // return [NSNumber numberWithInteger: ((ForceTouchGestureRecognizer *)_recognizer).minForce]; 152 | //} 153 | // 154 | // 155 | - (void) setFeedbackOnActivation:(Boolean) value { 156 | ((ForceTouchGestureRecognizer *)_recognizer).feedbackOnActivation = value; 157 | } 158 | // 159 | //- (NSNumber *) feedbackOnActivation { 160 | // return [NSNumber numberWithBool: ((ForceTouchGestureRecognizer *)_recognizer).feedbackOnActivation]; 161 | //} 162 | 163 | - (NSMutableDictionary *)eventExtraData:(ForceTouchGestureRecognizer *)recognizer 164 | { 165 | NSMutableDictionary* result = [super eventExtraData:recognizer]; 166 | [result setObject:@(recognizer.force) forKey:@"force"]; 167 | return result; 168 | } 169 | 170 | @end 171 | -------------------------------------------------------------------------------- /packages/gesturehandler/platforms/android/java/com/swmansion/gesturehandler/RotationGestureDetector.java: -------------------------------------------------------------------------------- 1 | package com.swmansion.gesturehandler; 2 | 3 | import android.view.MotionEvent; 4 | 5 | public class RotationGestureDetector { 6 | 7 | public interface OnRotationGestureListener { 8 | 9 | boolean onRotation(RotationGestureDetector detector); 10 | 11 | boolean onRotationBegin(RotationGestureDetector detector); 12 | 13 | void onRotationEnd(RotationGestureDetector detector); 14 | } 15 | 16 | private long mCurrTime; 17 | private long mPrevTime; 18 | private double mPrevAngle; 19 | private double mAngleDiff; 20 | private float mAnchorX; 21 | private float mAnchorY; 22 | 23 | private boolean mInProgress; 24 | 25 | private int mPointerIds[] = new int[2]; 26 | 27 | private OnRotationGestureListener mListener; 28 | 29 | public RotationGestureDetector(OnRotationGestureListener listener) { 30 | mListener = listener; 31 | } 32 | 33 | private void updateCurrent(MotionEvent event) { 34 | mPrevTime = mCurrTime; 35 | mCurrTime = event.getEventTime(); 36 | 37 | int firstPointerIndex = event.findPointerIndex(mPointerIds[0]); 38 | int secondPointerIndex = event.findPointerIndex(mPointerIds[1]); 39 | 40 | float firstPtX = event.getX(firstPointerIndex); 41 | float firstPtY = event.getY(firstPointerIndex); 42 | float secondPtX = event.getX(secondPointerIndex); 43 | float secondPtY = event.getY(secondPointerIndex); 44 | 45 | float vectorX = secondPtX - firstPtX; 46 | float vectorY = secondPtY - firstPtY; 47 | 48 | mAnchorX = (firstPtX + secondPtX) * 0.5f; 49 | mAnchorY = (firstPtY + secondPtY) * 0.5f; 50 | 51 | // Angle diff should be positive when rotating in clockwise direction 52 | double angle = -Math.atan2(vectorY, vectorX); 53 | 54 | if (Double.isNaN(mPrevAngle)) { 55 | mAngleDiff = 0.; 56 | } else { 57 | mAngleDiff = mPrevAngle - angle; 58 | } 59 | mPrevAngle = angle; 60 | 61 | if (mAngleDiff > Math.PI) { 62 | mAngleDiff -= Math.PI; 63 | } else if (mAngleDiff < -Math.PI) { 64 | mAngleDiff += Math.PI; 65 | } 66 | 67 | if (mAngleDiff > Math.PI / 2.) { 68 | mAngleDiff -= Math.PI; 69 | } else if (mAngleDiff < -Math.PI / 2.) { 70 | mAngleDiff += Math.PI; 71 | } 72 | } 73 | 74 | private void finish() { 75 | if (mInProgress) { 76 | mInProgress = false; 77 | if (mListener != null) { 78 | mListener.onRotationEnd(this); 79 | } 80 | } 81 | } 82 | 83 | public boolean onTouchEvent(MotionEvent event) { 84 | switch (event.getActionMasked()) { 85 | 86 | case MotionEvent.ACTION_DOWN: 87 | mInProgress = false; 88 | mPointerIds[0] = event.getPointerId(event.getActionIndex()); 89 | mPointerIds[1] = MotionEvent.INVALID_POINTER_ID; 90 | break; 91 | 92 | case MotionEvent.ACTION_POINTER_DOWN: 93 | if (!mInProgress) { 94 | mPointerIds[1] = event.getPointerId(event.getActionIndex()); 95 | mInProgress = true; 96 | mPrevTime = event.getEventTime(); 97 | mPrevAngle = Double.NaN; 98 | updateCurrent(event); 99 | if (mListener != null) { 100 | mListener.onRotationBegin(this); 101 | } 102 | } 103 | break; 104 | 105 | case MotionEvent.ACTION_MOVE: 106 | if (mInProgress) { 107 | updateCurrent(event); 108 | if (mListener != null) { 109 | mListener.onRotation(this); 110 | } 111 | } 112 | break; 113 | 114 | case MotionEvent.ACTION_POINTER_UP: 115 | if (mInProgress) { 116 | int pointerId = event.getPointerId(event.getActionIndex()); 117 | if (pointerId == mPointerIds[0] || pointerId == mPointerIds[1]) { 118 | // One of the key pointer has been lifted up, we have to end the gesture 119 | finish(); 120 | } 121 | } 122 | break; 123 | 124 | case MotionEvent.ACTION_UP: 125 | finish(); 126 | break; 127 | } 128 | return true; 129 | } 130 | 131 | /** 132 | * Returns rotation in radians since the previous rotation event. 133 | * 134 | * @return current rotation step in radians. 135 | */ 136 | public double getRotation() { 137 | return mAngleDiff; 138 | } 139 | 140 | /** 141 | * Return the time difference in milliseconds between the previous accepted 142 | * rotation event and the current rotation event. 143 | * 144 | * @return Time difference since the last rotation event in milliseconds. 145 | */ 146 | public long getTimeDelta() { 147 | return mCurrTime - mPrevTime; 148 | } 149 | 150 | /** 151 | * Returns X coordinate of the rotation anchor point relative to the view that 152 | * the provided motion event coordinates (usually relative to the view event was 153 | * sent to). 154 | * 155 | * @return X coordinate of the rotation anchor point 156 | */ 157 | public float getAnchorX() { 158 | return mAnchorX; 159 | } 160 | 161 | /** 162 | * Returns Y coordinate of the rotation anchor point relative to the view that 163 | * the provided motion event coordinates (usually relative to the view event was 164 | * sent to). 165 | * 166 | * @return Y coordinate of the rotation anchor point 167 | */ 168 | public float getAnchorY() { 169 | return mAnchorY; 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /packages/gesturehandler/platforms/android/java/com/swmansion/gesturehandler/TapGestureHandler.java: -------------------------------------------------------------------------------- 1 | package com.swmansion.gesturehandler; 2 | 3 | import android.util.Log; 4 | 5 | import android.os.Handler; 6 | import android.view.MotionEvent; 7 | 8 | public class TapGestureHandler extends GestureHandler { 9 | private final String TAG = "TapGestureHandler"; 10 | private static float MAX_VALUE_IGNORE = Float.MIN_VALUE; 11 | private static final long DEFAULT_MAX_DURATION_MS = 500; 12 | private static final long DEFAULT_MAX_DELAY_MS = 500; 13 | private static final int DEFAULT_NUMBER_OF_TAPS = 1; 14 | private static final int DEFAULT_MIN_NUMBER_OF_POINTERS = 1; 15 | 16 | private float mMaxDeltaX = MAX_VALUE_IGNORE; 17 | private float mMaxDeltaY = MAX_VALUE_IGNORE; 18 | private float mMaxDistSq = MAX_VALUE_IGNORE; 19 | 20 | private long mMaxDurationMs = DEFAULT_MAX_DURATION_MS; 21 | private long mMaxDelayMs = DEFAULT_MAX_DELAY_MS; 22 | private int mNumberOfTaps = DEFAULT_NUMBER_OF_TAPS; 23 | private int mMinNumberOfPointers = DEFAULT_MIN_NUMBER_OF_POINTERS; 24 | private int mNumberOfPointers = 1; 25 | 26 | private float mStartX, mStartY; 27 | private float mOffsetX, mOffsetY; 28 | private float mLastX, mLastY; 29 | 30 | private Handler mHandler; 31 | private int mTapsSoFar; 32 | 33 | private final Runnable mFailDelayed = new Runnable() { 34 | @Override 35 | public void run() { 36 | fail(); 37 | } 38 | }; 39 | 40 | public TapGestureHandler setNumberOfTaps(int numberOfTaps) { 41 | mNumberOfTaps = numberOfTaps; 42 | return this; 43 | } 44 | 45 | public TapGestureHandler setMaxDelayMs(long maxDelayMs) { 46 | mMaxDelayMs = maxDelayMs; 47 | return this; 48 | } 49 | 50 | public TapGestureHandler setMaxDurationMs(long maxDurationMs) { 51 | mMaxDurationMs = maxDurationMs; 52 | return this; 53 | } 54 | 55 | public TapGestureHandler setMaxDx(float deltaX) { 56 | mMaxDeltaX = deltaX; 57 | return this; 58 | } 59 | 60 | public TapGestureHandler setMaxDy(float deltaY) { 61 | mMaxDeltaY = deltaY; 62 | return this; 63 | } 64 | 65 | public TapGestureHandler setMaxDist(float maxDist) { 66 | mMaxDistSq = maxDist * maxDist; 67 | return this; 68 | } 69 | 70 | public TapGestureHandler setMinNumberOfPointers(int minNumberOfPointers) { 71 | mMinNumberOfPointers = minNumberOfPointers; 72 | return this; 73 | } 74 | 75 | public TapGestureHandler() { 76 | setShouldCancelWhenOutside(true); 77 | } 78 | 79 | private void startTap() { 80 | if (mHandler == null) { 81 | mHandler = new Handler(); 82 | } else { 83 | mHandler.removeCallbacksAndMessages(null); 84 | } 85 | mHandler.postDelayed(mFailDelayed, mMaxDurationMs); 86 | } 87 | 88 | private void endTap() { 89 | if (mHandler == null) { 90 | mHandler = new Handler(); 91 | } else { 92 | mHandler.removeCallbacksAndMessages(null); 93 | } 94 | if (++mTapsSoFar == mNumberOfTaps && mNumberOfPointers >= mMinNumberOfPointers) { 95 | activate(); 96 | end(); 97 | } else { 98 | mHandler.postDelayed(mFailDelayed, mMaxDelayMs); 99 | } 100 | } 101 | 102 | private boolean shouldFail() { 103 | float dx = mLastX - mStartX + mOffsetX; 104 | if (mMaxDeltaX != MAX_VALUE_IGNORE && Math.abs(dx) > mMaxDeltaX) { 105 | return true; 106 | } 107 | 108 | float dy = mLastY - mStartY + mOffsetY; 109 | if (mMaxDeltaY != MAX_VALUE_IGNORE && Math.abs(dy) > mMaxDeltaY) { 110 | return true; 111 | } 112 | 113 | float dist = dy * dy + dx * dx; 114 | return mMaxDistSq != MAX_VALUE_IGNORE && dist > mMaxDistSq; 115 | } 116 | 117 | @Override 118 | protected void onHandle(MotionEvent event) { 119 | int state = getState(); 120 | int action = event.getActionMasked(); 121 | 122 | if (state == STATE_UNDETERMINED) { 123 | mOffsetX = 0; 124 | mOffsetY = 0; 125 | mStartX = event.getRawX(); 126 | mStartY = event.getRawY(); 127 | } 128 | 129 | if (action == MotionEvent.ACTION_POINTER_UP || action == MotionEvent.ACTION_POINTER_DOWN) { 130 | mOffsetX += mLastX - mStartX; 131 | mOffsetY += mLastY - mStartY; 132 | mLastX = GestureUtils.getLastPointerX(event, true); 133 | mLastY = GestureUtils.getLastPointerY(event, true); 134 | mStartX = mLastX; 135 | mStartY = mLastY; 136 | } else { 137 | mLastX = GestureUtils.getLastPointerX(event, true); 138 | mLastY = GestureUtils.getLastPointerY(event, true); 139 | } 140 | 141 | if (mNumberOfPointers < event.getPointerCount()) { 142 | mNumberOfPointers = event.getPointerCount(); 143 | } 144 | 145 | if (shouldFail()) { 146 | fail(); 147 | } else if (state == STATE_UNDETERMINED) { 148 | if (action == MotionEvent.ACTION_DOWN) { 149 | begin(); 150 | } 151 | startTap(); 152 | } else if (state == STATE_BEGAN) { 153 | if (action == MotionEvent.ACTION_UP) { 154 | endTap(); 155 | } else if (action == MotionEvent.ACTION_DOWN) { 156 | startTap(); 157 | } 158 | } 159 | } 160 | 161 | @Override 162 | protected void onCancel() { 163 | if (mHandler != null) { 164 | mHandler.removeCallbacksAndMessages(null); 165 | } 166 | } 167 | 168 | @Override 169 | protected void onReset() { 170 | mTapsSoFar = 0; 171 | mNumberOfPointers = 0; 172 | if (mHandler != null) { 173 | mHandler.removeCallbacksAndMessages(null); 174 | } 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /docs/functions/install.html: -------------------------------------------------------------------------------- 1 | install | @nativescript-community/gesturehandler

Function install

  • Parameters

    • OptionaloverrideNGestures: boolean

    Returns any

2 | -------------------------------------------------------------------------------- /src-native/android/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /src-native/android/gesturehandler/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /packages/gesturehandler/platforms/android/java/com/swmansion/gesturehandler/NativeViewGestureHandler.java: -------------------------------------------------------------------------------- 1 | package com.swmansion.gesturehandler; 2 | 3 | import android.os.SystemClock; 4 | import android.view.MotionEvent; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | 8 | import android.util.Log; 9 | 10 | public class NativeViewGestureHandler extends GestureHandler { 11 | 12 | private boolean mShouldActivateOnStart = false; 13 | private boolean mDisallowInterruption = false; 14 | 15 | public NativeViewGestureHandler() { 16 | setShouldCancelWhenOutside(true); 17 | } 18 | 19 | protected void onPrepare() { 20 | 21 | } 22 | 23 | 24 | public NativeViewGestureHandler setShouldActivateOnStart(boolean shouldActivateOnStart) { 25 | mShouldActivateOnStart = shouldActivateOnStart; 26 | return this; 27 | } 28 | 29 | /** 30 | * Set this to {@code true} when wrapping native components that are supposed to 31 | * be an exclusive target for a touch stream. Like for example switch or slider 32 | * component which when activated aren't supposed to be cancelled by scrollview 33 | * or other container that may also handle touches. 34 | */ 35 | public NativeViewGestureHandler setDisallowInterruption(boolean disallowInterruption) { 36 | mDisallowInterruption = disallowInterruption; 37 | return this; 38 | } 39 | 40 | @Override 41 | public boolean shouldRequireToWaitForFailure(GestureHandler handler) { 42 | return super.shouldRequireToWaitForFailure(handler); 43 | } 44 | 45 | @Override 46 | public boolean shouldRecognizeSimultaneously(GestureHandler handler) { 47 | if (handler instanceof NativeViewGestureHandler) { 48 | // Special case when the peer handler is also an instance of 49 | // NativeViewGestureHandler: 50 | // For the `disallowInterruption` to work correctly we need to check the 51 | // property when 52 | // accessed as a peer, because simultaneous recognizers can be set on either 53 | // side of the 54 | // connection. 55 | NativeViewGestureHandler nativeWrapper = (NativeViewGestureHandler) handler; 56 | if (nativeWrapper.getState() == STATE_ACTIVE && nativeWrapper.mDisallowInterruption) { 57 | // other handler is active and it disallows interruption, we don't want to get 58 | // into its way 59 | return false; 60 | } 61 | } 62 | 63 | boolean canBeInterrupted = !mDisallowInterruption; 64 | 65 | if (GestureHandler.debug) { 66 | Log.d("JS", "NativeViewGestureHandler shouldRecognizeSimultaneously " + canBeInterrupted); 67 | } 68 | int state = getState(); 69 | int otherState = handler.getState(); 70 | 71 | if (state == STATE_ACTIVE && otherState == STATE_ACTIVE && canBeInterrupted) { 72 | // if both handlers are active and the current handler can be interruped it we 73 | // return `false` 74 | // as it means the other handler has turned active and returning `true` would 75 | // prevent it from 76 | // interrupting the current handler 77 | return false; 78 | } 79 | // otherwise we can only return `true` if already in an active state 80 | return state == STATE_ACTIVE && canBeInterrupted; 81 | } 82 | 83 | @Override 84 | public boolean shouldBeCancelledBy(GestureHandler handler) { 85 | 86 | // if (GestureHandler.debug) { 87 | // Log.d("JS", "NativeViewGestureHandler shouldBeCancelledBy " + mDisallowInterruption); 88 | // } 89 | return !mDisallowInterruption; 90 | } 91 | 92 | @Override 93 | protected void onHandle(MotionEvent event) { 94 | View view = getView(); 95 | int state = getState(); 96 | if (GestureHandler.debug) { 97 | Log.d("JS", "NativeViewGestureHandler onHandle " + state + " " + view +" " + event.getActionMasked() + " " + " " + mShouldActivateOnStart); 98 | } 99 | if (event.getActionMasked() == MotionEvent.ACTION_UP) { 100 | view.dispatchTouchEvent(event); 101 | if ((state == STATE_UNDETERMINED || state == STATE_BEGAN) && view.isPressed()) { 102 | activate(); 103 | } 104 | end(); 105 | } else if (state == STATE_UNDETERMINED || state == STATE_BEGAN) { 106 | 107 | if (mShouldActivateOnStart) { 108 | tryIntercept(view, event); 109 | view.dispatchTouchEvent(event); 110 | activate(); 111 | } else if (tryIntercept(view, event)) { 112 | view.dispatchTouchEvent(event); 113 | activate(); 114 | } else if (state != STATE_BEGAN) { 115 | begin(); 116 | } 117 | } else if (state == STATE_ACTIVE) { 118 | view.dispatchTouchEvent(event); 119 | } 120 | } 121 | 122 | private static boolean tryIntercept(View view, MotionEvent event) { 123 | if (view instanceof ViewGroup && ((ViewGroup) view).onInterceptTouchEvent(event)) { 124 | // if (GestureHandler.debug) { 125 | // Log.d("JS", "NativeViewGestureHandler tryIntercept true"); 126 | // } 127 | return true; 128 | } 129 | // if (GestureHandler.debug) { 130 | // Log.d("JS", "NativeViewGestureHandler tryIntercept false"); 131 | // } 132 | return false; 133 | } 134 | 135 | @Override 136 | protected void onCancel() { 137 | View view = getView(); 138 | if (view == null) { 139 | return; 140 | } 141 | if (GestureHandler.debug) { 142 | Log.d("JS", "NativeViewGestureHandler onCancel " + view); 143 | } 144 | long time = SystemClock.uptimeMillis(); 145 | MotionEvent event = MotionEvent.obtain(time, time, MotionEvent.ACTION_CANCEL, 0, 0, 0); 146 | event.setAction(MotionEvent.ACTION_CANCEL); 147 | getView().onTouchEvent(event); 148 | event.recycle(); 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /packages/gesturehandler/platforms/ios/src/FlingHandler.m: -------------------------------------------------------------------------------- 1 | #import "FlingHandler.h" 2 | 3 | 4 | @interface FlingGestureHandler(){ 5 | @protected UISwipeGestureRecognizer *_rightrecognizer; 6 | @protected UISwipeGestureRecognizer *_toprecognizer; 7 | @protected UISwipeGestureRecognizer *_bottomrecognizer; 8 | 9 | } 10 | @property (nonatomic) UISwipeGestureRecognizerDirection direction; 11 | @end 12 | @implementation FlingGestureHandler 13 | 14 | - (instancetype)initWithTag:(NSNumber *)tag 15 | { 16 | if ((self = [super initWithTag:tag])) { 17 | _direction = UISwipeGestureRecognizerDirectionLeft | UISwipeGestureRecognizerDirectionRight | UISwipeGestureRecognizerDirectionUp | UISwipeGestureRecognizerDirectionDown; 18 | _recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handleGesture:)]; 19 | [(UISwipeGestureRecognizer*)_recognizer setDirection:UISwipeGestureRecognizerDirectionLeft]; 20 | _rightrecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handleGesture:)]; 21 | [(UISwipeGestureRecognizer*)_rightrecognizer setDirection:UISwipeGestureRecognizerDirectionRight]; 22 | _toprecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handleGesture:)]; 23 | [(UISwipeGestureRecognizer*)_toprecognizer setDirection: UISwipeGestureRecognizerDirectionUp]; 24 | _bottomrecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handleGesture:)]; 25 | [(UISwipeGestureRecognizer*)_bottomrecognizer setDirection:UISwipeGestureRecognizerDirectionDown]; 26 | } 27 | return self; 28 | } 29 | 30 | - (void)configure:(NSDictionary *)config 31 | { 32 | [super configure:config]; 33 | UISwipeGestureRecognizer *recognizer = (UISwipeGestureRecognizer *)_recognizer; 34 | 35 | id prop = config[@"direction"]; 36 | if (prop != nil) { 37 | _direction = [prop integerValue]; 38 | if ((_direction & UISwipeGestureRecognizerDirectionLeft) == 0) { 39 | _recognizer.enabled = NO; 40 | } 41 | if ((_direction & UISwipeGestureRecognizerDirectionRight) == 0) { 42 | _rightrecognizer.enabled = NO; 43 | } 44 | if ((_direction & UISwipeGestureRecognizerDirectionUp) == 0) { 45 | _toprecognizer.enabled = NO; 46 | } 47 | if ((_direction & UISwipeGestureRecognizerDirectionDown) == 0) { 48 | _bottomrecognizer.enabled = NO; 49 | } 50 | } 51 | 52 | #if !TARGET_OS_TV 53 | prop = config[@"numberOfPointers"]; 54 | if (prop != nil) { 55 | NSInteger numberOfTouchesRequired = [prop integerValue]; 56 | recognizer.numberOfTouchesRequired = numberOfTouchesRequired; 57 | _rightrecognizer.numberOfTouchesRequired = numberOfTouchesRequired; 58 | _toprecognizer.numberOfTouchesRequired = numberOfTouchesRequired; 59 | _bottomrecognizer.numberOfTouchesRequired = numberOfTouchesRequired; 60 | } 61 | #endif 62 | } 63 | - (void)setEnabled:(BOOL)enabled 64 | { 65 | [super setEnabled:enabled]; 66 | self.recognizer.enabled = enabled; 67 | _rightrecognizer.enabled = enabled && ((self.direction & UISwipeGestureRecognizerDirectionRight) != 0); 68 | _toprecognizer.enabled = enabled && ((self.direction & UISwipeGestureRecognizerDirectionUp) != 0); 69 | _bottomrecognizer.enabled = enabled && ((self.direction & UISwipeGestureRecognizerDirectionDown) != 0); 70 | } 71 | 72 | - (void)bindToView:(UIView *)view 73 | { 74 | [super bindToView:view]; 75 | _rightrecognizer.delegate = self; 76 | [view addGestureRecognizer:_rightrecognizer]; 77 | _toprecognizer.delegate = self; 78 | [view addGestureRecognizer:_toprecognizer]; 79 | _bottomrecognizer.delegate = self; 80 | [view addGestureRecognizer:_bottomrecognizer]; 81 | } 82 | - (void)unbindFromView 83 | { 84 | [super unbindFromView]; 85 | [_rightrecognizer.view removeGestureRecognizer:_rightrecognizer]; 86 | _rightrecognizer.delegate = nil; 87 | [_toprecognizer.view removeGestureRecognizer:_toprecognizer]; 88 | _toprecognizer.delegate = nil; 89 | [_bottomrecognizer.view removeGestureRecognizer:_bottomrecognizer]; 90 | _bottomrecognizer.delegate = nil; 91 | } 92 | - (void) setDirection:(NSInteger) value { 93 | _direction = value; 94 | _recognizer.enabled = (_direction & UISwipeGestureRecognizerDirectionLeft) != 0; 95 | _rightrecognizer.enabled = (_direction & UISwipeGestureRecognizerDirectionRight) != 0; 96 | _toprecognizer.enabled = (_direction & UISwipeGestureRecognizerDirectionUp) != 0; 97 | _bottomrecognizer.enabled = (_direction & UISwipeGestureRecognizerDirectionDown) != 0; 98 | } 99 | // 100 | //- (NSNumber *) direction { 101 | // return [NSNumber numberWithInteger: ((UISwipeGestureRecognizer *)_recognizer).direction]; 102 | //} 103 | // 104 | - (void) setNumberOfTouchesRequired:(NSInteger) value { 105 | ((UISwipeGestureRecognizer *)_recognizer).numberOfTouchesRequired = value; 106 | } 107 | // 108 | //- (NSNumber *) numberOfTouchesRequired { 109 | // return [NSNumber numberWithInteger: ((UISwipeGestureRecognizer *)_recognizer).numberOfTouchesRequired]; 110 | //} 111 | 112 | -(NSString*)directionToString:(UISwipeGestureRecognizerDirection) direction { 113 | if (direction == UISwipeGestureRecognizerDirectionDown) { 114 | return @"down"; 115 | } 116 | if (direction == UISwipeGestureRecognizerDirectionUp) { 117 | return @"up"; 118 | } 119 | if (direction == UISwipeGestureRecognizerDirectionLeft) { 120 | return @"left"; 121 | } 122 | if (direction == UISwipeGestureRecognizerDirectionRight) { 123 | return @"right"; 124 | } 125 | return NULL; 126 | } 127 | 128 | - (NSMutableDictionary *)eventExtraData:(UISwipeGestureRecognizer *)recognizer 129 | { 130 | NSMutableDictionary* result = [super eventExtraData:recognizer]; 131 | [result setObject:[self directionToString:recognizer.direction] forKey:@"direction"]; 132 | return result; 133 | } 134 | @end 135 | -------------------------------------------------------------------------------- /packages/gesturehandler/platforms/ios/src/NativeViewHandler.m: -------------------------------------------------------------------------------- 1 | // 2 | // NativeViewHandler.m 3 | // GestureHandler 4 | // 5 | // Created by Krzysztof Magiera on 12/10/2017. 6 | // Copyright © 2017 Software Mansion. All rights reserved. 7 | // 8 | 9 | #import "NativeViewHandler.h" 10 | 11 | #import 12 | 13 | 14 | #pragma mark DummyGestureRecognizer 15 | 16 | @implementation DummyGestureRecognizer 17 | 18 | - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event 19 | { 20 | self.state = UIGestureRecognizerStateFailed; 21 | [self reset]; 22 | } 23 | 24 | - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event 25 | { 26 | self.state = UIGestureRecognizerStateCancelled; 27 | [self reset]; 28 | } 29 | 30 | @end 31 | 32 | #pragma mark NativeViewgestureHandler 33 | 34 | @implementation NativeViewGestureHandler { 35 | BOOL _shouldActivateOnStart; 36 | BOOL _disallowInterruption; 37 | } 38 | 39 | - (instancetype)initWithTag:(NSNumber *)tag 40 | { 41 | if ((self = [super initWithTag:tag])) { 42 | _recognizer = [[DummyGestureRecognizer alloc] init]; 43 | self.shouldCancelWhenOutside = YES; 44 | } 45 | return self; 46 | } 47 | 48 | - (void)configure:(NSDictionary *)config 49 | { 50 | [super configure:config]; 51 | _shouldActivateOnStart = [config[@"shouldActivateOnStart"] boolValue]; 52 | _disallowInterruption = [config[@"disallowInterruption"] boolValue]; 53 | } 54 | 55 | // 56 | - (void) setShouldActivateOnStart:(Boolean) value { 57 | _shouldActivateOnStart = value; 58 | } 59 | // 60 | //- (NSNumber *) shouldActivateOnStart { 61 | // return [NSNumber numberWithBool: _shouldActivateOnStart]; 62 | //} 63 | - (void) setDisallowInterruption:(Boolean) value { 64 | _disallowInterruption = value; 65 | } 66 | // 67 | //- (NSNumber *) disallowInterruption { 68 | // return [NSNumber numberWithBool: _disallowInterruption]; 69 | //} 70 | 71 | 72 | - (void)bindToView:(UIView *)view 73 | { 74 | // For UIControl based views (UIButton, UISwitch) we provide special handling that would allow 75 | // for properties like `disallowInterruption` to work. 76 | if ([view isKindOfClass:[UIControl class]]) { 77 | UIControl *control = (UIControl *)view; 78 | [control addTarget:self action:@selector(handleTouchDown:forEvent:) forControlEvents:UIControlEventTouchDown]; 79 | [control addTarget:self action:@selector(handleTouchUpOutside:forEvent:) forControlEvents:UIControlEventTouchUpOutside]; 80 | [control addTarget:self action:@selector(handleTouchUpInside:forEvent:) forControlEvents:UIControlEventTouchUpInside]; 81 | [control addTarget:self action:@selector(handleDragExit:forEvent:) forControlEvents:UIControlEventTouchDragExit]; 82 | [control addTarget:self action:@selector(handleDragEnter:forEvent:) forControlEvents:UIControlEventTouchDragEnter]; 83 | [control addTarget:self action:@selector(handleTouchCancel:forEvent:) forControlEvents:UIControlEventTouchCancel]; 84 | } else { 85 | [super bindToView:view]; 86 | } 87 | 88 | // We can restore default scrollview behaviour to delay touches to scrollview's children 89 | // because gesture handler system can handle cancellation of scroll recognizer when JS responder 90 | // is set 91 | if ([view isKindOfClass:[UIScrollView class]]) { 92 | // This part of the code is coupled with RN implementation of ScrollView native wrapper and 93 | // we expect for RCTScrollView component to contain a subclass of UIScrollview as the only 94 | // subview 95 | UIScrollView *scrollView = (UIScrollView*)view; 96 | scrollView.delaysContentTouches = YES; 97 | } 98 | } 99 | 100 | - (void)handleTouchDown:(UIView *)sender forEvent:(UIEvent *)event 101 | { 102 | [self reset]; 103 | 104 | if (_disallowInterruption) { 105 | // When `disallowInterruption` is set we cancel all gesture handlers when this UIControl 106 | // gets DOWN event 107 | for (UITouch *touch in [event allTouches]) { 108 | for (UIGestureRecognizer *recogn in [touch gestureRecognizers]) { 109 | recogn.enabled = NO; 110 | recogn.enabled = YES; 111 | } 112 | } 113 | } 114 | [self sendEventsInState:GestureHandlerStateActive 115 | forView:sender 116 | withExtraData:@{@"pointerInside": @(YES)}]; 117 | } 118 | 119 | - (void)handleTouchUpOutside:(UIView *)sender forEvent:(UIEvent *)event 120 | { 121 | [self sendEventsInState:GestureHandlerStateEnd 122 | forView:sender 123 | withExtraData:@{@"pointerInside": @(NO)}]; 124 | } 125 | 126 | - (void)handleTouchUpInside:(UIView *)sender forEvent:(UIEvent *)event 127 | { 128 | [self sendEventsInState:GestureHandlerStateEnd 129 | forView:sender 130 | withExtraData:@{@"pointerInside": @(YES)}]; 131 | } 132 | 133 | - (void)handleDragExit:(UIView *)sender forEvent:(UIEvent *)event 134 | { 135 | // Pointer is moved outside of the view bounds, we cancel button when `shouldCancelWhenOutside` is set 136 | if (self.shouldCancelWhenOutside) { 137 | UIControl *control = (UIControl *)sender; 138 | [control cancelTrackingWithEvent:event]; 139 | [self sendEventsInState:GestureHandlerStateEnd 140 | forView:sender 141 | withExtraData:@{@"pointerInside": @(NO)}]; 142 | } else { 143 | [self sendEventsInState:GestureHandlerStateActive 144 | forView:sender 145 | withExtraData:@{@"pointerInside": @(NO)}]; 146 | } 147 | } 148 | 149 | - (void)handleDragEnter:(UIView *)sender forEvent:(UIEvent *)event 150 | { 151 | [self sendEventsInState:GestureHandlerStateActive 152 | forView:sender 153 | withExtraData:@{@"pointerInside": @(YES)}]; 154 | } 155 | 156 | - (void)handleTouchCancel:(UIView *)sender forEvent:(UIEvent *)event 157 | { 158 | [self sendEventsInState:GestureHandlerStateCancelled 159 | forView:sender 160 | withExtraData:@{@"pointerInside": @(NO)}]; 161 | } 162 | 163 | @end 164 | -------------------------------------------------------------------------------- /src/gesturehandler/gesturehandler.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-redeclare */ 2 | import Observable from '@nativescript-community/observable'; 3 | import { View } from '@nativescript/core'; 4 | import { BaseGestureRootView, HandlerType, OptionsTypeMap, TypeMap } from './gesturehandler.common'; 5 | 6 | export { GestureState, GestureHandlerStateEvent, GestureHandlerTouchEvent, GestureStateEventData, GestureTouchEventData, HandlerType } from './gesturehandler.common'; 7 | // export * from './gesturehandler.ios'; 8 | 9 | declare module '@nativescript/core/ui/core/view' { 10 | interface View { 11 | tapGestureOptions: Partial; 12 | panGestureOptions: Partial; 13 | doubleTapGestureOptions: Partial; 14 | longPressGestureOptions: Partial; 15 | swipeGestureOptions: Partial; 16 | pinchGestureOptions: Partial; 17 | rotationGestureOptions: Partial; 18 | } 19 | } 20 | 21 | export enum FlingDirection { 22 | DIRECTION_LEFT, 23 | DIRECTION_UP, 24 | DIRECTION_DOWN, 25 | DIRECTION_RIGHT, 26 | } 27 | 28 | export abstract class BaseNative extends Observable { 29 | options?: U; 30 | native: T; 31 | constructor(options?: U, native?: T); 32 | initNativeView(native: T, options: U): void; 33 | getNative(): T; 34 | log(...args); 35 | } 36 | export interface NativePropertyOptions { 37 | converter?: { 38 | fromNative: Function; 39 | toNative: Function; 40 | }; 41 | defaultValue?: any; 42 | nativeGetterName?: string; 43 | nativeSetterName?: string; 44 | getConverter?: Function; 45 | ios?: { 46 | nativeGetterName?: string; 47 | nativeSetterName?: string; 48 | }; 49 | android?: { 50 | nativeGetterName?: string; 51 | nativeSetterName?: string; 52 | }; 53 | } 54 | 55 | export declare function nativeProperty(target: any, k?, desc?: PropertyDescriptor): any; 56 | export declare function nativeProperty(options: NativePropertyOptions): (target: any, k?, desc?: PropertyDescriptor) => any; 57 | export declare function nativeProperty(...args); 58 | 59 | export interface HandlerOptions { 60 | [k: string]: any; 61 | enabled?: boolean; 62 | shouldCancelWhenOutside?: boolean; 63 | waitFor?: number[]; 64 | simultaneousHandlers?: number[]; 65 | /** 66 | * optional property to access the View nativeView 67 | * 68 | * @memberof HandlerOptions 69 | */ 70 | nativeGetterKey?: string; 71 | } 72 | export abstract class Handler extends BaseNative { 73 | enabled: boolean; 74 | shouldCancelWhenOutside: boolean; 75 | setTag(tag: number); 76 | getTag(): number; 77 | getView(): View; 78 | cancel(); 79 | attachToView(view: View); 80 | detachFromView(view?: View); 81 | } 82 | export interface TapGestureHandlerOptions extends HandlerOptions { 83 | numberOfTaps?: number; 84 | maxDurationMs?: number; 85 | maxDelayMs?: number; 86 | maxDeltaX?: number; 87 | maxDeltaY?: number; 88 | maxDist?: number; 89 | minPointers?: number; 90 | } 91 | 92 | export class TapGestureHandler extends Handler { 93 | numberOfTaps: number; 94 | maxDurationMs: number; 95 | maxDelayMs: number; 96 | maxDeltaX: number; 97 | maxDeltaY: number; 98 | maxDist: number; 99 | minPointers: number; 100 | } 101 | export interface PanGestureHandlerOptions extends HandlerOptions { 102 | minDist?: number; 103 | activeOffsetXStart?: number; 104 | activeOffsetXEnd?: number; 105 | failOffsetXStart?: number; 106 | failOffsetXEnd?: number; 107 | activeOffsetYStart?: number; 108 | activeOffsetYEnd?: number; 109 | failOffsetYStart?: number; 110 | failOffsetYEnd?: number; 111 | } 112 | 113 | export class PanGestureHandler extends Handler { 114 | minDist: number; 115 | activeOffsetXStart: number; 116 | activeOffsetXEnd: number; 117 | failOffsetXStart: number; 118 | failOffsetXEnd: number; 119 | activeOffsetYStart: number; 120 | activeOffsetYEnd: number; 121 | failOffsetYStart: number; 122 | failOffsetYEnd: number; 123 | } 124 | export interface NativeViewGestureHandlerOptions extends HandlerOptions { 125 | shouldActivateOnStart?: boolean; 126 | disallowInterruption?: boolean; 127 | } 128 | export class NativeViewGestureHandler extends Handler { 129 | shouldActivateOnStart: boolean; 130 | disallowInterruption: boolean; 131 | } 132 | export interface LongPressGestureHandlerOptions extends HandlerOptions { 133 | maxDist?: number; 134 | minDurationMs?: number; 135 | } 136 | export class LongPressGestureHandler extends Handler { 137 | maxDist: number; 138 | minDurationMs: number; 139 | } 140 | export interface FlingGestureHandlerOptions extends HandlerOptions { 141 | numberOfPointers?: number; 142 | direction?: number; 143 | } 144 | export class FlingGestureHandler extends Handler { 145 | numberOfPointers: number; 146 | direction: number; 147 | } 148 | export interface PinchGestureHandlerOptions extends HandlerOptions { 149 | minSpan?: number; // Android only 150 | } 151 | export class PinchGestureHandler extends Handler {} 152 | export interface RotationGestureHandlerOptions extends HandlerOptions {} 153 | export class RotationGestureHandler extends Handler {} 154 | 155 | export interface ForceTouchGestureHandlerOptions extends HandlerOptions { 156 | minForce?: number; 157 | maxForce?: number; 158 | feedbackOnActivation?: boolean; 159 | } 160 | export class ForceTouchGestureHandler extends Handler { 161 | minForce: number; 162 | maxForce: number; 163 | feedbackOnActivation: boolean; 164 | } 165 | 166 | export class Manager extends Observable { 167 | static getInstance(): Manager; 168 | createGestureHandler(handlerName: T, handlerTag: number, config?: OptionsTypeMap[T]): TypeMap[T]; 169 | } 170 | export function install(overrideNGestures?: boolean); 171 | 172 | export class GestureRootView extends BaseGestureRootView {} 173 | -------------------------------------------------------------------------------- /packages/gesturehandler/platforms/ios/src/GestureHandlerManager.m: -------------------------------------------------------------------------------- 1 | #import "GestureHandlerManager.h" 2 | 3 | #import "GestureHandlerState.h" 4 | #import "GestureHandler.h" 5 | #import "GestureHandlerRegistry.h" 6 | #import "RootViewGestureRecognizer.h" 7 | 8 | #import "PanHandler.h" 9 | #import "TapHandler.h" 10 | #import "FlingHandler.h" 11 | #import "LongPressHandler.h" 12 | #import "NativeViewHandler.h" 13 | #import "PinchHandler.h" 14 | #import "RotationHandler.h" 15 | #import "ForceTouchHandler.h" 16 | 17 | 18 | @interface GestureHandlerManager () 19 | 20 | @end 21 | 22 | @implementation GestureHandlerManager 23 | { 24 | GestureHandlerRegistry *_registry; 25 | NSMutableSet *_rootViews; 26 | } 27 | 28 | - (instancetype)init 29 | { 30 | if ((self = [super init])) { 31 | _registry = [GestureHandlerRegistry new]; 32 | _rootViews = [NSMutableSet new]; 33 | } 34 | return self; 35 | } 36 | 37 | - (GestureHandler*)createGestureHandler:(NSString *)handlerName 38 | tag:(NSNumber *)handlerTag 39 | config:(NSDictionary *)config 40 | { 41 | static NSDictionary *map; 42 | static dispatch_once_t mapToken; 43 | dispatch_once(&mapToken, ^{ 44 | map = @{ 45 | @"pan" : [PanGestureHandler class], 46 | @"tap" : [TapGestureHandler class], 47 | @"fling" : [FlingGestureHandler class], 48 | @"longPress": [LongPressGestureHandler class], 49 | @"nativeView": [NativeViewGestureHandler class], 50 | @"pinch": [PinchGestureHandler class], 51 | @"rotation": [RotationGestureHandler class], 52 | @"forceTouch": [ForceTouchHandler class], 53 | }; 54 | }); 55 | 56 | Class nodeClass = map[handlerName]; 57 | if (!nodeClass) { 58 | NSLog(@"Gesture handler type %@ is not supported", handlerName); 59 | return nil; 60 | } 61 | 62 | GestureHandler *gestureHandler = [[nodeClass alloc] initWithTag:handlerTag]; 63 | [gestureHandler configure:config]; 64 | [_registry registerGestureHandler:gestureHandler]; 65 | return gestureHandler; 66 | // __weak id emitter = self; 67 | // gestureHandler.emitter = emitter; 68 | } 69 | 70 | 71 | - (void)registerGestureHandler:(nonnull GestureHandler *)gestureHandler 72 | { 73 | [_registry registerGestureHandler:gestureHandler]; 74 | } 75 | - (void)attachGestureHandler:(nonnull NSNumber *)handlerTag 76 | toView:(nonnull UIView *)view 77 | { 78 | [_registry attachHandlerWithTag:handlerTag toView:view]; 79 | 80 | // register root view if not already there 81 | // [self registerRootViewIfNeeded:view]; 82 | } 83 | 84 | - (void)updateGestureHandler:(NSNumber *)handlerTag config:(NSDictionary *)config 85 | { 86 | GestureHandler *handler = [_registry handlerWithTag:handlerTag]; 87 | [handler configure:config]; 88 | } 89 | 90 | - (void)dropGestureHandler:(NSNumber *)handlerTag 91 | { 92 | [_registry dropHandlerWithTag:handlerTag]; 93 | } 94 | 95 | //- (void)handleSetJSResponder:(NSNumber *)viewTag blockNativeResponder:(NSNumber *)blockNativeResponder 96 | //{ 97 | // if ([blockNativeResponder boolValue]) { 98 | // for (RCTRootView *rootView in _rootViews) { 99 | // for (UIGestureRecognizer *recognizer in rootView.gestureRecognizers) { 100 | // if ([recognizer isKindOfClass:[RNRootViewGestureRecognizer class]]) { 101 | // [(RNRootViewGestureRecognizer *)recognizer blockOtherRecognizers]; 102 | // } 103 | // } 104 | // } 105 | // } 106 | //} 107 | 108 | //- (void)handleClearJSResponder 109 | //{ 110 | // // ignore... 111 | //} 112 | 113 | #pragma mark Root Views Management 114 | 115 | //- (void)registerRootViewIfNeeded:(UIView*)childView 116 | //{ 117 | // UIView *parent = childView; 118 | // while (parent != nil && ![parent isKindOfClass:[RCTRootView class]]) parent = parent.superview; 119 | // 120 | // RootView *rootView = (RCTRootView *)parent; 121 | // UIView *rootContentView = rootView.contentView; 122 | // if (rootContentView != nil && ![_rootViews containsObject:rootContentView]) { 123 | // LifecycleLog(@"[GESTURE HANDLER] Initialize gesture handler for root view %@", rootContentView); 124 | // [_rootViews addObject:rootContentView]; 125 | // RootViewGestureRecognizer *recognizer = [RNRootViewGestureRecognizer new]; 126 | // recognizer.delegate = self; 127 | // rootContentView.userInteractionEnabled = YES; 128 | // [rootContentView addGestureRecognizer:recognizer]; 129 | // } 130 | //} 131 | 132 | - (void)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer 133 | didActivateInRootView:(UIView *)rootContentView 134 | { 135 | // Cancel touches in RN's root view in order to cancel all in-js recognizers 136 | 137 | // As scroll events are special-cased in RN responder implementation and sending them would 138 | // trigger JS responder change, we don't cancel touches if the handler that got activated is 139 | // a scroll recognizer. This way root view will keep sending touchMove and touchEnd events 140 | // and therefore allow JS responder to properly release the responder at the end of the touch 141 | // stream. 142 | // NOTE: this is not a proper fix and solving this problem requires upstream fixes to RN. In 143 | // particular if we have one PanHandler and ScrollView that can work simultaniously then when 144 | // the Pan handler activates it would still tigger cancel events. 145 | // Once the upstream fix lands the line below along with this comment can be removed 146 | if ([gestureRecognizer.view isKindOfClass:[UIScrollView class]]) return; 147 | 148 | // UIView *parent = rootContentView.superview; 149 | // if ([parent isKindOfClass:[RCTRootView class]]) { 150 | // [(RCTRootView*)parent cancelTouches]; 151 | // } 152 | } 153 | 154 | - (void)dealloc 155 | { 156 | // if ([_rootViews count] > 0) { 157 | // LifecycleLog(@"[GESTURE HANDLER] Tearing down gesture handler registered for views %@", _rootViews); 158 | // } 159 | } 160 | 161 | //#pragma mark Events 162 | 163 | //- (void)sendTouchEvent:(GestureHandlerEvent *)event 164 | //{ 165 | //// [_eventDispatcher sendEvent:event]; 166 | //} 167 | // 168 | //- (void)sendStateChangeEvent:(GestureHandlerStateChange *)event 169 | //{ 170 | //// [_eventDispatcher sendEvent:event]; 171 | //} 172 | 173 | @end 174 | -------------------------------------------------------------------------------- /packages/gesturehandler/platforms/ios/src/TapHandler.m: -------------------------------------------------------------------------------- 1 | // 2 | // TapHandler.m 3 | // GestureHandler 4 | // 5 | // Created by Krzysztof Magiera on 12/10/2017. 6 | // Copyright © 2017 Software Mansion. All rights reserved. 7 | // 8 | 9 | #import "TapHandler.h" 10 | 11 | #import 12 | 13 | 14 | // BetterTapGestureRecognizer extends UIGestureRecognizer instead of UITapGestureRecognizer 15 | // because the latter does not allow for parameters like maxDelay, maxDuration, minPointers, 16 | // maxDelta to be configured. Using our custom implementation of tap recognizer we are able 17 | // to support these. 18 | 19 | @interface BetterTapGestureRecognizer : UIGestureRecognizer 20 | 21 | @property (nonatomic) NSUInteger numberOfTaps; 22 | @property (nonatomic) NSTimeInterval maxDelay; 23 | @property (nonatomic) NSTimeInterval maxDuration; 24 | @property (nonatomic) CGFloat maxDistSq; 25 | @property (nonatomic) CGFloat maxDeltaX; 26 | @property (nonatomic) CGFloat maxDeltaY; 27 | @property (nonatomic) NSInteger minPointers; 28 | 29 | - (id)initWithGestureHandler:(GestureHandler*)gestureHandler; 30 | 31 | @end 32 | 33 | @implementation BetterTapGestureRecognizer { 34 | __weak TapGestureHandler *_gestureHandler; 35 | NSUInteger _tapsSoFar; 36 | CGPoint _initPosition; 37 | NSInteger _maxNumberOfTouches; 38 | } 39 | 40 | - (id)initWithGestureHandler:(GestureHandler*)gestureHandler 41 | { 42 | if ((self = [super initWithTarget:gestureHandler action:@selector(handleGesture:)])) { 43 | _gestureHandler = (TapGestureHandler*)gestureHandler; 44 | _tapsSoFar = 0; 45 | _numberOfTaps = 1; 46 | _minPointers = 1; 47 | _maxDelay = 0.2; 48 | _maxDuration = NAN; 49 | _maxDeltaX = NAN; 50 | _maxDeltaY = NAN; 51 | _maxDistSq = NAN; 52 | _gestureHandler.shouldCancelWhenOutside = YES; 53 | } 54 | return self; 55 | } 56 | 57 | - (void)triggerAction 58 | { 59 | [_gestureHandler handleGesture:self]; 60 | } 61 | 62 | - (void)cancel 63 | { 64 | self.enabled = NO; 65 | } 66 | 67 | - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 68 | { 69 | [_gestureHandler resetStored]; 70 | [super touchesBegan:touches withEvent:event]; 71 | if (_tapsSoFar == 0) { 72 | _initPosition = [self locationInView:self.view]; 73 | } 74 | _tapsSoFar++; 75 | if (_tapsSoFar) { 76 | [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(cancel) object:nil]; 77 | } 78 | NSInteger numberOfTouches = [touches count]; 79 | if (numberOfTouches > _maxNumberOfTouches) { 80 | _maxNumberOfTouches = numberOfTouches; 81 | } 82 | if (!isnan(_maxDuration)) { 83 | [self performSelector:@selector(cancel) withObject:nil afterDelay:_maxDuration]; 84 | } 85 | self.state = UIGestureRecognizerStatePossible; 86 | [self triggerAction]; 87 | } 88 | 89 | - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event 90 | { 91 | [super touchesMoved:touches withEvent:event]; 92 | NSInteger numberOfTouches = [touches count]; 93 | if (numberOfTouches > _maxNumberOfTouches) { 94 | _maxNumberOfTouches = numberOfTouches; 95 | } 96 | 97 | if (self.state != UIGestureRecognizerStatePossible) { 98 | return; 99 | } 100 | 101 | if ([self shouldFailUnderCustomCriteria]) { 102 | self.state = UIGestureRecognizerStateFailed; 103 | [self triggerAction]; 104 | [self reset]; 105 | return; 106 | } 107 | 108 | self.state = UIGestureRecognizerStatePossible; 109 | [self triggerAction]; 110 | } 111 | 112 | - (CGPoint)translationInView { 113 | CGPoint currentPosition = [self locationInView:self.view]; 114 | return CGPointMake(currentPosition.x - _initPosition.x, currentPosition.y - _initPosition.y); 115 | } 116 | 117 | - (BOOL)shouldFailUnderCustomCriteria 118 | { 119 | if (_gestureHandler.shouldCancelWhenOutside) { 120 | if (![_gestureHandler containsPointInView]) { 121 | return YES; 122 | } 123 | } 124 | 125 | CGPoint trans = [self translationInView]; 126 | if (TEST_MAX_IF_NOT_NAN(fabs(trans.x), _maxDeltaX)) { 127 | return YES; 128 | } 129 | if (TEST_MAX_IF_NOT_NAN(fabs(trans.y), _maxDeltaY)) { 130 | return YES; 131 | } 132 | if (TEST_MAX_IF_NOT_NAN(fabs(trans.y * trans.y + trans.x + trans.x), _maxDistSq)) { 133 | return YES; 134 | } 135 | return NO; 136 | } 137 | 138 | - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event 139 | { 140 | [super touchesEnded:touches withEvent:event]; 141 | if (_numberOfTaps == _tapsSoFar && _maxNumberOfTouches >= _minPointers) { 142 | self.state = UIGestureRecognizerStateEnded; 143 | [self reset]; 144 | } else { 145 | [self performSelector:@selector(cancel) withObject:nil afterDelay:_maxDelay]; 146 | } 147 | } 148 | 149 | - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event 150 | { 151 | [super touchesCancelled:touches withEvent:event]; 152 | self.state = UIGestureRecognizerStateCancelled; 153 | [self reset]; 154 | } 155 | 156 | - (void)reset 157 | { 158 | if (self.state == UIGestureRecognizerStateFailed) { 159 | [self triggerAction]; 160 | } 161 | [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(cancel) object:nil]; 162 | _tapsSoFar = 0; 163 | _maxNumberOfTouches = 0; 164 | self.enabled = YES; 165 | [super reset]; 166 | } 167 | 168 | @end 169 | 170 | @implementation TapGestureHandler { 171 | __weak NSMutableDictionary *_lastExtraEventData; 172 | } 173 | 174 | 175 | - (instancetype)initWithTag:(NSNumber *)tag 176 | { 177 | if ((self = [super initWithTag:tag])) { 178 | _recognizer = [[BetterTapGestureRecognizer alloc] initWithGestureHandler:self]; 179 | } 180 | return self; 181 | } 182 | 183 | - (void)configure:(NSDictionary *)config 184 | { 185 | [super configure:config]; 186 | BetterTapGestureRecognizer *recognizer = (BetterTapGestureRecognizer *)_recognizer; 187 | 188 | APPLY_INT_PROP(numberOfTaps); 189 | APPLY_INT_PROP(minPointers); 190 | APPLY_FLOAT_PROP(maxDeltaX); 191 | APPLY_FLOAT_PROP(maxDeltaY); 192 | 193 | id prop = config[@"maxDelayMs"]; 194 | if (prop != nil) { 195 | recognizer.maxDelay = [prop floatValue] / 1000.0; 196 | } 197 | 198 | prop = config[@"maxDurationMs"]; 199 | if (prop != nil) { 200 | recognizer.maxDuration = [prop floatValue] / 1000.0; 201 | } 202 | 203 | prop = config[@"maxDist"]; 204 | if (prop != nil) { 205 | CGFloat dist = [prop floatValue]; 206 | recognizer.maxDistSq = dist * dist; 207 | } 208 | } 209 | 210 | - (void)resetStored 211 | { 212 | _lastExtraEventData = NULL; 213 | } 214 | - (NSMutableDictionary *)eventExtraData:(UIGestureRecognizer *)recognizer 215 | { 216 | if (recognizer.numberOfTouches == 0 && _lastExtraEventData != NULL) { 217 | return _lastExtraEventData; 218 | } 219 | NSMutableDictionary *result = [super eventExtraData:recognizer]; 220 | if (recognizer.numberOfTouches != 0) 221 | { 222 | _lastExtraEventData = result; 223 | } 224 | return result; 225 | } 226 | 227 | 228 | - (void)setMaxDist:(CGFloat)value { 229 | ((BetterTapGestureRecognizer*)_recognizer).maxDistSq = value * value; 230 | } 231 | - (void)setNumberOfTaps:(NSUInteger)value { 232 | ((BetterTapGestureRecognizer*)_recognizer).numberOfTaps = value; 233 | } 234 | - (void)setMaxDelayMs:(CGFloat)value { 235 | ((BetterTapGestureRecognizer*)_recognizer).maxDelay = value / 1000.0; 236 | } 237 | - (void)setMaxDurationMs:(CGFloat)value { 238 | ((BetterTapGestureRecognizer*)_recognizer).maxDuration = value / 1000.0; 239 | } 240 | - (void)setMaxDeltaX:(CGFloat)value { 241 | ((BetterTapGestureRecognizer*)_recognizer).maxDeltaX = value; 242 | } 243 | - (void)setMaxDeltaY:(CGFloat)value { 244 | ((BetterTapGestureRecognizer*)_recognizer).maxDeltaY = value; 245 | } 246 | - (void)setMinPointers:(NSInteger)value { 247 | ((BetterTapGestureRecognizer*)_recognizer).minPointers = value; 248 | } 249 | @end 250 | 251 | --------------------------------------------------------------------------------