Very cool, thanks for sharing.
Thank you Bruce.
This is a pretty cool idea. Do you have any more explanation on how you are triggering the layout change on rotation?
Steve is the one who developed the technique.
My only part in this was complimenting him.
You are correct, sorry about that
Do you have any more explanation on how you are triggering the layout change on rotation?
I actually never went so as far to make the demo file change layouts -- I just triggered a script that used a SetField script step, but, presumably, one could change layouts or do any variety of desired tasks in the triggered script.
If you enjoy pulling things apart to see how they work, most of the code that illustrates what is going on can be found in the last layout of the demo file: Inspect the webviewer object (upper right corner of layout) and check out the calculation used to define the source for the webviewer.
Below I'll list the gory details regarding what I tried, what worked, what didn't work, and what I wound up doing to make the demo file. Please feel free to let me know if there's something that needs clarification, or if I leave something unanswered. It is a lot of information, but not knowing which dots would be most helpful for me to connect, I'm trying sketch out most of the points that went into coming up with the demo.
Hope you enjoy.
Introduction to how this technique works:
Each layout that responds to device rotation needs to have a small webviewer object on it.
The webviewer will take up some space, and it will take up more layout real estate when the device is in an orientation which causes the webviewer object to stretch. We cause the webviewer to stretch/shrink by anchoring it on two opposing sides.
This stretching of the webviewer object, along with the fact that it is 'visible', is key to how this technique works. (I say 'visible' in quotes, because we set the color of the text in the webviewer to match the background color, which, in turn, should be set to match the background color of the containing object, so that the webviewer does not appear to be visible.)
I think of webviewers in FM Go as having three states:
- Awake and in focus
- Not in focus, but still 'awake', i.e. not asleep
- Asleep - where the webviewer 'freezes' its display, and the little circular arrow appears in the upper corner
For the purposes of this technique, we can generalize to two states: Awake (regardless of focus), and Asleep.
Discovery which motivated this idea:
While I was playing around one day, I discovered that an asleep webviewer object wakes up if it is resized. This actually even seemed to hold true if the webviewer was to the right of the layout edge.
This discovery was the motivation for pursuing this technique:
- We put a webviewer on the layout which will resize when the device is rotated.
What this means is that we have successfully managed to trigger an FM script for the case where our webviewer is 'asleep'.
At this point, we need to figure out how to trigger the FM script in the case where the webviewer is still awake.
Trying to solve the case where the webviewer is still awake - dual webviewer:
This did not work:
( Examples of events would be something like the user pressing/clicking somewhere, a field receiving focus, etc.)
This did not work: onorientationchange
My first attempt to detect a change of orientation was what appeared to be most direct and obvious:
There is an event called 'onorientationchange' which can be listened for on an iOS device.
I thought for sure that I would be able to set up an Event Listener to listen for and respond to this event. It didn't work. At the time, I did not know why -- I tried using different methodologies for setting up the Event Listener for this event, but no luck.
I've since seen a forum post which seems to explain this:
This did work: onresize
I discovered that, in order for this to work, I had to actually have some 'visible' page content displaying in the webviewer. I chose to use a small amount of text with color matching the background of the webviewer object so as to be 'visible' with respect to the webviewer, though not visible to the eye. This requirement of visibility also meant that I could no longer place the webviewer offscreen, i.e. to the right of the layout edge -- the webviewer had to be positioned on the layout, and of sufficient size, such that its content would be present. Without both of these requirements being met, the resize event did not seem to trigger upon device rotation. Presumably, the webviewer is smart enough to recognize that, without displayed content, no resize is necessary when the device orientation changes.
At this point, we are able to trigger an FM script based on device rotation for both of our webviewer cases defined above: Awake, Asleep.
Mitigating dual invocations of the target script:
The last item to clean up was the fact that the target script was generally being called two times in a row for every orientation change of the device.
I worked on this for a while, first seeing if I could utilize only the onresize event to detect device rotation, but the onresize event alone was not sufficient to catch all rotations.
-- That's pretty much everything. Below are just a few extra references and elaborations --
document.location = varFmUrlValue;
where: varFmUrlValue is the well-formed FMP URL that references our target script.
The references I include below should tell you everything you might need to know about proper construction of the FMP URL.
In my demo file, I use the following snippet of code to launch the URL:
"document.location = 'fmp://$/" & GetAsURLEncoded( Get( FileName ) ) & ".fmp12?script=" & GetAsURLEncoded ( callbackScript ) & "¶m=' + varParam;¶"
callbackScript is defined earlier within the first part of the encosing Let function where the above snippet occurs. Its value is the name of the FM script to be invoked.
* Regarding storing state data in a webviewer:
References for FMP URL protocol, especially combined with a webviewer:
Thank you for the details, Steve.
Very helpful, I was able to play around and trigger a layout change. Worked as expceted.