{ "id": "89809", "key": "TIMOB-8673", "fields": { "issuetype": { "id": "6", "description": "gh.issue.epic.desc", "name": "Epic", "subtask": false }, "project": { "id": "10153", "key": "TIMOB", "name": "Titanium SDK/CLI", "projectCategory": { "id": "10100", "description": "Titanium and related SDKs used in application development", "name": "Client" } }, "fixVersions": [ { "id": "13271", "description": "Release 2.1.0", "name": "Release 2.1.0", "archived": false, "released": true, "releaseDate": "2012-06-29" }, { "id": "13404", "description": "Sprint 2012-12 Core", "name": "Sprint 2012-12 Core", "archived": true, "released": true, "releaseDate": "2012-06-17" } ], "resolution": { "id": "1", "description": "A fix for this issue is checked into the tree and tested.", "name": "Fixed" }, "resolutiondate": "2012-06-18T14:31:39.000+0000", "created": "2012-04-10T23:07:42.000+0000", "priority": { "name": "High", "id": "2" }, "labels": [ "core", "parity" ], "versions": [ { "id": "12593", "name": "Release 2.0.0", "archived": false, "released": true, "releaseDate": "2012-03-30" } ], "issuelinks": [ { "id": "17355", "type": { "id": "10020", "name": "Depends", "inward": "is dependent of", "outward": "depends on" }, "inwardIssue": { "id": "91296", "key": "TIMOB-8980", "fields": { "summary": "Android: Horizontal layout should provide consistent behavior when wrapping", "status": { "description": "The issue is considered finished, the resolution is correct. Issues which are closed can be reopened.", "name": "Closed", "id": "6", "statusCategory": { "id": 3, "key": "done", "colorName": "green", "name": "Done" } }, "priority": { "name": "High", "id": "2" }, "issuetype": { "id": "1", "description": "A problem which impairs or prevents the functions of the product.", "name": "Bug", "subtask": false } } } }, { "id": "16485", "type": { "id": "10003", "name": "Relates", "inward": "relates to", "outward": "relates to" }, "outwardIssue": { "id": "63888", "key": "TIMOB-3256", "fields": { "summary": "iOS: \"Horizontal\" layout incorrectly wraps", "status": { "description": "The issue is considered finished, the resolution is correct. Issues which are closed can be reopened.", "name": "Closed", "id": "6", "statusCategory": { "id": 3, "key": "done", "colorName": "green", "name": "Done" } }, "priority": { "name": "Trivial", "id": "5" }, "issuetype": { "id": "1", "description": "A problem which impairs or prevents the functions of the product.", "name": "Bug", "subtask": false } } } }, { "id": "17494", "type": { "id": "10003", "name": "Relates", "inward": "relates to", "outward": "relates to" }, "outwardIssue": { "id": "92293", "key": "TIMOB-9225", "fields": { "summary": "iOS: Review composite layout feature requests", "status": { "description": "The issue is considered finished, the resolution is correct. Issues which are closed can be reopened.", "name": "Closed", "id": "6", "statusCategory": { "id": 3, "key": "done", "colorName": "green", "name": "Done" } }, "priority": { "name": "High", "id": "2" }, "issuetype": { "id": "7", "description": "gh.issue.story.desc", "name": "Story", "subtask": false } } } }, { "id": "17507", "type": { "id": "10003", "name": "Relates", "inward": "relates to", "outward": "relates to" }, "outwardIssue": { "id": "92294", "key": "TIMOB-9226", "fields": { "summary": "Android: Review composite layout feature requests", "status": { "description": "The issue is considered finished, the resolution is correct. Issues which are closed can be reopened.", "name": "Closed", "id": "6", "statusCategory": { "id": 3, "key": "done", "colorName": "green", "name": "Done" } }, "priority": { "name": "High", "id": "2" }, "issuetype": { "id": "7", "description": "gh.issue.story.desc", "name": "Story", "subtask": false } } } }, { "id": "16486", "type": { "id": "10003", "name": "Relates", "inward": "relates to", "outward": "relates to" }, "outwardIssue": { "id": "80204", "key": "TIMOB-5266", "fields": { "summary": "iOS: Flow Layout", "status": { "description": "The issue is considered finished, the resolution is correct. Issues which are closed can be reopened.", "name": "Closed", "id": "6", "statusCategory": { "id": 3, "key": "done", "colorName": "green", "name": "Done" } }, "priority": { "name": "Low", "id": "4" }, "issuetype": { "id": "2", "description": "A new feature of the product, which has yet to be developed.", "name": "New Feature", "subtask": false } } } }, { "id": "16487", "type": { "id": "10003", "name": "Relates", "inward": "relates to", "outward": "relates to" }, "outwardIssue": { "id": "80205", "key": "TIMOB-5267", "fields": { "summary": "Android: Flow Layout", "status": { "description": "The issue is considered finished, the resolution is correct. Issues which are closed can be reopened.", "name": "Closed", "id": "6", "statusCategory": { "id": 3, "key": "done", "colorName": "green", "name": "Done" } }, "priority": { "name": "Low", "id": "4" }, "issuetype": { "id": "2", "description": "A new feature of the product, which has yet to be developed.", "name": "New Feature", "subtask": false } } } }, { "id": "16500", "type": { "id": "10003", "name": "Relates", "inward": "relates to", "outward": "relates to" }, "inwardIssue": { "id": "89864", "key": "TIDOC-557", "fields": { "summary": "APIDoc: Correct documentation of 'horizontal' layout", "status": { "description": "The issue is considered finished, the resolution is correct. Issues which are closed can be reopened.", "name": "Closed", "id": "6", "statusCategory": { "id": 3, "key": "done", "colorName": "green", "name": "Done" } }, "priority": { "name": "High", "id": "2" }, "issuetype": { "id": "1", "description": "A problem which impairs or prevents the functions of the product.", "name": "Bug", "subtask": false } } } } ], "assignee": { "name": "mstepanov", "key": "mstepanov", "displayName": "Max Stepanov", "active": true, "timeZone": "America/Los_Angeles" }, "updated": "2017-03-21T20:38:15.000+0000", "status": { "description": "The issue is considered finished, the resolution is correct. Issues which are closed can be reopened.", "name": "Closed", "id": "6", "statusCategory": { "id": 3, "key": "done", "colorName": "green", "name": "Done" } }, "components": [ { "id": "10224", "name": "TiAPI", "description": "This component is used for cross-platform API work. Specifications are most likely to use this component." } ], "description": "When creating a horizontal layout containing the same set of views on Android and iOS, the views display differently.\r\n\r\n{code}\r\nvar win = Ti.UI.createWindow({ fullscreen: true, backgroundColor: 'white'});\r\n//Horizontal Layout behavior. Green child centered vertically (No positioning pins)\r\nvar parent = Ti.UI.createView({backgroundColor:'red',layout:'horizontal',width:300, height:300})\r\nvar child1 =Ti.UI.createView({backgroundColor:'green',height:60,width:150});\r\nvar child2 =Ti.UI.createView({backgroundColor:'blue',height:120,width:120});\r\nvar child3 =Ti.UI.createView({backgroundColor:'#eee',height:120,width:150});\r\nvar child4 =Ti.UI.createView({backgroundColor:'#666',height:60,width:150});\r\n\r\nparent.add(child1);\r\nparent.add(child2);\r\nparent.add(child3);\r\nparent.add(child4);\r\n\r\nwin.add(parent);\r\nwin.open();\r\n{code}\r\n\r\nOn iOS, the \"child1\" view is centered vertically with respect to the \"Child2\" view, and child2 is flush to the top of the parent view. Child3 and Child4 are on the next line, again centered vertically relative to each other.\r\n\r\nOn Android, child1 and child2 are centered vertically in the parent view, and child3 and child4 are flush against the bottom of the view.\r\n\r\nOn both platforms, the child3 and child4 views wrap to the next line rather than going off-screen. This is inconsistent with the behavior of vertical layouts, -and a break with Android behavior pre-2.0-.\r\n\r\nCorrection--wrapping is not a behavior change from pre-2.0. Both iOS and Android wrapped pre-2.0, and my original testing was incorrect.\r\n\r\nMeanwhile, Mobile Web does *not* wrap the children, but also doesn't center them vertically. See attached screenshots for comparison\r\n\r\nAs an additional note, the treatment of top and bottom is not consistent when the views wrap:\r\n\r\n* On iOS, specifying either top or bottom causes the child view to be aligned to the top or bottom _of the row_. However, specifying both top and bottom *without specifying a height* causes the child view to be pinned to the top and bottom _of the parent view_. If height is not specified and top and bottom are both specified, the child's height is set implicitly.\r\n\r\n* On Android, top and bottom behave as they do in a composite layout--pinning the child to the top and/or bottom of the parent view. If height is not specified and top and bottom are both specified, the child's height is set implicitly.\r\n\r\n* On Mobile Web, I believe top and bottom are interpreted as padding, so if both top and bottom are specified, the height is *not* set implicitly.\r\n\r\nIf we address horizontal layout parity, we might also want to consider Ivan's suggestion of adding a gravity or default vertical alignment within the rows. I believe Mobile Web already uses something like this internally.\r\n", "attachment": [ { "id": "26971", "filename": "horizontal_layout_mobileweb.png", "author": { "name": "aevans", "key": "aevans", "displayName": "Arthur Evans", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2012-04-10T23:22:53.000+0000", "size": 5693, "mimeType": "image/png" }, { "id": "26970", "filename": "horizontal_layout.png", "author": { "name": "aevans", "key": "aevans", "displayName": "Arthur Evans", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2012-04-10T23:20:28.000+0000", "size": 18120, "mimeType": "image/png" } ], "flagged": false, "summary": "Ti API: Horizontal Layout Modes do not match.", "creator": { "name": "aevans", "key": "aevans", "displayName": "Arthur Evans", "active": true, "timeZone": "America/Los_Angeles" }, "subtasks": [ { "id": "92829", "key": "TIMOB-9385", "fields": { "summary": "iOS: Implement conditional horizontal layout wrapping", "status": { "description": "The issue is considered finished, the resolution is correct. Issues which are closed can be reopened.", "name": "Closed", "id": "6", "statusCategory": { "id": 3, "key": "done", "colorName": "green", "name": "Done" } }, "priority": { "name": "High", "id": "2" }, "issuetype": { "id": "5", "description": "The sub-task of the issue", "name": "Sub-task", "subtask": true } } }, { "id": "92830", "key": "TIMOB-9386", "fields": { "summary": "Android: Implement conditional horizontal layout wrapping", "status": { "description": "The issue is considered finished, the resolution is correct. Issues which are closed can be reopened.", "name": "Closed", "id": "6", "statusCategory": { "id": 3, "key": "done", "colorName": "green", "name": "Done" } }, "priority": { "name": "High", "id": "2" }, "issuetype": { "id": "5", "description": "The sub-task of the issue", "name": "Sub-task", "subtask": true } } }, { "id": "92867", "key": "TIMOB-9410", "fields": { "summary": "MobileWeb: Implement conditional horizontal layout wrapping", "status": { "description": "The issue is considered finished, the resolution is correct. Issues which are closed can be reopened.", "name": "Closed", "id": "6", "statusCategory": { "id": 3, "key": "done", "colorName": "green", "name": "Done" } }, "priority": { "name": "High", "id": "2" }, "issuetype": { "id": "5", "description": "The sub-task of the issue", "name": "Sub-task", "subtask": true } } } ], "reporter": { "name": "aevans", "key": "aevans", "displayName": "Arthur Evans", "active": true, "timeZone": "America/Los_Angeles" }, "environment": null, "comment": { "comments": [ { "id": "190543", "author": { "name": "ivan.skugor", "key": "ivan.skugor", "displayName": "Ivan Skugor", "active": true, "timeZone": "Europe/Amsterdam" }, "body": "Pictures are awesome. :D\r\n\r\n\r\n\r\nAnyway, I don't know what composite layout specification contains (it's still top secret for outside world :( ), but I really miss functionality like \"float\" is in CSS world. It would be extremely useful if there was something like that. When building forms, typical use-case is to have label and input element like this:\r\n\r\n\r\nlabel1 input1\r\nlabel2 input2\r\n...\r\n\r\n\r\nTo achieve this, parent container must have \"vertical\" layout and all label-inputs needs to be wrapped with view that have \"horizontal\" layout (ok, this can be achieved by setting parent's layout property to \"absolute\" and hardcode position of label-inputs, but that is limited in dynamic scenarios when there are components that can change their height dynamically). That solution is fine, but it is not optimal and it impacts performances when there are a lot of elements (one extra view needs to be created for every label-input pair). So, IMHO, having something like \"float\" could be very benifitical in use-case I described.\r\n\r\n\r\n\r\nSorry for invading this issue, this does not belong here, but it's related (hopefully we can have a decent place for discussion, heh?). :)", "updateAuthor": { "name": "ivan.skugor", "key": "ivan.skugor", "displayName": "Ivan Skugor", "active": true, "timeZone": "Europe/Amsterdam" }, "created": "2012-04-11T01:05:26.000+0000", "updated": "2012-04-11T01:05:26.000+0000" }, { "id": "190589", "author": { "name": "aevans", "key": "aevans", "displayName": "Arthur Evans", "active": true, "timeZone": "America/Los_Angeles" }, "body": "Hi Ivan,\r\n\r\nYeah, you could sort of do that with 'horizontal' as it is defined in iOS, but I don't think it's optimal, and I also think there are valid use cases for 'horizontal' as it was defined on Android.\r\n\r\nThe label/input use case is such a common one that we should really provide a simpler way to put it together. ", "updateAuthor": { "name": "aevans", "key": "aevans", "displayName": "Arthur Evans", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2012-04-11T11:25:59.000+0000", "updated": "2012-04-11T11:25:59.000+0000" }, { "id": "190590", "author": { "name": "aevans", "key": "aevans", "displayName": "Arthur Evans", "active": true, "timeZone": "America/Los_Angeles" }, "body": "Fixed sample code to match screenshots.", "updateAuthor": { "name": "aevans", "key": "aevans", "displayName": "Arthur Evans", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2012-04-11T11:28:35.000+0000", "updated": "2012-04-11T11:28:35.000+0000" }, { "id": "190626", "author": { "name": "aevans", "key": "aevans", "displayName": "Arthur Evans", "active": true, "timeZone": "America/Los_Angeles" }, "body": "Corrected description. This is NOT a behavior change on Android, but handling of this layout type should be made consistent.\r\n\r\nGiven the wrapping behavior, iOS is probably doing this the 'right' way. But it really seems like this should be a separate layout mode and we should have a normal 'horizontal'.", "updateAuthor": { "name": "aevans", "key": "aevans", "displayName": "Arthur Evans", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2012-04-11T14:31:27.000+0000", "updated": "2012-04-11T14:31:27.000+0000" }, { "id": "190631", "author": { "name": "aevans", "key": "aevans", "displayName": "Arthur Evans", "active": true, "timeZone": "America/Los_Angeles" }, "body": "Ivan: \r\n\r\nUntil we have a discussion forum available...\r\n\r\nOne approach to the type of layout you described is to use the 'horizontal' layout and use percentage widths adding up to 100% for the label and input field. Here's an example:\r\n\r\n{code}\r\nvar labelColor = '#59a9e3';\r\n\r\nvar makeDivider = function() {\r\n\treturn Ti.UI.createView({\r\n\t\ttop: 0,\r\n\twidth: '100%',\r\n\theight: 1,\r\n\tbackgroundColor: '#484848'\r\n});\r\n};\r\n//\r\n// create base UI tab and root window\r\n//\r\nvar win1 = Titanium.UI.createWindow({ \r\n title:'Form Test',\r\n backgroundColor:'#eee',\r\n layout: 'horizontal'\r\n});\r\n\r\nlabel1 = Ti.UI.createLabel({\r\n\ttop: 0,\r\n\ttextAlign: Ti.UI.TEXT_ALIGNMENT_RIGHT,\r\n\tcolor: labelColor,\r\n\twidth: '20%',\r\n\theight: '50dp',\r\n\ttext: 'Name'\r\n});\r\ninput1 = Ti.UI.createTextField({\r\n\ttop: 0,\r\n\tleft: '2%',\r\n\twidth: '78%',\r\n\theight: '50dp',\r\n\tbackgroundImage: 'none'\r\n});\r\n\r\nlabel2 = Ti.UI.createLabel({\r\n\ttop: 0,\r\n\tcolor: labelColor,\r\n\ttextAlign: Ti.UI.TEXT_ALIGNMENT_RIGHT,\r\n\ttext: 'Rank',\r\n\twidth: '20%',\r\n\theight: '50dp'\r\n});\r\ninput2 = Ti.UI.createTextField({\r\n\ttop: 0,\r\n\tleft: '2%',\r\n\twidth: '78%',\r\n\theight: '50dp',\r\n\tbackgroundImage: 'none'\r\n});\r\n\r\nwin1.add(label1);\r\nwin1.add(input1);\r\nwin1.add(makeDivider());\r\nwin1.add(label2);\r\nwin1.add(input2);\r\nwin1.add(makeDivider());\r\nwin1.open();\r\n{code}\r\n\r\nThis appears to work in Android back to 1.7.5. In 2.0 it will work on both iOS and Android, but not Mobile Web.\r\n", "updateAuthor": { "name": "aevans", "key": "aevans", "displayName": "Arthur Evans", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2012-04-11T14:51:33.000+0000", "updated": "2012-04-11T14:51:33.000+0000" }, { "id": "190683", "author": { "name": "ivan.skugor", "key": "ivan.skugor", "displayName": "Ivan Skugor", "active": true, "timeZone": "Europe/Amsterdam" }, "body": "Arthur, thanks a lot. That's exactly what I wanted to achieve.\r\n\r\n\r\nBut that solution does not work for ScrollView (and ScrollView must be used when there is large number of form components present). Btw, ScrollView component has issues on Android and usually wrapping ScrollView's content with basic View helps. I tried to play a bit with your code and I managed to come to some solution (it has some issues, but could be used as a workaround)\r\n\r\n{code}\r\nvar labelColor = '#59a9e3';\r\n \r\nvar makeDivider = function() {\r\n return Ti.UI.createView({\r\n top: 0,\r\n width: '100%',\r\n height: 1,\r\n backgroundColor: '#484848'\r\n});\r\n};\r\n//\r\n// create base UI tab and root window\r\n//\r\nvar win1 = Titanium.UI.createWindow({\r\n title:'Form Test',\r\n navBarHidden: true,\r\n backgroundColor:'#eee'\r\n});\r\n\r\nvar wrapper = Ti.UI.createView({\r\n width: '100%',\r\n height: '150%',\r\n layout: 'horizontal'\r\n});\r\n\r\nvar view = Ti.UI.createScrollView({\r\n contentWidth: 'auto',\r\n contentHeight: 'auto',\r\n width: '100%',\r\n height: '100%'\r\n});\r\n\r\nfor (var i = 0; i < 100; ++i) {\r\n \r\n var label1 = Ti.UI.createLabel({\r\n top: 0,\r\n textAlign: Ti.UI.TEXT_ALIGNMENT_RIGHT,\r\n color: labelColor,\r\n width: '20%',\r\n height: '50dp',\r\n text: 'Name ' + i\r\n });\r\n \r\n var input1 = Ti.UI.createTextField({\r\n top: 0,\r\n left: '2%',\r\n width: '78%',\r\n height: '50dp',\r\n backgroundImage: 'none'\r\n });\r\n \r\n wrapper.add(label1);\r\n wrapper.add(input1);\r\n wrapper.add(makeDivider());\r\n}\r\n\r\nview.add(wrapper);\r\nwin1.add(view);\r\nwin1.open();\r\n{code}\r\n\r\n\r\n\r\nIf issues with ScrollView will be fixed, then this solution is satisfying. But still, there is unnecessary code (top: 0) and in my opinion it would be more useful if we could set, for example, some layout property that would do that without a need to specify \"top\" property for every component. I think Android has something like \"gravity\" that does something like that, but I'm not really sure (I'm not Android programmer).", "updateAuthor": { "name": "ivan.skugor", "key": "ivan.skugor", "displayName": "Ivan Skugor", "active": true, "timeZone": "Europe/Amsterdam" }, "created": "2012-04-12T02:14:35.000+0000", "updated": "2012-04-12T02:14:35.000+0000" }, { "id": "193781", "author": { "name": "bhughes", "key": "bhughes", "displayName": "Bryan Hughes", "active": true, "timeZone": "America/Los_Angeles" }, "body": "We do have internal mechanisms for setting the default horizontal/vertical alignment in views, as the ticket suggests, and we have default vertical alignment of horizontal layout rows coming in TIMOB-8275.", "updateAuthor": { "name": "bhughes", "key": "bhughes", "displayName": "Bryan Hughes", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2012-05-04T13:16:39.000+0000", "updated": "2012-05-04T13:16:39.000+0000" }, { "id": "195283", "author": { "name": "bhughes", "key": "bhughes", "displayName": "Bryan Hughes", "active": true, "timeZone": "America/Los_Angeles" }, "body": "FYI TIMOB-8275 has been completed and merged, so Mobile Web now has wrapping in horizontal views. The screenshots attached to the ticket should probably be updated.", "updateAuthor": { "name": "bhughes", "key": "bhughes", "displayName": "Bryan Hughes", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2012-05-18T09:43:44.000+0000", "updated": "2012-05-18T09:43:44.000+0000" }, { "id": "198699", "author": { "name": "mstepanov", "key": "mstepanov", "displayName": "Max Stepanov", "active": true, "timeZone": "America/Los_Angeles" }, "body": "Android and iOS are now match.\r\nMobileWeb needs a fix, afaik.", "updateAuthor": { "name": "mstepanov", "key": "mstepanov", "displayName": "Max Stepanov", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2012-06-15T10:58:49.000+0000", "updated": "2012-06-15T10:58:49.000+0000" }, { "id": "198718", "author": { "name": "bhughes", "key": "bhughes", "displayName": "Bryan Hughes", "active": true, "timeZone": "America/Los_Angeles" }, "body": "PR is in for Mobile Web.", "updateAuthor": { "name": "bhughes", "key": "bhughes", "displayName": "Bryan Hughes", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2012-06-15T11:54:05.000+0000", "updated": "2012-06-15T11:54:05.000+0000" }, { "id": "414372", "author": { "name": "lmorris", "key": "lmorris", "displayName": "Lee Morris", "active": false, "timeZone": "America/Los_Angeles" }, "body": "Closing ticket as fixed.", "updateAuthor": { "name": "lmorris", "key": "lmorris", "displayName": "Lee Morris", "active": false, "timeZone": "America/Los_Angeles" }, "created": "2017-03-21T20:38:15.000+0000", "updated": "2017-03-21T20:38:15.000+0000" } ], "maxResults": 11, "total": 11, "startAt": 0 } } }