How do I create a scalable UI using graphics?
Creating interfaces that grow / scale based on the size and aspect ratio of their container.
Introduction
In this lesson we look about building a UI using vector graphics that scales all assets and positions them according the device screen size and density.
By way of example, we will convert an app that was made for a small form factor mobile device (original iPhone) and make it scale for any device in any orientation.
Note: This lesson is taken from a seminar run at RunRevLive 2013 by Ben Beaumont, LiveCode product manager. As a result, it may not explain the concepts as clearly as other standard lessons.
SheepHerder Original
App made as a promo for how quickly mobile apps can be made with LiveCode
PRO
1) We made an app in a little over 3 hours
CON
1) The app only ran at 320x480 and didn't scale for different devices
2) The app was based entirely on images so making it scale for devices was not possible without exporting those images at a variety of resolutions
SheepHerder Vector
I then remade the SheepHerder app using only graphics.
PRO
1) Works at ANY screen resolution and aspect ratio.
2) The total source for the application is 89Kb.
CON
1) There is an overhead using graphics, particularly with effects like gradients because they have to be calculated when displayed.
2) Very rich applications may not suit this approach.
SheepHerder is a simple app that is perfectly suited to this method.
1) It doesn't have a complex layout so works on any aspect ratio.
2) It doesn't have any animated elements or visually rich elements.
3) It has a simplistic UI.
However, I use these principles in all the apps I write to varying degrees.
Preparation
Break the UI up into logical containers whose components are logically scaled and positioned based on the container. With SheepHerder I broke it up like this:
- Background
- Sheep
- Pit
- Footer
- Message Screen
Each is a group of objects.
Example Footer Group
1) Create a new stack
2a) Add a graphic
2b) Style it: I've added a gradient
3a) Add a button
3b) Style it: I've made it a round button with a blue background color
4) Group the objects
5) Set the group margins to 0
NOTE: Margin 0.
- Whenever working with groups as containers it's best to set the margins to 0. It makes calculating the position of components much easier.
ResizeControl message
1) A group receives a resize control message whenever it changes size.
2) We can use this message to resize and reposition all the controls in the group.
Example Script - Scale and position the background.
on resizecontrol
set the rect of graphic 1 of me to the rect of me
end resizecontrol
NOTE: "of me".
- When working with groups we use the "of me" syntax which ensures the script acts on the object in the group rather than an similarly named object.
Example Script - Scale and position the button.
on resizecontrol
lock screen
// Background
set the rect of graphic 1 of me to the rect of me
// Background
set the width of button 1 of me to the width of me * 0.4
set the height of button 1 of me to height of me * 0.65
set the loc of button 1 of me to the loc of me
unlock screen
end resizecontrol
NOTE: "lock screen" when resizing multiple objects.
- To avoid flickers as objects resize and move, surround the code with "lock/unlock screen".
NOTE: % scaling applied by setting width/height of objects to a scale factor of width/height of group.
ResizeStack
1) Once you have created your scalable components your can turn your attention to scaling and positioning them in the context of a full app.
2) When a stack changes size, a "resizeStack" message is sent to the stack.
Example script - Position the footer
1) Name the group "footer"
2) Position the group in the "resizeStack" handler in the stack script
on resizeStack
lock screen
// FOOTER
set the width of group "footer" to the width of me
set the left of group "footer" to 0
set the bottom of group "footer" to the height of me
unlock screen
end resizeStack
Example script - Position and scale the footer
on resizeStack
lock screen
// FOOTER
set the height of group "footer" to the height of me * 0.15
set the width of group "footer" to the width of me
set the left of group "footer" to 0
set the bottom of group "footer" to the height of me
unlock screen
end resizeStack
Example Script - Scale the button text size
on resizecontrol
lock screen
// Background
set the rect of graphic 1 of me to the rect of me
// Button Size and Position
set the width of button 1 of me to the width of me * 0.4
set the height of button 1 of me to height of me * 0.65
set the loc of button 1 of me to the loc of me
// Button Text Size
put the height of button 1 of me * 0.7 into tTextHeight
repeat with x = 6 to 100
set the textSize of button 1 of me to x
if the formattedheight of button 1 of me > tTextHeight then exit repeat
end repeat
unlock screen
end resizecontrol
Example Script - Scale field text size
1) Add a field
2) Make the field scale and position left
3) Make the button scale and position right
on resizecontrol
lock screen
// Background
set the rect of graphic 1 of me to the rect of me
// Button Size and Position
set the width of button 1 of me to the width of me * 0.4
set the height of button 1 of me to height of me * 0.65
set the loc of button 1 of me to the loc of me
set the right of button 1 of me to (the left of me + (the width of me * 0.95))
// Button Text Size
put the height of button 1 of me * 0.7 into tTextHeight
repeat with x = 6 to 100
set the textSize of button 1 of me to x
if the formattedheight of button 1 of me > tTextHeight then exit repeat
end repeat
// Field Size and Position
set the width of field 1 of me to the width of me * 0.5
set the height of field 1 of me to height of me * 0.65
set the loc of field 1 of me to the loc of me
set the left of field 1 of me to (the left of me + (the width of me * 0.05))
// Field Margins (Centers the text in the field)
local tTextRect, tFieldRect, tDeltaY
set the textsize of field 1 of me to the textsize of button 1 of me
set the margins of field 1 of me to 0
put the formattedRect of line 1 to -1 of field 1 of me into tTextRect
put the rect of field 1 of me into tFieldRect
put ((item 4 of tFieldRect - item 2 of tFieldRect) - (item 4 of tTextRect - item 2 of tTextRect)) div 2 + (item 2 of tFieldRect - item 2 of tTextRect) into tDeltaY
set the margins of field 1 of me to 0,tDeltaY,4,0
unlock screen
end resizecontrol
0 Comments
Add your comment