N.B. The info in this article applies only to FileMaker 13 and 14. The problems that I complain of here may disappear, indeed, I hope they will disappear, in a future maintenance update to FileMaker 14. This info is good as of 5-20-15, but if you're reading this months later, check to see if the problems haven't since been fixed.
Written a database solution in FileMaker 13 or 14 that you are deploying on iOS devices, and want to distinguish double-taps from single-taps? For example, would you like a single tap on a record in list view simply to select the record, while a double-tap selects the record and views it in form view? Me, too.
So the way you're supposed to be able to do this is pretty straightforward (although it involves a little arithmetic). FileMaker Pro provides the basic tools in a layout script trigger OnGestureTap and a function Get(TriggerGestureInfo). In layout mode, you enable the OnGestureTap script trigger for the layout, and configure it to trigger a script. Let's call the script "respond to tap". The key line in the script should look something like this:
Set Variable [ $gestureinfo ; Get(TriggerGestureInfo) ]
Set Variable [ $tapcount ; GetValue ( $gestureinfo ; 2 ) ]
The function returns, in a return-delimited list, five pieces of info, of which the second — the one we're interested in — tells you how many taps were recorded. If it's 2, you branch to what you want to do when user double-taps. If it's not 2, you do nothing or something else.
But it's not exactly a bug. It's a mistake, but not a bug. I was finally able to generate a double-tap. Not by doing what I expect my users to do, i.e. tapping twice fast with the same finger. I did it by tapping twice with two different fingers, as if I were playing 32nd notes on the piano.
So the OnGestureTap trigger works, kind of. It simply has way too narrow an event window for normal humans. Those engineers at FileMaker must really tap fast.
Written a database solution in FileMaker 13 or 14 that you are deploying on iOS devices, and want to distinguish double-taps from single-taps? For example, would you like a single tap on a record in list view simply to select the record, while a double-tap selects the record and views it in form view? Me, too.
So the way you're supposed to be able to do this is pretty straightforward (although it involves a little arithmetic). FileMaker Pro provides the basic tools in a layout script trigger OnGestureTap and a function Get(TriggerGestureInfo). In layout mode, you enable the OnGestureTap script trigger for the layout, and configure it to trigger a script. Let's call the script "respond to tap". The key line in the script should look something like this:
Set Variable [ $gestureinfo ; Get(TriggerGestureInfo) ]
Set Variable [ $tapcount ; GetValue ( $gestureinfo ; 2 ) ]
The function returns, in a return-delimited list, five pieces of info, of which the second — the one we're interested in — tells you how many taps were recorded. If it's 2, you branch to what you want to do when user double-taps. If it's not 2, you do nothing or something else.
Does it actually, you know, work?
Ah, but the problem is, it doesn't seem to work. When I first tried it myself, my script was triggered every single time by the first click, so the tap-count always returned 1. I asked the all-seeing, all-knowing Google for help and found that I was not alone in this experience.But it's not exactly a bug. It's a mistake, but not a bug. I was finally able to generate a double-tap. Not by doing what I expect my users to do, i.e. tapping twice fast with the same finger. I did it by tapping twice with two different fingers, as if I were playing 32nd notes on the piano.
So the OnGestureTap trigger works, kind of. It simply has way too narrow an event window for normal humans. Those engineers at FileMaker must really tap fast.
So where does that leave us?
I've written FileMaker Inc to complain that the event window for OnGestureTap is too short, and I reckon others have too. I assume that the engineers will sooner or later realize that they need to lengthen the event window that the OnGestureTap trigger responds to.
In the meantime? Well, you can create a workaround using a variables and the Get(CurrentTimeUTCMilliseconds) function. For this purpose, Get(CurrentTimeUTCMilliseconds) is basically like Get(CurrentTimestamp), just 1000 times more precise. Your script now looks something like this
Set Variable [ $$TAPTIME[2] ; Get(CurrentTimeUTCMilliseconds ) ]
Set Variable [ $timesincelasttap ; Case ( not IsEmpty ( $$TAPTIME[1] ) ; $$TAPTIME[2] - $$TAPTIME[1] ; "" ) ]
Set Variable [ $$TAPTIME[1] ; $$TAPTIME[2] ]
And then you'd do something in an if statement with the value in that variable $timesincelasttap, for example, if it's less than 500 (i.e. less than half a second), you regard it as a double-tap and respond accordingly. Note that I used a single variable with two reps: rep 1 for the tap that triggered this script last time, rep 2 for the current tap. You could use two different variables just as easily. Of course, variable for the previous tap needs to be a global variable so it sticks around for later reference. Oh, and don't use OnGestureTap with this, unless you're really trying to catch a double-tap anywhere on the layout. Instead, attach your script to a field or button that the user will be likely to tap.
Anyway, try it. It's a kludge but it works.
What record got tapped?
And I mentioned above that the OnGestureTap and Get(TriggerGestureInfo) tools are supposed to make it possible to tell when a user double-clicks on a record in a list, so you can do something like view that record in form view. But how do you do that, given that the OnGestureTap trigger is tied to the layout and not to a particular record or even to the body part? The answer is a bit depressing. And it involves arithmetic.
To make it easy, let's imagine that you've got a list layout that has no header or navigation part, nothing but a body part. So record 1 is displayed at the top of the screen. And say the body part is 100 pixels high. So the first record in the current found set the first 100 pixels at the top of the display, the second record occupies the next 100 pixels, and so on. The curious thing here is that these are virtual pixels that extend to the bottom of the list, not just to the bottom of the screen. So if you've got 500 records in the list, the last record occupies the last 100 pixels of a virtual area that is 500 x 100 pixels high. Anyway, just use GetValue ( Get ( TriggerGestureInfo ) ; 5 ) to get the y-coordinate or vertical pixel the user clicked on and do the math to figure out what record that must be. For example, if it's pixel 247, that would be record #3. Follow that up with a Go To Record [recordnumber] script step, and take it from there.
Why is this approach depressing? It's not because it involves arithmetic or because arithmetic is hard. It's because this script is going to break if you make even a minor adjustment to the size of the parts in your layout. So keep that in mind. I really wish that the OnGestureTap trigger could be attached to an element like a field or a button inside the body part, instead of being attached to the entire layout.
Keep in mind that if you attach an OnGestureTap trigger to a layout, you are now trapping for and responding to (or not responding to, which is itself a kind of response) every single tap on that layout, including all the benign taps like user clicking on button. I think this stuff worked better in HyperCard, where we could decide whether to pass a click through to the layer behind the initial object or not.
To make it easy, let's imagine that you've got a list layout that has no header or navigation part, nothing but a body part. So record 1 is displayed at the top of the screen. And say the body part is 100 pixels high. So the first record in the current found set the first 100 pixels at the top of the display, the second record occupies the next 100 pixels, and so on. The curious thing here is that these are virtual pixels that extend to the bottom of the list, not just to the bottom of the screen. So if you've got 500 records in the list, the last record occupies the last 100 pixels of a virtual area that is 500 x 100 pixels high. Anyway, just use GetValue ( Get ( TriggerGestureInfo ) ; 5 ) to get the y-coordinate or vertical pixel the user clicked on and do the math to figure out what record that must be. For example, if it's pixel 247, that would be record #3. Follow that up with a Go To Record [recordnumber] script step, and take it from there.
Why is this approach depressing? It's not because it involves arithmetic or because arithmetic is hard. It's because this script is going to break if you make even a minor adjustment to the size of the parts in your layout. So keep that in mind. I really wish that the OnGestureTap trigger could be attached to an element like a field or a button inside the body part, instead of being attached to the entire layout.
Etc
If you decide to use the kludge, you will quickly discover that there's one other problem, which is that this approach doesn't prevent other things from happening in response to a double tap. Specifically, a double tap is likely to zoom the display from 100% to 200% (or from whatever to whatever else). So you need to deal with that little problem. Can be done in a couple different ways and I leave it to you to figure them out.Keep in mind that if you attach an OnGestureTap trigger to a layout, you are now trapping for and responding to (or not responding to, which is itself a kind of response) every single tap on that layout, including all the benign taps like user clicking on button. I think this stuff worked better in HyperCard, where we could decide whether to pass a click through to the layer behind the initial object or not.
Comments
Post a Comment