Titanium SDK Save PDF Selected topic Selected topic and subtopics All content UI Composite Layout Behavior Spec Contents Overview Titanium's UI behavior has remained unspecified and fragmented across platforms, which makes cross-platform development difficult for users and designing tests to evaluate UI impractical. With proposed changes to the layout system, and more advanced testing frameworks, it has become necessary to explicitly define UI behavior in as many situations as possible. This document is a codification of UI behavior (the "Composite" layout) for both Android and iOS platforms, including explicit specifications for unit types, order in which layout properties are valuated, "auto" behavior, and dealing with unset values. The behavior for "Horizontal" and "Vertical" layouts will be specified in another document. Backwards Compatibility and Deprecation In Titanium Mobile 2.0, the value of any layout parameter on a View will always maintain that value, making it "static". The properties size, and rect, will now serve as the "dynamic" APIs that provide position and size. We will also maintain backwards compatibility with the current "immediate mode" layout scheme, but this behavior will be marked as DEPRECATED. Moving forward, we will drop support for this method in favor of the the startLayout / finishLayout, and updateLayout semantics. Definitions dip : Density-independent pixels. A measurement which is translated natively to a corresponding pixel measure using a scale factor based on a platform-specific "default" density, and the device's physical density. System unit : A platform-dependent unit which is the default for how the system presents its view information to the native layout system. On Android this is pixels; on iOS it is dip. Layout parameters This is the list of Layout Parameters used by "Composite", "Horizontal", and "Vertical" layouts. Layout Parameters are discussed in more detail in the Layout specification, but these all correspond to existing layout settings. width : The width of the view left : Pins left side of the view to this x position in the parent, measured from the parent's left bound. right : Pins right side of the view to this x position in the parent, measured from the parent's right bound. height : The height of the view top : Pins top side of the view to this y position in the parent, measured from the parent's top bound. bottom : Pins bottom side of the view to this y position in the parent, measured from the parent's bottom bound. center : (x, y) : Pins the view's center to the specified point: center.x : The x-coordinate, measured from the parent's left bound center.y : The y-coordinate, measured from the parent's top bound layout : The layout type to use. The default value is for the "Composite" layout. Other valid values are "vertical" and "horizontal". This property is intended to be replaced by the new UI Layout API Spec 'vertical' : Pinning happens vertically relative to other views inside the parent, using remaining space 'horizontal' : Pinning happens horizontally relative to other views inside the parent, using remaining space zIndex : The stack order of the view inside its parent. Higher values are rendered towards the top. When a child view's boundary exceeds that of the parent view, it should be clipped to the size of the parent view. Available units A unit is a unit of measurement on the device screen or, for some types, a measurement relative to information from the parent view. Absolute measurements px : pixels mm : millimeters cm : centimeters in : inches dp/dip : Density-independent pixels Android : px = dip * (screen density) / 160 iOS : px = dip * (screen density) / 163 (effectively; 1dip=1px on standard, 1dip=2px on retina) Mobile Web: px = dip * (screen density) / 96 (effectively; 1dip=1px most browsers scale pages to 96dpi to make them consistent with desktops). Relative measurements % : Percentage of the size of the parent. For x-axis values (width, left, right, center.x) this is relative to the parent's width For y-axis values (height, top, bottom, center.y) this is relative to the parent's height. tiapp.xml properties We allow users to specify a default unit type to interpret untyped values. By default, this value is a special unit type only available to this property, 'system' (see Definitions, above). ti.ui.defaultunit : String, the default unit to interpret values without a unit as. Generated in default tiapp.xml template (users can explicitly see default value) Valid values: px, mm, cm, in, dp, dip, system As of SDK 8.0.0, dp starts supported for default unit on Windows. Since Windows default unit has been px in previous versions this means this may cause breaking change. You might want to update your tiapp.xml to use px for default unit explicitly like <property name="ti.ui.defaultunit" type="string">px</property> to keep consistency between previous SDK versions. Precedence of layoutParams Certain parameters influence the calculation of others when they are unset (see UNDEFINED behavior ). The purpose of establishing an order of precedence is only to determine when certain settings override others when there is an obvious conflict, or determine which properties are used for computing implicit values. In order of precedence, from 'evaluated first' to 'evaluated last': width : overrides implicit width calculations left : overrides horizontal positioning determined by center.x, right center.x : overrides horizontal positioning determined by other pins right height : overrides implicit height calculations top : overrides vertical positioning determined by other pins center.y : overrides vertical positioning determined by other pins bottom When a conflict occurs between the different layout params, the order of precedence will determine which params will be ignored. If a view has a width of 200, a left value of 100, and a right value of 10, then the view would be 200 wide, and 100 from the left of its parent view. The right value is ignored since it conflicts the width and left values, and has lower precedence. Auto size behaviors "auto" (sometimes refered to as "psychic") is a measurement specification for width/height which "sizes the view appropriately given the type of view and its contents." This is a vague descriptor, and has been broken up into two general specified behaviors: SIZE and FILL. "auto" will be deprecated in 2.0.0, to be replaced with Ti.UI.SIZE and Ti.UI.FILL constants which represent explicit "auto" behavior. As a result, this section codifies existing "auto" behavior into these two subtypes, and declares which views use which type when their width or height is set to "auto" under the present system. ScrollView content size In the case of ScrollView, contentWidth and contentHeight may also be set to "auto", and in those cases, this is the expected behavior: When all children views have FILL behavior, the content area of the scroll view will be clipped to the physical size of the scroll view Otherwise, the content area will grow according to the bottom offset of the bottom-most View and the right offset of right-most View. In some cases the bottom-most and right-most View may be the same View. SIZE behavior This behavior represents constraining a view size to fit its contents. height only : Constrained by view's width, or if width is incalcuable (<2 horizontal pinning properties) and unset, then constrained by parent's width. width only : Constrained by view's height, or if height is incalculable (<2 vertical pinning properties) and unset, then constrained by parent's height. height + width : width constrained by parent width, height constraint by content height, i.e. grows to fill width first, and then sizes height to display content. ScrollView SIZE Scrollview contentWidth or contentHeight can be set to Ti.UI.SIZE. This value behaves as SIZE is described above, where the scrollview itself first sizes to contents, and then if those contents extend beyond the bounds of the scrollview, the content view sizes to fit the contents appropriately. FILL behavior This behavior represents growing a view size to fill its parent. height only : Fills all available vertical space inside the parent width only : Fills all available horizontal space inside the parent height + width : Fills all available space inside the parent\ NOTE: The fill behavior does not take any other views into account except for its parent. i.e. If the parent view has 2 children, the first with a static width/height and the second with fill behavior for both, the second view will still fill its parent. If the parent does not have a height/width constraint (i.e. The parent has size behavior for width/height while the child has fill behavior), then the view will recursively go through the parents to find a width/height constraint and fill to that constraint. ScrollView FILL Scrollview contentWidth or contentHeight can be set to Ti.UI.FILL. Regardless of contents, this behaves as described above, meaning that the content view bounds fill the scrollview. This has the side-effect that the scrollview does not scroll, so using this value is considered undesirable. View auto size classification Views are logically grouped into either SIZE or FILL for their auto behavior. Windows FILL the screen by default. SIZE Views Button Label ImageView ProgressBar Switch TextArea TextField Picker SearchBar height only, FILL width ButtonBar TableViewSection FILL Views View TabGroup VideoView Toolbar width only, SIZE height TableView TableViewRow width only, SIZE height WebView ScrollView ScrollableView Slider width only, SIZE height UNDEFINED behavior If layout parameter values are undefined, then this means that they need to be computed based on existing values if possible, and if not, then have some sensible default. Icon The layout parameters themselves will not actually change value, the dynamic APIs rect and size will contain the actual system values. width : implicit based on horizontal pins (left, center.x, right) If two (or more) horizontal pins are available, computed from these values Otherwise, follows view's "auto" behavior On "auto" deprecation, follows SIZE behavior If width is dependent on the parent (e.g. percentage), and the parent is set to SIZE, width is undefined left : implicit based on other horizontal pins (center.x, right) If no pinning properties are set : The view is centered horizontally in it's parent Otherwise, no left side pinning center.x : No center pinning (horizontal) right : No right side pinning height : implicit based on vertical pins (top, center.y, bottom) If two (or more) vertical pins are available, computed from these values Otherwise, follows view's "auto" behavior On "auto" deprecation, follows SIZE behavior If height is dependent on the parent (e.g. percentage), and the parent is set to SIZE, height is undefined top : implicit based on other vertical pins (center.y, bottom) If no pinning properties are set : The view is centered vertically in it's parent Otherwise, no top side pinning center.y : No center pinning (vertical) bottom : No bottom side pinning zIndex: implementation treats as 0, but will still be undefined in the View's layout params. Views are stacked in order of being added to the parent based on their index. UNDEFINED and scrollview contents For clarity, scrollview contentWidth and contentHeight behave as if they were set to "auto" when undefined. This is consistent with the behavior described above. Code Examples Each of these examples contrast the way something is done today ("old") with the way it will be done with the new dynamic size / rect properties, and batch updating semantics ("new"). Updating Layout Parameters // [old] changes the top and left of the view directly, re-layout twice view.top = 50; view.left = 50; // [new] change top and left, but only request a single layout view.startLayout(); view.top = 50; view.left = 50; view.finishLayout(); // [new] equivalent to above, but using batch update for convenience view.updateLayout({ top: 50, left: 50 }); Get Native and Model parameters view.width = 100; // [old] get the views's native width, but user supplied width is unavailable // view.width may not necessarily be 100 after being laid out Ti.API.debug("view width = " + view.width); // [new] get the view's native width, and the user supplied width // view.rect, view.size, are the new dynamic/native APIs // view.X will always have the user-supplied layout params Ti.API.debug("button width = " + view.rect.width + ", my width = " + view.width); Proposed API Dimension (duck type) Properties x : Number y : Number width : Number height : Number Ti.UI.View Properties size : Dimension, read-only, returns the bounds of the view in system units. x and y properties are always 0 rect : Dimension, read-only, returns the frame of the view (position relative to parent bounds) in system units. left : String or Number, the left bound of the view specified by the user right : String or Number, the right bound of the view specified by the user top : String or Number, the top bound of the view specified by the user bottom : String or Number, the bottom bound of the view specified by the user center : Object, the center point of the view specified by the user x : String or Number, the x coordinate of the center point y : String or Number, the y coordinate of the center point width : String or Number, the width of the view specified by the user height : String or Number, the height of the view specified by the user Functions startLayout() : void, starts a batch-update of the View's layout params finishLayout() : void, finishes a batch-update of the View's layout params, and schedules a layout pass of the view tree updateLayout(Object params) : void, performs a batch-update of all supplied layout params, and schedules a layout pass after they have been updated Ti.UI Constants Ti.UI.SIZE : Sets a view's height/width to be that of "auto" SIZE Ti.UI.FILL : Sets a view's height/width to be that of "auto" FILL Ti.UI.UNIT_PX : px unit Ti.UI.UNIT_MM : mm unit Ti.UI.UNIT_CM : cm unit Ti.UI.UNIT_IN : in unit Ti.UI.UNIT_DIP : dip unit Functions convertUnits(String convertFromValue, String convertToUnits) : Number, the conversion of one unit type to another using the metrics of the main Display convertFromValue : A measurement and optional unit to convert from, i.e. 160, "120dip" convertToUnits : The unit to convert to from one of the UNIT_* constants above NOTE we will need to accomodate for multiple displays in future revisions of this API NOTE because parent/self information is required for converting % values, there is no unit constant for '%' or conversions allowed to/from this value. If a percent value is passed in, this method returns 0. Events 'postlayout' : This event will be fired after a layout pass has occurred. Related Links
UI Composite Layout Behavior Spec Contents Overview Titanium's UI behavior has remained unspecified and fragmented across platforms, which makes cross-platform development difficult for users and designing tests to evaluate UI impractical. With proposed changes to the layout system, and more advanced testing frameworks, it has become necessary to explicitly define UI behavior in as many situations as possible. This document is a codification of UI behavior (the "Composite" layout) for both Android and iOS platforms, including explicit specifications for unit types, order in which layout properties are valuated, "auto" behavior, and dealing with unset values. The behavior for "Horizontal" and "Vertical" layouts will be specified in another document. Backwards Compatibility and Deprecation In Titanium Mobile 2.0, the value of any layout parameter on a View will always maintain that value, making it "static". The properties size, and rect, will now serve as the "dynamic" APIs that provide position and size. We will also maintain backwards compatibility with the current "immediate mode" layout scheme, but this behavior will be marked as DEPRECATED. Moving forward, we will drop support for this method in favor of the the startLayout / finishLayout, and updateLayout semantics. Definitions dip : Density-independent pixels. A measurement which is translated natively to a corresponding pixel measure using a scale factor based on a platform-specific "default" density, and the device's physical density. System unit : A platform-dependent unit which is the default for how the system presents its view information to the native layout system. On Android this is pixels; on iOS it is dip. Layout parameters This is the list of Layout Parameters used by "Composite", "Horizontal", and "Vertical" layouts. Layout Parameters are discussed in more detail in the Layout specification, but these all correspond to existing layout settings. width : The width of the view left : Pins left side of the view to this x position in the parent, measured from the parent's left bound. right : Pins right side of the view to this x position in the parent, measured from the parent's right bound. height : The height of the view top : Pins top side of the view to this y position in the parent, measured from the parent's top bound. bottom : Pins bottom side of the view to this y position in the parent, measured from the parent's bottom bound. center : (x, y) : Pins the view's center to the specified point: center.x : The x-coordinate, measured from the parent's left bound center.y : The y-coordinate, measured from the parent's top bound layout : The layout type to use. The default value is for the "Composite" layout. Other valid values are "vertical" and "horizontal". This property is intended to be replaced by the new UI Layout API Spec 'vertical' : Pinning happens vertically relative to other views inside the parent, using remaining space 'horizontal' : Pinning happens horizontally relative to other views inside the parent, using remaining space zIndex : The stack order of the view inside its parent. Higher values are rendered towards the top. When a child view's boundary exceeds that of the parent view, it should be clipped to the size of the parent view. Available units A unit is a unit of measurement on the device screen or, for some types, a measurement relative to information from the parent view. Absolute measurements px : pixels mm : millimeters cm : centimeters in : inches dp/dip : Density-independent pixels Android : px = dip * (screen density) / 160 iOS : px = dip * (screen density) / 163 (effectively; 1dip=1px on standard, 1dip=2px on retina) Mobile Web: px = dip * (screen density) / 96 (effectively; 1dip=1px most browsers scale pages to 96dpi to make them consistent with desktops). Relative measurements % : Percentage of the size of the parent. For x-axis values (width, left, right, center.x) this is relative to the parent's width For y-axis values (height, top, bottom, center.y) this is relative to the parent's height. tiapp.xml properties We allow users to specify a default unit type to interpret untyped values. By default, this value is a special unit type only available to this property, 'system' (see Definitions, above). ti.ui.defaultunit : String, the default unit to interpret values without a unit as. Generated in default tiapp.xml template (users can explicitly see default value) Valid values: px, mm, cm, in, dp, dip, system As of SDK 8.0.0, dp starts supported for default unit on Windows. Since Windows default unit has been px in previous versions this means this may cause breaking change. You might want to update your tiapp.xml to use px for default unit explicitly like <property name="ti.ui.defaultunit" type="string">px</property> to keep consistency between previous SDK versions. Precedence of layoutParams Certain parameters influence the calculation of others when they are unset (see UNDEFINED behavior ). The purpose of establishing an order of precedence is only to determine when certain settings override others when there is an obvious conflict, or determine which properties are used for computing implicit values. In order of precedence, from 'evaluated first' to 'evaluated last': width : overrides implicit width calculations left : overrides horizontal positioning determined by center.x, right center.x : overrides horizontal positioning determined by other pins right height : overrides implicit height calculations top : overrides vertical positioning determined by other pins center.y : overrides vertical positioning determined by other pins bottom When a conflict occurs between the different layout params, the order of precedence will determine which params will be ignored. If a view has a width of 200, a left value of 100, and a right value of 10, then the view would be 200 wide, and 100 from the left of its parent view. The right value is ignored since it conflicts the width and left values, and has lower precedence. Auto size behaviors "auto" (sometimes refered to as "psychic") is a measurement specification for width/height which "sizes the view appropriately given the type of view and its contents." This is a vague descriptor, and has been broken up into two general specified behaviors: SIZE and FILL. "auto" will be deprecated in 2.0.0, to be replaced with Ti.UI.SIZE and Ti.UI.FILL constants which represent explicit "auto" behavior. As a result, this section codifies existing "auto" behavior into these two subtypes, and declares which views use which type when their width or height is set to "auto" under the present system. ScrollView content size In the case of ScrollView, contentWidth and contentHeight may also be set to "auto", and in those cases, this is the expected behavior: When all children views have FILL behavior, the content area of the scroll view will be clipped to the physical size of the scroll view Otherwise, the content area will grow according to the bottom offset of the bottom-most View and the right offset of right-most View. In some cases the bottom-most and right-most View may be the same View. SIZE behavior This behavior represents constraining a view size to fit its contents. height only : Constrained by view's width, or if width is incalcuable (<2 horizontal pinning properties) and unset, then constrained by parent's width. width only : Constrained by view's height, or if height is incalculable (<2 vertical pinning properties) and unset, then constrained by parent's height. height + width : width constrained by parent width, height constraint by content height, i.e. grows to fill width first, and then sizes height to display content. ScrollView SIZE Scrollview contentWidth or contentHeight can be set to Ti.UI.SIZE. This value behaves as SIZE is described above, where the scrollview itself first sizes to contents, and then if those contents extend beyond the bounds of the scrollview, the content view sizes to fit the contents appropriately. FILL behavior This behavior represents growing a view size to fill its parent. height only : Fills all available vertical space inside the parent width only : Fills all available horizontal space inside the parent height + width : Fills all available space inside the parent\ NOTE: The fill behavior does not take any other views into account except for its parent. i.e. If the parent view has 2 children, the first with a static width/height and the second with fill behavior for both, the second view will still fill its parent. If the parent does not have a height/width constraint (i.e. The parent has size behavior for width/height while the child has fill behavior), then the view will recursively go through the parents to find a width/height constraint and fill to that constraint. ScrollView FILL Scrollview contentWidth or contentHeight can be set to Ti.UI.FILL. Regardless of contents, this behaves as described above, meaning that the content view bounds fill the scrollview. This has the side-effect that the scrollview does not scroll, so using this value is considered undesirable. View auto size classification Views are logically grouped into either SIZE or FILL for their auto behavior. Windows FILL the screen by default. SIZE Views Button Label ImageView ProgressBar Switch TextArea TextField Picker SearchBar height only, FILL width ButtonBar TableViewSection FILL Views View TabGroup VideoView Toolbar width only, SIZE height TableView TableViewRow width only, SIZE height WebView ScrollView ScrollableView Slider width only, SIZE height UNDEFINED behavior If layout parameter values are undefined, then this means that they need to be computed based on existing values if possible, and if not, then have some sensible default. Icon The layout parameters themselves will not actually change value, the dynamic APIs rect and size will contain the actual system values. width : implicit based on horizontal pins (left, center.x, right) If two (or more) horizontal pins are available, computed from these values Otherwise, follows view's "auto" behavior On "auto" deprecation, follows SIZE behavior If width is dependent on the parent (e.g. percentage), and the parent is set to SIZE, width is undefined left : implicit based on other horizontal pins (center.x, right) If no pinning properties are set : The view is centered horizontally in it's parent Otherwise, no left side pinning center.x : No center pinning (horizontal) right : No right side pinning height : implicit based on vertical pins (top, center.y, bottom) If two (or more) vertical pins are available, computed from these values Otherwise, follows view's "auto" behavior On "auto" deprecation, follows SIZE behavior If height is dependent on the parent (e.g. percentage), and the parent is set to SIZE, height is undefined top : implicit based on other vertical pins (center.y, bottom) If no pinning properties are set : The view is centered vertically in it's parent Otherwise, no top side pinning center.y : No center pinning (vertical) bottom : No bottom side pinning zIndex: implementation treats as 0, but will still be undefined in the View's layout params. Views are stacked in order of being added to the parent based on their index. UNDEFINED and scrollview contents For clarity, scrollview contentWidth and contentHeight behave as if they were set to "auto" when undefined. This is consistent with the behavior described above. Code Examples Each of these examples contrast the way something is done today ("old") with the way it will be done with the new dynamic size / rect properties, and batch updating semantics ("new"). Updating Layout Parameters // [old] changes the top and left of the view directly, re-layout twice view.top = 50; view.left = 50; // [new] change top and left, but only request a single layout view.startLayout(); view.top = 50; view.left = 50; view.finishLayout(); // [new] equivalent to above, but using batch update for convenience view.updateLayout({ top: 50, left: 50 }); Get Native and Model parameters view.width = 100; // [old] get the views's native width, but user supplied width is unavailable // view.width may not necessarily be 100 after being laid out Ti.API.debug("view width = " + view.width); // [new] get the view's native width, and the user supplied width // view.rect, view.size, are the new dynamic/native APIs // view.X will always have the user-supplied layout params Ti.API.debug("button width = " + view.rect.width + ", my width = " + view.width); Proposed API Dimension (duck type) Properties x : Number y : Number width : Number height : Number Ti.UI.View Properties size : Dimension, read-only, returns the bounds of the view in system units. x and y properties are always 0 rect : Dimension, read-only, returns the frame of the view (position relative to parent bounds) in system units. left : String or Number, the left bound of the view specified by the user right : String or Number, the right bound of the view specified by the user top : String or Number, the top bound of the view specified by the user bottom : String or Number, the bottom bound of the view specified by the user center : Object, the center point of the view specified by the user x : String or Number, the x coordinate of the center point y : String or Number, the y coordinate of the center point width : String or Number, the width of the view specified by the user height : String or Number, the height of the view specified by the user Functions startLayout() : void, starts a batch-update of the View's layout params finishLayout() : void, finishes a batch-update of the View's layout params, and schedules a layout pass of the view tree updateLayout(Object params) : void, performs a batch-update of all supplied layout params, and schedules a layout pass after they have been updated Ti.UI Constants Ti.UI.SIZE : Sets a view's height/width to be that of "auto" SIZE Ti.UI.FILL : Sets a view's height/width to be that of "auto" FILL Ti.UI.UNIT_PX : px unit Ti.UI.UNIT_MM : mm unit Ti.UI.UNIT_CM : cm unit Ti.UI.UNIT_IN : in unit Ti.UI.UNIT_DIP : dip unit Functions convertUnits(String convertFromValue, String convertToUnits) : Number, the conversion of one unit type to another using the metrics of the main Display convertFromValue : A measurement and optional unit to convert from, i.e. 160, "120dip" convertToUnits : The unit to convert to from one of the UNIT_* constants above NOTE we will need to accomodate for multiple displays in future revisions of this API NOTE because parent/self information is required for converting % values, there is no unit constant for '%' or conversions allowed to/from this value. If a percent value is passed in, this method returns 0. Events 'postlayout' : This event will be fired after a layout pass has occurred.