Thanks again for providing the screen shots. They're especially useful for understanding the full scope of options for handling your app's layout.
We have two general approaches for adapting our layouts to work well on the wide range of today's mobile devices, FullScreenMode and Responsive Design.
At the moment our community is at a disadvantage, because we have a good tutorial on using FullScreenMode, but none of all for using common Responsive Design principles in LiveCode.
Here's the link to the Lesson on fullScreenMode:
http://lessons.livecode.com/m/15262/l/5 ... ll-devices
I've requested access to the proprietary tool used to produce the Lessons so I can add one about Responsive Design. In the meantime, here are some notes which can help you get started evaluating which is the best option for your app:
A Brief Introduction to Responsive Design in LiveCode
Understanding the Challenge and the Options
FullScreenMode is by far the easiest to implement, and the one that's been more practical to use for longer within LiveCode.
Responsive Design is by far the most commonly used by both native and web app designers, though like anything else in a scripting language it will require some scripting to use.
Let's first step back and consider the problem, and then we can evaluate how each option applies.
Modern screens come in a wide range of sizes and ratios, and support two orientations. And because mobile screens are much smaller than the ones we enjoy on the desktop, we want to think about things carefully to make the best use of every pixel.
If you make a fixed layout for a 4" phone in portrait orientation, running it on a full-size tablet will take those buttons you've lovingly arranged to be a comfortable fit for a finger and enlarge them to the size of a fist. And if you rotate the orientation of the device, there will be empty space on either size, and the top and bottom of your layout will be beyond the edges of the display. And even in other devices of similar size and also in portrait mode, a different ratio can still produce some padding and/or cropping.
FullScreenMode makes short work of allowing your app's layout to scale to fit the target device by automating one of several combinations of cropping, padding, shrinking, and/or stretching effects, or some combination of those depending on the mode chosen.
For some apps it's a truly optimal choice, esp. some types of games where only one orientation is allowed, there are no standard controls so scalling looks good, and meaningful content is limited to the center of the screen, so padding/cropping pose no impairment at all. The great game Monument Valley is a shining example of this, looking gorgeous on small phones and big tablets alike, at ratios from 3x4 to 9x16 and everything in between.
Responsive Design places screen elements in specific locations based on screen dimensions, usually relative to the edges of the screen or other objects so placement adjusts itself automatically to fit any dimensions, ratios, or orientations.
Responsive Design can even support different layouts at different sizes, such as exposing more controls on a tablet while having those tucked away in a flyout panel on a smaller device.
You'll find examples of Responsive Design in most web sites, and most of the apps on your phone, including gMail, Facebook, YouTube, Amazon, and most others.
Putting Reponsive Design to Work
Let's take a look at Responsive Design in action:
I've taken the liberty of reproducing a mock-up of your app based on the screen shots. I chose the most complex layout, the one with the most controls, as a test case for how we might approach this.
What we see in your layout is a common design pattern: header at the top, footer at the bottom, and a content region in between. The header and footer are of a fixed height, and run full-bleed to the edges of the screen, and the content region is the space available in between them.
What we need is a way for our app to be notified when the screen dimensions change, either when the app is launched or when orientation is changed. The resizeStack message provides this notification.
Putting this to work to handle your layout requres only one line for each major region of your layout, header, content, and footer nav:
Code: Select all
on resizeStack x,y
put 60 into tRowSize
-- Header - fixed height, full bleed:
set the rect of btn "header" to 0,0,x, tRowSize
-- Content Region
set the rect of grp "ContentRegion" to 0, tRowSize, x, y-tRowSize
-- Footer - fixed height, full bleed:
set the rect of widget "NavBar" to 0,y-tRowSize,x,y
end resizeStack
The tricky part is usually the content region, and your layout is no exception. With more than a dozen controls, we don't want to hand-code the arithmetic for all those if we can avoid it.
Fortunately, LiveCode supports a resizeControl message for groups, which lets a group be self-contained in managing its contents. Using that message within a group simplifies the arithmetic tremendously, and also allows the group to be repurposed in other layouts while still preserving its clean interrior appearance.
If I were to limit the apps to work in portrait orientation only, I could just set the loc of the content region group to the loc of the card and be done with it.
But this exercise was too simple, so to make it more challenging I decided landscape mode should be an option.
I noticed the fields tend to fall into two conceptually-related categories, contact info and membership info. This lend itself nicely to putting each into its own group, so they could be placed side-by-side in landscape while stacked in portrait.
Here's the code for the "ContentRegion" group that handles that:
Code: Select all
on resizeControl
-- Allow the user to enjoy whichever orientation
-- they prefer with responsive design:
--
put item 1 of the loc of me into tMidX
put item 2 of the loc of me into tMidY
--
if the width of this cd < the height of this cd then
-- Portrait:
set the loc of grp "UserInfo" to \
tMidX, tMidY - (the formattedHeight of grp "UserInfo" div 2)
set the loc of grp "MembershipInfo" to \
tMidX, tMidY + (the formattedHeight of grp "MembershipInfo" div 2)
else
-- Landscape:
set the loc of grp "UserInfo" to \
tMidX - (the formattedWidth of grp "UserInfo" div 2), tMidY
set the loc of grp "MembershipInfo" to \
tMidX + (the formattedWidth of grp "MembershipInfo" div 2), tMidY
end if
--
end resizeControl
There we have it.
All in all, I spent just a few minutes dragging out the controls, and about half as much time writing the code to maintain their tidiness on every possible device type LiveCode supports.
Comments aside, in just 9 lines we can handle attractive placement on any device in any orientation.
Coupled with the three lines in the card script, we now have full bleed for the header and footer, attractive placement of the form fields and buttons, and this layout will adjust itself to fit every screen size, ratio, and orientation.
And that is indeed "every": one more advantage to Responsive Design is that you can see the results right in the IDE as you're working, reducing the number of build-load-test cycles needed just to see how things look. Just resize the window in the IDE and the layout updates itself as you go.
Here's the sample mock-up stack:
I hope this helps.
As with anything else in app design, we rarely need to reinvent wheels. Examine your app's layout, examine the apps like it made by others, and in most cases you can get something quite similar at least as easily in LiveCode.
Additional Notes and Historical Information
For some background on LiveCode's layout options, this post to the use-livecode mailing list earlier this month in a related discusion may be of interest:
http://lists.runrev.com/pipermail/use-l ... 59594.html
Graham Samuel wrote:
> Thanks Richard, for that typically useful reply! I have indeed written
> many a resize handler, but getting back into this stuff I was struck
> by how messy it can get. Right now I don’t even know if say a field
> with 12 point type in it has to be changed to a smaller or larger
> rectangle with smaller or larger type in it, but obviously as soon as
> I can start doing simulations (I have a totally different problem
> there!) I can experiment.
If it seems messy you may just be thinking about it too hard.
Geometry no longer differs as much between the IDE and the device as it used to.
In the first versions of LC's mobile offering, we didn't have resolution independence. Heck, in the fist versions we didn't even have a pixelDensity function. Back then, fullScreenMode was offered as a
quicky workaround because while it rarely produces apps that look exactly like the ones we most commonly use, it was easy to implement and easy to use. The alternative involved a lot of guesswork and tedious
arithmetic to try to figure out the difference between logical and physical pixels. Ugh.
Today, LC only uses logical pixels, and it automatically translates those to whatever physical pixels a given phone may be using.
Want to place a button 20 pixels from the bottom-right of the screen?
Just use the syntax you've been using for years:
on resizeStack x,y
set the bottomRight of btn 1 to x-20, y-20
end resizeStack
One nice thing about this approach is that you spend a LOT less time needing to move the stack to the device just to see what it'll look like. Just resize the stack in the IDE and look at it.
> I do like the idea of sending resizeControl to groups - I have used
> similar techniques for other purposes in the past. Powerful and
> encapsulated.
It's one of the most useful enhancements added to LiveCode, making so much about delivering pixel-perfect UIs on every platform so much easier.
> As to graphics, I can presumably start with the highest possible
> resolution and resize at startup according to the actual screen size,
> or do what I said before, have a little library of different versions
> tweaked for different screen sizes. Or possibly use SVG...
No matter which method you use for your layout, LC includes options for including referenced images of different resolutions. IIRC the manual covers that pretty well.
But if you can use SVG for the images you want you'll never need to think about multiple copies at all, and will always have a rendering optimized for the device you're running on.
> Well, I am trying to learn, and I am grateful for all that you’ve
> said.
They key to that long post is this line:
As with desktop software, I find it instructive to observe how the
best apps on mobile behave, and then - because those establish user
expectations - do what they do.
I haven't seen your app so I can't say with complete confidence whether explicit placement via resizeStack or automated approximation with fullScreenMode is the best fit for your particular needs.
Consider what your app needs to do, and study the apps on your phone that best reflect your design goals. Rotate the device, run the apps on your phone and your tablet, observe how the apps adapt their layouts to
make the best use of each screen size.
As we've been doing on the desktop all these years, we can often get results every bit as good as apps made with anything else, and usually more easily.
--
Richard Gaskin
Fourth World Systems