[TIMOB-15501] iOS: ScrollableView with many child views flicker when changing orientation
GitHub Issue | n/a |
---|---|
Type | Bug |
Priority | Medium |
Status | Closed |
Resolution | Won't Fix |
Resolution Date | 2014-02-03T23:55:47.000+0000 |
Affected Version/s | Release 3.1.2, Release 3.1.3 |
Fix Version/s | 2014 Sprint 03, 2014 Sprint 03 API |
Components | iOS |
Labels | supportTeam, triage |
Reporter | Ashish Nigam |
Assignee | Vishal Duggal |
Created | 2013-10-16T09:55:17.000+0000 |
Updated | 2017-03-22T18:27:02.000+0000 |
Description
When using multiple views with scrollable view, flickering effect if observed in iOS7 with 3.1.3.GA.
Steps to reproduce:
1: Use the sample code1 to reproduce the issue.
2: Use the code in app.js of a newly created project.
3: Build the project for iOS7 device (Simulator does not reproduce it).
4: check the effect while changing the orientation.
Note: sample code 2, does not reproduce the issue. Having less views in container view.
**Sample code1 - can reproduce issue**
var headerView = Ti.UI.createView({
backgroundColor : '#DB2027',
height : '40dp'
});
var headerTitle = Ti.UI.createLabel({
text : "Main Window",
font : {
fontSize : '20dp',
fontWeight : 'bold'
},
textAlign : Ti.UI.TEXT_ALIGNMENT_CENTER,
color : '#FFFFFF'
});
headerView.add(headerTitle);
// btn
var leftBtnSetting = Ti.UI.createButton({
settingsOpen : false,
left : '5dp',
height : '15dp',
style : Ti.UI.iPhone.SystemButtonStyle.PLAIN,
title : "Ashish"
});
headerView.add(leftBtnSetting);
var rtBtn = Ti.UI.createButton({
title : "right",
//color: 'white',
font : {
fontSize : '15dp',
},
right : '5dp'
});
headerView.add(rtBtn);
// btn end
var win = Ti.UI.createWindow({
top : 20,
backgroundColor : "black",
orientationModes : [Ti.UI.PORTRAIT, Ti.UI.LANDSCAPE_LEFT, Ti.UI.LANDSCAPE_RIGHT]
});
var containerView = Ti.UI.createView({
backgroundColor : "gray",
top : 0,
layout : "vertical"
});
containerView.add(headerView);
//view 1
var surveyView = Ti.UI.createView({
backgroundColor : '#d0d0d0',
layout : 'vertical'
});
var surveyNames = ['Check1', 'Check2', 'Check3', 'Check4', 'Check5'];
var surveyUnits = ['(feet)', '(degrees)', '(degrees)', '(feet)', '(deg/100 ft)'];
function createColumnHeader (names, units){
var viewWidth = (100/names.length).toString() + '%';
var headerView = Ti.UI.createView({
height : '60dp',
layout : 'horizontal',
backgroundColor : '#CCCCCC'
});
names.forEach(function(e, i){
var view = Ti.UI.createView({
width : viewWidth,
height : headerView.height,
left : '0dp',
borderWidth : 0.3,
borderColor : '#444444',
layout: 'vertical'
});
var label = Ti.UI.createLabel({
text : e,
top : '10dp',
color : '#333333',
textAlign : Ti.UI.TEXT_ALIGNMENT_CENTER,
font : {
fontSize : '12dp',
fontWeight : 'bold'
}
});
label.setHeight(Ti.UI.SIZE);
view.add(label);
if(units)
{
var unitLabel = Ti.UI.createLabel({
text : units[i],
textAlign : Ti.UI.TEXT_ALIGNMENT_CENTER,
font : {
fontSize : '10dp'
}
});
view.add(unitLabel);
}
//view.setHeight(Ti.UI.SIZE);
headerView.add(view);
});
//headerView.setHeight(Ti.UI.SIZE);
return headerView;
};
var surveyHeaderView = createColumnHeader(surveyNames, surveyUnits);
surveyView.add(surveyHeaderView);
var rows = [];
var values = [3000, 4000, 5000, 6000, 7000];
function createSurveyPageRow (values){
var viewWidth = (100/values.length).toString() + '%';
var tableRow = Ti.UI.createTableViewRow({
height : '40dp',
className : 'surveyRow',
backgroundColor : '#EEEEEE'
});
var rowView = Ti.UI.createView({
height : '40dp',
layout : 'horizontal'
});
values.forEach(function(e){
var view = Ti.UI.createView({
width : viewWidth,
height : rowView.height,
left : '0dp',
layout: 'vertical'
});
var label = Ti.UI.createLabel({
text : e,
top : '10dp',
textAlign : Ti.UI.TEXT_ALIGNMENT_CENTER,
font : {
fontSize : '12dp'
}
});
view.add(label);
rowView.add(view);
});
tableRow.add(rowView);
return tableRow;
};
for ( i = 0; i < 5; i++) {
rows.push(createSurveyPageRow(values));
}
var tableView = Ti.UI.createTableView({
data : rows,
});
surveyView.add(tableView);
//view end
// var view1 = Ti.UI.createView({
// width : Ti.UI.FILL,
// height : Ti.UI.FILL,
// backgroundColor : "red"
// });
// var view2 = Ti.UI.createView({
// width : Ti.UI.FILL,
// height : Ti.UI.FILL,
// backgroundColor : "yellow"
// });
createLithologyPageRow = function(data){
//var key = Object.keys(data);
//alert(key.length);
var keys = Object.keys(data); // Get an array of property names for object o
var values = []; // Store matching property values in this array
for(var i = 0; i < keys.length; i++) { // For each index in the array
var key = keys[i]; // Get the key at that index
values[i] = data[key]; // Store the value in the values array
}
var viewWidth = (100/keys.length).toString() + '%';
var tableRow = Ti.UI.createTableViewRow({
backgroundColor : '#666666',
className : 'lithologyRow'
});
var rowView = Ti.UI.createView({
top : '0dp',
bottom : '0dp',
layout : 'horizontal'
});
//keys.forEach(function(e, index){
for(index=0; index<keys.length ; index++){
var view = Ti.UI.createView({
width : viewWidth,
top : '0dp',
left : '0dp',
bottom : '0dp',
layout: 'vertical'
});
var val_obj = values[index];
var val_obj_keys = Object.keys(values[index]);
var val = [];
for(var i = 0; i < val_obj_keys.length; i++) { // For each index in the array
var key = val_obj_keys[i]; // Get the key at that index
val[i] = val_obj[key]; // Store the value in the values array
}
for(i=0; i<val.length ; i++)
{
var label = Ti.UI.createLabel({
text : val[i],
top : '0dp',
textAlign : Ti.UI.TEXT_ALIGNMENT_CENTER,
font : {
fontSize : '14dp'
}
});
view.add(label);
}
view.setHeight(Ti.UI.SIZE);
rowView.add(view);
};
rowView.setHeight(Ti.UI.SIZE);
tableRow.add(rowView);
//tableRow.setHeight(Ti.UI.SIZE);
return tableRow;
};
var lithologyView = Ti.UI.createView({
backgroundColor : '#e3e3e3',
layout : 'vertical'
});
var lithologyNames = ['Check1', 'Check2', '%', 'REMARKS'];
var lithologyHeaderView = createColumnHeader(lithologyNames);
lithologyView.add(lithologyHeaderView);
var rows = [];
var value_row1 = {
'Check1' : {
1 : '3000'
},
'Check2' : {
0 : 'Check2A',
1 : 'Check2B',
2 : 'Check2C',
3 : 'Check2D'
},
'Check3' : {
1 : '25%',
2 : '25%',
3 : '25%',
4 : '25%'
},
'Remarks' : {
1 : 'YES'
}
};
var value_row2 = {
'Check1' : {
1 : '3000'
},
'Check2' : {
0 : 'Check2A',
1 : 'Check2B',
2 : 'Check2C',
3 : 'Check2D'
},
'Check3' : {
1 : '25%',
2 : '25%',
3 : '25%',
4 : '25%'
},
'Remarks' : {
1 : 'YES'
}
};
var value_row3 = {
'Check1' : {
1 : '3000'
},
'Check2' : {
0 : 'Check2A',
1 : 'Check2B',
2 : 'Check2C',
3 : 'Check2D'
},
'Check3' : {
1 : '25%',
2 : '25%',
3 : '25%',
4 : '25%'
},
'Remarks' : {
1 : 'YES'
}
};
rows.push(createLithologyPageRow(value_row1));
rows.push(createLithologyPageRow(value_row2));
rows.push(createLithologyPageRow(value_row3));
var tableView = Ti.UI.createTableView({
data : rows,
});
rows[0].addEventListener('click', function(e) {
var win = Titanium.UI.createWindow({
url : 'ui/handheld/lithology_detail.js',
backgroundColor : '#FFFFFF',
top:iOS7 ? 20 : 0,
statusBarStyle : osStatusBarStyle,
layout : 'vertical',
fullscreen : false
});
win.open(leftNavAnimation);
});
tableView.setHeight(Ti.UI.SIZE);
lithologyView.add(tableView);
var monitorSettingsBtn = Ti.UI.createButton({
title : 'Monitor Settings',
//bottom : 10,
//left : '40%',
});
lithologyView.add(monitorSettingsBtn);
monitorSettingsBtn.addEventListener('click', function(e) {
var win = Titanium.UI.createWindow({
url : 'ui/handheld/monitorSettings.js',
backgroundColor : '#FFFFFF',
top:iOS7 ? 20 : 0,
statusBarStyle : osStatusBarStyle,
layout : 'vertical',
fullscreen : false
});
win.open(leftNavAnimation);
});
var slableView = Ti.UI.createScrollableView({
views : [surveyView, lithologyView],
showPagingControl : true
});
containerView.add(slableView);
win.add(containerView);
win.open();
**sample code2 - does not reproduce issue**
var headerView = Ti.UI.createView({
backgroundColor : '#DB2027',
height : '40dp'
});
var headerTitle = Ti.UI.createLabel({
text : "Main Window",
font : {
fontSize : '20dp',
fontWeight : 'bold'
},
textAlign : Ti.UI.TEXT_ALIGNMENT_CENTER,
color : '#FFFFFF'
});
headerView.add(headerTitle);
// btn
var leftBtnSetting = Ti.UI.createButton({
settingsOpen : false,
left : '5dp',
height : '15dp',
style : Ti.UI.iPhone.SystemButtonStyle.PLAIN,
title:"Ashish"
});
headerView.add(leftBtnSetting);
var rtBtn = Ti.UI.createButton({
title : "right",
//color: 'white',
font : {
fontSize : '15dp',
},
right : '5dp'
});
headerView.add(rtBtn);
// btn end
var win = Ti.UI.createWindow({
top : 20,
backgroundColor : "black",
orientationModes : [Ti.UI.PORTRAIT, Ti.UI.LANDSCAPE_LEFT, Ti.UI.LANDSCAPE_RIGHT]
});
var containerView = Ti.UI.createView({
backgroundColor : "gray",
top : 0,
layout : "vertical"
});
containerView.add(headerView);
var view1 = Ti.UI.createView({
width : Ti.UI.FILL,
height : Ti.UI.FILL,
backgroundColor : "red"
});
var view2 = Ti.UI.createView({
width : Ti.UI.FILL,
height : Ti.UI.FILL,
backgroundColor : "yellow"
});
var slableView = Ti.UI.createScrollableView({
views : [view1, view2],
showPagingControl : true
});
containerView.add(slableView);
win.add(containerView);
win.open();
Sample code2 does not reproduce the issue, as it does not contain many views attached to a single view of scrollable view.
This is not exactly a ScrollableView problem but a symptom of our layout system limitation that the ScrollableView exacerbates (since it has to manage and update the internal page cache on rotation) The way this UI is set up, you have nested vertical layouts in horizontal layouts within vertical layouts. While the horizontal and vertical layouts are nice to have they are inherently slower than the absolute layout system since the layout engine has to measure every view before starting a layout pass. The more constraints the layout engine has to resolve the slower the layout is going to be A second problem is with the Ti.UI.TEXT_ALIGNMENT_CENTER property of the Label. This property is only useful if you have multiple lines of text or the width of the Label is more than that of the text. Setting this property of single lines of text with width set to SIZE only causes UI glitches (the flickering effect) since the actual label drawing happens outside the animated layout loop. This particular screen can easily be modified to an absolute layout. Please see sample code below which modifies the container view and the first page of the Scrollable view to an absolute layout. Further improvements can be gained by incorporating the table header views into the table view itself (as a row so it lays out along with the other rows). The second screen can also be set up similarly.
Closing ticket as the issue will not fix and with reference to the above comments.