Skip to content

longPress gesture fires twice #3573

Closed
Closed

Description

@NordlingDev

Platform: iOS
TNS: 2.5.0

When using the longPress gesture, it will fire once (as it should) and then when you let go of your finger, it fires again. This isn't intentional, is it?

There's no state or action property of the event, so there's no such thing as an "up" event to handle.


Want to back this issue? Post a bounty on it! We accept bounties via Bountysource.

Activity

  1. tsonevn commented on Feb 6, 2017

    @tsonevn
    Contributor

    Hi @NordlingArt,
    Thank you for reporting this issue.
    I was able to reproduce this behavior on my side and confirm that this is a real issue for iOS. I am also attaching sample code, where the problem could be reproduced.

    main-page.xml

    <Page xmlns="http://schemas.nativescript.org/tns.xsd" navigatingTo="navigatingTo" class="page">
    
        <Page.actionBar>
            <ActionBar title="My App" icon="" class="action-bar">
            </ActionBar>
        </Page.actionBar>
    
        <StackLayout class="p-20">
            <Label loaded="labelLoaded" text="Tap the button" class="h1 text-center" />
            <Button text="TAP" tap="{{ onTap }}" class="btn btn-primary btn-active"/>
            <Label text="{{ message }}" class="h2 text-center" textWrap="true"/>
        </StackLayout>
    </Page>
    

    main-page.ts

    import { EventData } from 'data/observable';
    import { Page } from 'ui/page';
    import { HelloWorldModel } from './main-view-model';
    import { GestureTypes, GestureEventData, TouchGestureEventData } from "ui/gestures";
    import labelModule = require("ui/label");
    import {isIOS} from "platform"
    
    // Event handler for Page "navigatingTo" event attached in main-page.xml
    var viewmodel = new HelloWorldModel()
    var statedown=true
    export function navigatingTo(args: EventData) {
    
        let page = <Page>args.object;
     
        page.bindingContext = viewmodel;
    }
    
    export function labelLoaded(args){
        var label = args.object;
        label.on("longPress", function (args: GestureEventData) {
            console.log("longPress");
                    console.log(args.eventName);
                    console.log(args.type);
            
            
        });
        
    
    }
    

    As a workaround, you could create one custom flag, which will allow you to determine the second fire of the event on iOS.

    main-page.ts

    import { EventData } from 'data/observable';
    import { Page } from 'ui/page';
    import { HelloWorldModel } from './main-view-model';
    import { GestureTypes, GestureEventData, TouchGestureEventData } from "ui/gestures";
    import labelModule = require("ui/label");
    import {isIOS} from "platform"
    
    // Event handler for Page "navigatingTo" event attached in main-page.xml
    var viewmodel = new HelloWorldModel()
    var statedown=true
    export function navigatingTo(args: EventData) {
    
        let page = <Page>args.object;
     
        page.bindingContext = viewmodel;
    }
    
    export function labelLoaded(args){
        var label = args.object;
        label.on("longPress", function (args: GestureEventData) {
            console.log(statedown)
            if(isIOS){
                if(statedown){
                    console.log("longPress");
                    console.log(args.eventName);
                    console.log(args.type);
                    statedown=false;
                }
                else{
                    statedown=true;
                }
            }
            
            
        });
        
    
    }
    

    longPress gesture does not have state or action property. For this case, you could use touch gesture, where you could handle the state while using its action property.

    label.on(GestureTypes.touch, function (args: TouchGestureEventData) {
            console.log("Touch: x: " + args.getX() + " y: " + args.getY());
            console.log(args.action)
        });
    
  2. NordlingDev commented on Feb 7, 2017

    @NordlingDev
    Author

    @tsonevn - Thanks for confirming issue. I have applied a custom flag as a temporary work around.

  3. NathanaelA commented on Feb 8, 2017

    @NathanaelA
  4. terreb commented on Aug 17, 2017

    @terreb

    Having the same, any updates?

  5. tsonevn commented on Aug 21, 2017

    @tsonevn
    Contributor

    Hi @terreb,
    This is still a valid issue for iOS. Regarding that, this problem is still under review and I could not commit to the exact time, where it would be fixed. You could keep track on the issue for further info and in the meantime, you could use the above-given workaround.

  6. terreb commented on Aug 21, 2017

    @terreb

    @tsonevn, ok thank you.

  7. two-bridges commented on Oct 30, 2017

    @two-bridges
    Sponsor

    TNS 3.2.1, iOS

    Having the same, any updates?

  8. tsonevn commented on Feb 7, 2018

    @tsonevn
    Contributor

    Base on the iOS documentation, we could check the state of the gesture and to allow executing our functionality only on long press ended.

    In the meantime, we could workaround this case as follow:

    <Label textWrap="true" text="Play with NativeScript!"v backgroundColor="green" height="200"
    		 class="h2 description-label" loaded="labelLoaded"/>
    
    import { GestureTypes,  GestureEventData } from "tns-core-modules/ui/gestures";
    abelLoaded(args) {
            console.log("add gesture- label: " + NgZone.isInAngularZone());
            let label: Label = <Label>args.object;
            label.on(GestureTypes.longPress, (args: GestureEventData) => {
                if (args.ios.state !== 3)
                    return;
    
                console.log("long press");
              
            });
        }
    
  9. tsonevn commented on Jul 30, 2018

    @tsonevn
    Contributor

    reproducible with modules 4.1

  10. erkanarslan commented on Aug 27, 2018

    @erkanarslan

    This is not a bug but a feature of iOS I guess. We should just check the state on iOS. Should this issue still be opened?

  11. shaedrich commented on Aug 27, 2018

    @shaedrich

    Can you explain why triggering a method can be a feature?

  12. erkanarslan commented on Aug 27, 2018

    @erkanarslan

    They implemented states into event. You can track when it starts, continues and ends. That means it is clearly something intended. Not a bug. Maybe you can use this to drag something around. It would be handy if you could track that.

  13. mudlabs commented on Jul 25, 2019

    @mudlabs
    Contributor
    // Assume platform is iOS
    exports.onLongPress = args => {
        switch(args.ios.state) {
            case UIGestureRecognizerStateBegan: // 1
                // The long press event has begun.
                break;
            case UIGestureRecognizerStateChanged: // 2
                // The long press event has changed.
                break;
            case UIGestureRecognizerStateEnded: // 3
                // The long press event has ended.
                break;
        }
    }
  14. farfromrefug commented on Sep 27, 2019

    @farfromrefug
    Collaborator

    A good thing would be to return the state directly in the gesture event and in the ios object. It is the case for some gesture events but not all.

  15. fgutteridge commented on Jan 2, 2020

    @fgutteridge

    Hey @NickIliev...

    Just ran in to this issue myself ({N}6.3), and while the solution provided above (manually checking the UIGestureRecognizer's state) works, I wondered if this will be fixed in upcoming releases of NS...

    These are the sorts of things that (I feel) are holding NativeScript back––weird, inconsistent behaviour across versions, platforms, etc. (though they are also the hardest to perfect, of course)

    Thanks for your help, @tsonevn and @NickIliev!

  16. NickIliev commented on Jan 3, 2020

    @NickIliev
    Contributor

    @farfromrefug @fgutteridge I've opened this PR which is proving the state as an argument for longPress event on iOS (via GestureEventDataWithState interface).

    Example:

    export function testLongPress(args: GestureEventDataWithState) {
        console.log(`LongPress fired!`);
        console.log(`>>> args.state ${args.state}`);
    }
    

    Note: As Android doesn't support states I've made it so it would always return state 1 when the long press is triggered on Android

  17. fgutteridge commented on Jan 3, 2020

    @fgutteridge

    Looks great, @NickIliev! Thanks so much for your help. Yes, having the longPress event exposed statefully (for iOS at least) makes the most sense.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions