MR.Gestures handles ALL touch gestures

1457910

Posts

  • DanielKramerDanielKramer Daniel Kramer USMember

    Let me give some more info cuz I'm stumped. Here's my tileBoard:

    namespace Upwords
    {
        public class TileBoard : MR.Gestures.AbsoluteLayout 
        {
    
            public Tile currentTile;
    
            public TileBoard ()
            {
    
                Panning +=  (object sender, MR.Gestures.PanEventArgs e) => {                
    
                    if(currentTile != null) {
                        currentTile.TranslationX = e.Touches[0].X - currentTile.Width/2;
                        currentTile.TranslationY = e.Touches[0].Y - currentTile.Height/2;
                    }
                };
    
            }
        }
    }
    

    Here's a tile that goes in it (a stripped down ver with relevant parts):

    namespace Upwords
    {
        public class Tile : MR.Gestures.Grid
        {
            private string letter = "Qu";
            public int size = 50;
    
            public Tile ()
            {
    
                VerticalOptions = LayoutOptions.CenterAndExpand;
                HorizontalOptions = LayoutOptions.CenterAndExpand;
                WidthRequest = size;
                HeightRequest = size;
    
                //Add Letter
                letterLabel = new Label {
                    TextColor = Color.Black,
                    FontFamily = "Helvetica",
                    FontAttributes = FontAttributes.Bold,
                    FontSize = Math.Round( WidthRequest * .5),
                    HorizontalTextAlignment = TextAlignment.Center,
                    VerticalTextAlignment = TextAlignment.Center,
                };
    
                letterLabel.BindingContext = this;
                letterLabel.SetBinding (Label.TextProperty, "Letter");
                Children.Add (letterLabel);
    
                //Tile touched
                Down += (object sender, MR.Gestures.DownUpEventArgs e) => {
    
                    WidthRequest = size*1.2;
                    HeightRequest = size*1.2;                   
    
                    int offset = (int)Math.Round((size*1.2-size)/2);
    
                    TranslationX += e.Touches[0].X - Width/2 - offset;
                    TranslationY += e.Touches[0].Y - Height/2 - offset;
    
                    ((TileBoard)Parent).currentTile = this;
                    ((TileBoard)Parent).RaiseChild(this);
    
                };
    
                //Tile Released
                Up += (object sender, MR.Gestures.DownUpEventArgs e) => {
    
                    WidthRequest = size;
                    HeightRequest = size;
    
                    ((TileBoard)Parent).currentTile = null;
    
                };
    
    
            }
    
            //Bindable Properties
            public string Letter {
                get { return letter; }
                set {
                    if (value == letter) {
                        return;
                    }
                    letter = value;
                    OnPropertyChanged ("Letter");
                }
            }   
        }
    }
    

    Now I add these to my content page and I can touch a tile which scales it up and pan it around:

    namespace Upwords
    {
        public class GamePage : ContentPage
        {
    
            public MasterDetailPage master;
    
            public GamePage ()
            {
    
                NavigationPage.SetHasNavigationBar(this, false);    
                BackgroundColor = AppStyle.BoardColor;
    
                Tile tile1 =  new Tile();
                tile1.Letter = "R";
                tile1.TranslationX = 100;
                tile1.TranslationY = 100;
    
                TileBoard tileBoard = new TileBoard ();
                tileBoard.Children.Insert(0, tile1);
    
            //Setting Content directly to tileBoard works.. I can touch and move my tiles around
            Content = tileBoard;
    
    
            //If I nest my tileboard under a stacklayout I no longer receive gestures on my tiles or tileboard
                MR.Gestures.StackLayout topStack = new MR.Gestures.StackLayout () {
                    Children = { tileBoard },
                };
                Content = topStack;
    
            }
    
    
        }
    }
    

    If you look at the last class GamePage, you'll see at the bottom if I set my Content to tileboard I get gestures for my tiles and tilelboard.. if I nest that under a stack layout I no longer get gestures to those children. Any ideas?

  • MichaelRumplerMichaelRumpler Michael Rumpler ATMember ✭✭✭✭

    @AntoineElDaher said:
    Hi @MichaelRumpler

    Any thought on when you can get a fix in for this?

    System.NullReferenceExceptionObject reference not set to an instance of an object
    Xamarin.Forms.BindableObject.GetValue(BindableProperty property)
    MR.Gestures.AbsoluteLayout.get_TappedCommandParameter()

    If there is a NullReferenceException in Xamarin.Forms.BindableObject.GetValue then I cannot fix this. Xamarin has to fix the bug. Did you already file it on bugzilla?

    I added some try/catch code around the calls to all the CommandParameters as a workaround. But I cannot do this for everything I call in XF. So there will come the time where I won't do this anymore.

    The workaround is in the next version. I'll try to release it as soon as I get the time.

  • MichaelRumplerMichaelRumpler Michael Rumpler ATMember ✭✭✭✭

    @DanielKramer
    I always try not to consume any gestures so that other elements which also handle them can still work. So when you have two layouts within each other, both should receive the gestures. Unfortunately sometimes this does not work. This depends on the platform and also on the contained elements.

    If you don't need any gesture handling on your topStack, you can try using a Xamarin.Forms.StackLayout instead.
    Sometimes you have to handle the gestures on a parent container and check if the touch coordinates are on a child element.

  • TonyDTonyD Antoine El Daher USMember ✭✭✭

    OK thanks @MichaelRumpler - please let me know when you release the workaround. I will file a bug against Xamarin but it will probably take a long time for them to fix it since it's hard to repro.

  • MichaelRumplerMichaelRumpler Michael Rumpler ATMember ✭✭✭✭

    @AntoineElDaher

    I released MR.Gestures 1.3.3.

    This version adds try/catch around every time I read the *Command and *CommandParameter properties. I cannot reproduce those problems. I hope it helps.

  • TonyDTonyD Antoine El Daher USMember ✭✭✭

    Thanks @MichaelRumpler I will include this in next week's release and will see if the crash disappears as expected!

  • TonyDTonyD Antoine El Daher USMember ✭✭✭

    @MichaelRumpler - no more crashes since I updated to MR.Gestures 1.3.3, thanks!

  • TonyDTonyD Antoine El Daher USMember ✭✭✭

    Hi @MichaelRumpler

    I'm having some trouble getting panning to work smoothly.

    In particular, if you're changing the TranslationX variable in response to the panning event, there will be some jumpiness.

    e.g. BoxView.Panning += BoxView.TranslationX = e.TotalDistance.X;

    I've tried to offset e.TotalDistance by the current BoxView.TranslationX and it is better but it it still jumpy.

    Is there a way for e.TotalDistance to actually refer to the point at which the panning started (even if the view was translated in the process)? It gets even worse if rotations are involved.

  • MichaelRumplerMichaelRumpler Michael Rumpler ATMember ✭✭✭✭
  • JohnEeckhoutJohnEeckhout John Eeckhout USMember
    edited May 2016

    Is there a way to prevent the events from firing on elements behind the element that you are pressing?

    When I use the built in TapGestureRecognizer on my controls it only fires on the top element (which is good).
    But when I replace it with TappedCommand it will also press the button behind my view.

    This is a problem for example with popups.

  • MichaelRumplerMichaelRumpler Michael Rumpler ATMember ✭✭✭✭

    @JohnEeckhout This has been asked several times in this thread.
    See comments 178475 and 195113 for example.

  • JohnEeckhoutJohnEeckhout John Eeckhout USMember

    @MichaelRumpler
    Thanks & sorry!

  • MaximTkMaximTk Maxim Tkachenko USMember ✭✭

    @MichaelRumpler I'm using your lib and I have a lot of reports about crashes from Insights. It happens on Android (basically on 5.1). I'm using MR.Gesturest v1.2.4.

    System.NotSupportedExceptionUnable to activate instance of type MR.Gestures.Android.SimpleGestureListener from native handle 0xbe869e5c (key_handle 0x3ef88aef).
    
      at Java.Interop.TypeManager.CreateInstance (IntPtr handle, JniHandleOwnership transfer, System.Type targetType) [0x001a4] in <filename unknown>:0 
      at Java.Lang.Object.GetObject (IntPtr handle, JniHandleOwnership transfer, System.Type type) [0x000e5] in <filename unknown>:0 
      at Java.Lang.Object._GetObject[T] (IntPtr handle, JniHandleOwnership transfer) [0x0001a] in <filename unknown>:0 
      at Java.Lang.Object.GetObject[T] (IntPtr handle, JniHandleOwnership transfer) [0x00000] in <filename unknown>:0 
      at Java.Lang.Object.GetObject[T] (IntPtr jnienv, IntPtr handle, JniHandleOwnership transfer) [0x00006] in <filename unknown>:0 
      at Android.Views.GestureDetector+SimpleOnGestureListener.n_OnLongPress_Landroid_view_MotionEvent_ (IntPtr jnienv, IntPtr native__this, IntPtr native_e) [0x00000] in <filename unknown>:0 
      at (wrapper dynamic-method) System.Object:fbc721f1-fe58-46dc-9524-49f14c36235e (intptr,intptr,intptr)
    
    System.MissingMethodExceptionNo constructor found for MR.Gestures.Android.SimpleGestureListener::.ctor(System.IntPtr, Android.Runtime.JniHandleOwnership)
    
      at Java.Interop.TypeManager.CreateProxy (System.Type type, IntPtr handle, JniHandleOwnership transfer) [0x00058] in <filename unknown>:0 
      at Java.Interop.TypeManager.CreateInstance (IntPtr handle, JniHandleOwnership transfer, System.Type targetType) [0x0012c] in <filename unknown>:0 
    
    Java.Lang.ErrorException of type 'Java.Interop.JavaLocationException' was thrown.
    
    Java.Lang.Error: Exception of type 'Java.Lang.Error' was thrown.
    
      --- End of managed exception stack trace ---
    java.lang.Error: Java callstack:
        at md5cf4b09d0afe9b09f8458554395119d93.SimpleGestureListener.n_onLongPress(Native Method)
        at md5cf4b09d0afe9b09f8458554395119d93.SimpleGestureListener.onLongPress(SimpleGestureListener.java:57)
        at android.view.GestureDetector.dispatchLongPress(GestureDetector.java:700)
        at android.view.GestureDetector.access$200(GestureDetector.java:40)
        at android.view.GestureDetector$GestureHandler.handleMessage(GestureDetector.java:273)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:145)
        at android.app.ActivityThread.main(ActivityThread.java:6872)
        at java.lang.reflect.Method.invoke(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:372)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1404)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1199)
    
  • MichaelRumplerMichaelRumpler Michael Rumpler ATMember ✭✭✭✭

    @MaximTk
    A lot has been talked about this bug already in the bugs 27408 and 39189.
    According to Jason Smith in this comment on bug 39189 and Jonathan Pryor's comment on his own answer on SO we should not simply add that constructor cause it would hide the real bug and just cause others.

    However, I also found that Xamarin did add that constructor themselves to some classes in XF. I found this comment in the InnerGestureListener:

    // This is needed because GestureRecognizer callbacks can be delayed several hundred milliseconds
    // which can result in the need to resurect this object if it has already been disposed. We dispose
    // eagerly to allow easier garbage collection of the renderer
    internal InnerGestureListener(IntPtr handle, JniHandleOwnership ownership) : base(handle, ownership)
    

    So I added that constructor to all my gesture listeners as well.

    I released MR.Gestures 1.3.4 with this change. Please test that version as I cannot reproduce it.

  • TonyDTonyD Antoine El Daher USMember ✭✭✭

    Hi @MichaelRumpler

    We have an app with 1.3.3/1.3.4 live for the past few weeks and users are complaining that swipe doesn't work very well. I am able to reproduce it pretty easily by swiping quickly.

    I get Direction = NotClear even though it's clearly a left or right swipe. If I do a slow/normal swipe it works fine.

    I tried to check e.Center but it seems it is the place where the swipe started, not ended.

    Any ideas?

  • TonyDTonyD Antoine El Daher USMember ✭✭✭

    I did some debugging and even if
    DeltaX = 200
    DeltaY = ~40

    It shows up as UnClear. Is there a way to configure the ratio for "clearness"?

  • MichaelRumplerMichaelRumpler Michael Rumpler ATMember ✭✭✭✭

    @TonyD

    You can adjust the platform dependant Settings.SwipeVelocityThreshold.

    MR.Gestures.Android.Settings.SwipeVelocityThreshold

    The velocity of a lifted finger relative to the ScaledMaximumFlingVelocity must be at least this value to count as Swipe.
    The default value is 0.1. Set it to a higher value if you want the user to move faster.

    MR.Gestures.iOS.Settings.SwipeVelocityThreshold

    The velocity (UIPanGestureRecognizer.VelocityInView) of a lifted finger in X or Y direction must be at least this value to count as Swipe.
    The default value is 800/800. Set it to a higher value if you want the user to move faster.

    WinRT and UWP:

    The velocity of a lifted finger must be at least this value to count as Swipe.
    The velocity comes from ManipulationCompletedRoutedEventArgs.Velocities.Linear and is in device-independent pixel per millisecond.
    The default value is 1. Set it to a higher value if you want the user to move faster.

    But be careful there. A direction will only be set, if the horizontal OR vertical velocity are high enough. If both directions are too high, then NotClear will be set.

    Alternately you could handle Panning and Panned instead of Swiped. In the PanEventArgs you get the DeltaDistance and Velocity and can check the direction yourself.

  • AlanSpiresAlanSpires Alan Spires USBeta ✭✭

    When inheriting from MR.Gestures.ListView gestures no longer work.

    public class MyListView : MR.Gestures.ListView etc....

  • huangjinshehuangjinshe Mike M USMember ✭✭✭
          <mr:ListView Margin="0,10,0,0" ItemsSource="{Binding ProductList}" LongPressedCommand="{Binding GoProductLongCommand}" LongPressedCommand="{Bindnig }"  TappedCommand="{Binding GoProductCommand}"  TappedCommandParameter="{Binding }">
                      <mr:ListView.ItemTemplate>
                        <DataTemplate>
                          <ViewCell>
                            <Grid Padding="5, 10, 5, 10" HorizontalOptions="FillAndExpand">
                              <Label Text="{Binding ProductName}" HorizontalOptions="StartAndExpand" />
                            </Grid>
                          </ViewCell>
                        </DataTemplate>
                      </mr:ListView.ItemTemplate>
                    </mr:ListView>
    

    What I want is, when selected some item, fire it for short tapped or long tapped. But use this code it has only fired long pressed command, not tapped command. why?

    It also not get the current selected item model for the command parameter, How do I put the current selected item context for the parameter?

    My last question is, Looks like your library need to pay. If I don't sure my app name, could I change the app name and continue use your library in the future?(some are looks like even has multiple app name for different language, I also don't know how to do for this)

  • JohnEeckhoutJohnEeckhout John Eeckhout USMember

    Would it be possible to make the gestures not fire when inputtransparent is true?
    I have had quite few problems when using MR.gestures with any sort of popup so I have tried to set the inputtransparent to true for all the elements behind my popup. This works for WindowsRT but not for Android (don't know about iOS). It would be a shame if I had to drop MR.gestures because of this.

  • MaximTkMaximTk Maxim Tkachenko USMember ✭✭

    MichaelRumpler said:
    I released MR.Gestures 1.3.4 with this change. Please test that version as I cannot reproduce it.

    @MichaelRumpler, after updating to ver 1.3.4 LongPressing event doesn't fire (on android). So I can't to test it.

  • MichaelRumplerMichaelRumpler Michael Rumpler ATMember ✭✭✭✭

    I updated the GestureSample

    • MR.Gestures to 1.3.4
    • Xamarin.Forms to 2.3.0.49

    and added a CustomListView in GestureSample/Views/Tests.

    @AlanSpires See the CustomListView. This inherits from MR.Gestures.ListView and it works.
    @AhsanHayat The same sample shows you how you can use RecycleElement in a custom ListView.
    @MaximTk In that sample LongPressing still works in 1.3.4 on Android.

    @huangjinshe A long press is no tap. It raises either one or the other depending how long you leave your finger on the screen. You also have your binding to the TappedCommandParameter wrong. "{Binding }" binds to the ViewModel of the whole page. To get the currently selected item, just use the lists SelectedItem property. If you want to sell your app under multiple names, then you also need multiple licences for MR.Gestures.

    @JohnEeckhout Thats a good idea, but unfortunately now it would be a breaking change which I'd rather avoid. How about you check the InputTransparent property in your gesture handler?

  • huangjinshehuangjinshe Mike M USMember ✭✭✭

    @MichaelRumpler said:
    I updated the GestureSample

    • MR.Gestures to 1.3.4
    • Xamarin.Forms to 2.3.0.49

    and added a CustomListView in GestureSample/Views/Tests.

    @AlanSpires See the CustomListView. This inherits from MR.Gestures.ListView and it works.
    @AhsanHayat The same sample shows you how you can use RecycleElement in a custom ListView.
    @MaximTk In that sample LongPressing still works in 1.3.4 on Android.

    @huangjinshe A long press is no tap. It raises either one or the other depending how long you leave your finger on the screen. You also have your binding to the TappedCommandParameter wrong. "{Binding }" binds to the ViewModel of the whole page. To get the currently selected item, just use the lists SelectedItem property. If you want to sell your app under multiple names, then you also need multiple licences for MR.Gestures.

    @JohnEeckhout Thats a good idea, but unfortunately now it would be a breaking change which I'd rather avoid. How about you check the InputTransparent property in your gesture handler?

    Why don't you just detect it if bind short and long command both? and then if all bind, raise it when time short or long?

  • MichaelRumplerMichaelRumpler Michael Rumpler ATMember ✭✭✭✭

    @huangjinshe said:
    Why don't you just detect it if bind short and long command both? and then if all bind, raise it when time short or long?

    I do that.
    Start at the beginning. Read the MR.Gestures website and look at the code from the GestureSample.

  • MaximTkMaximTk Maxim Tkachenko USMember ✭✭

    @MichaelRumpler, you didn't add CustomListView to repository

  • MichaelRumplerMichaelRumpler Michael Rumpler ATMember ✭✭✭✭

    @MaximTk Oops, sorry about that. It's up now.

  • MaximTkMaximTk Maxim Tkachenko USMember ✭✭
    edited July 2016

    @MichaelRumpler, in your CustomListView example LongPressing and LongPressed events only fires if you drag your fingers a litle bit while pressing.

  • LasseMadsenLasseMadsen Lasse Madsen USMember ✭✭

    Hey @MichaelRumpler
    I have some problems using MR.Gestures with Xamarin.Forms 2.3.0.107, as the tapped events somehow is not called on Android.
    I need to use 2.3.0.107, as I am using UWP.
    Do you have a workaround for this?

  • MichaelRumplerMichaelRumpler Michael Rumpler ATMember ✭✭✭✭

    @LasseMadsen Did you buy a license?

  • LasseMadsenLasseMadsen Lasse Madsen USMember ✭✭
  • MichaelRumplerMichaelRumpler Michael Rumpler ATMember ✭✭✭✭

    @LasseMadsen

    I updated the GestureSample from 2.3.0.49 to 2.3.1.111. With both versions Tapped works as expected.

    Usually Tapped is only raised after Tapping if NumberOfTaps was 1. Therefore it is never raised without a LicenseKey, because then NumberOfTaps remains 0.

    Can you try if Tapping is raised? Can you show your code?

  • MichaelRumplerMichaelRumpler Michael Rumpler ATMember ✭✭✭✭

    @MaximTk said:
    @MichaelRumpler, in your CustomListView example LongPressing and LongPressed events only fires if you drag your fingers a litle bit while pressing.

    I could not reproduce this on my usual test device - a Nexus 10. However, I could reproduce it on my Sony Xperia Z5 Compact. Give me some time to look into it.

  • RodrigoEliasRodrigoElias Rodrigo Elias USMember

    Hey pals. I need some assistance here. :smile:

    What's the deal with ListView on Android?
    The SelectedItem is not firing!

    I've extended MR.Gesture.Android.Renderers.FrameRenderer and watched the return for DispatchTouchEvent method.
    It always returns true, even if Mr.Gesture.GesturesHandler are all false.

    Is this behavior expected? Where can I find the documentation?

    Thanks!

  • MichaelRumplerMichaelRumpler Michael Rumpler ATMember ✭✭✭✭

    @RodrigoElias This is caused by this bug. When you handle touch events on a cell, then SelectedItem does not work.
    But give them some time. The bug is only 7 months old. They should look at it soon.

  • NathanMNathanM Nathan M. AUMember

    Hi @MichaelRumpler, I am having a problem where Panning (and possibly other) events are still triggering after a Page's OnDisappearing event has been triggered. Is it possible to stop this from happening?

    Thanks.

  • MichaelRumplerMichaelRumpler Michael Rumpler ATMember ✭✭✭✭

    @NathanM
    When a new page is pushed into view, then the old remains. It's just overlapped by the new page. Unfortunately some native gesture handlers don't check whether the controls they are attached to are still visible. I already worked around this for TabbedPage and CarouselPage. I will check the CarouselView once it is merged to the main Xamarin.Forms.dll.
    Please send me your code so that I can check why this happens for you and if I can introduce a workaround there too.

  • MichaelRumplerMichaelRumpler Michael Rumpler ATMember ✭✭✭✭

    I just released MR.Gestures 1.3.5.

    This should fix the bug @MaximTk reported that LongPressing and LongPressed are not always raised on Android.

  • JimmiBendtsonJimmiBendtson Jimmi Bendtson USMember ✭✭

    For various reasons I need to change the name of my app slightly on iOS compared to the Windows and Android versions. How does the licensing system support this? Have you considered changing from name and instead base the license on application ID?

  • MichaelRumplerMichaelRumpler Michael Rumpler ATMember ✭✭✭✭

    @JimmiBendtson
    MR.Gestures is licensed per app name. Like I already wrote on http://www.mrgestures.com/#Buy

    I.e. if your app has the same name on all three platforms, you only need one license key. If you have different versions of your app (e.g. a free and a pro one) with different names, then you need a separate key for each version.

    If you want to use two different app names, then you need to buy two licenses.

  • AlessioIafrateAlessioIafrate Alessio Iafrate ITMember

    Hi,
    i have buy the license of this beautiful control but i have a problem, i have two image one above the other with ontap event.
    I wanna receive the event only on the top image, how can i do that?

Sign In or Register to comment.