The extendEdges property of a window under a NavigationWindow allows the content of the window to extend under a translucent navigation bar, giving an iOS 7 depth effect.
However, when extendEdges is defined and a SearchBar is added to a ListView the positioning is incorrect. Using contentInsets on the ListView should align the SearchBar to be visible under the navigation bar, but it does not work as expected. It also creates a positioning problem when one clicks the SearchBar to use it, as it gets re-positioned under the navigation bar.
Expected Behavior:
When the SearchBar is added to a ListView, it should show below the navigation bar of the window without the need to use contentInsets. It should also remain in position when the user taps on it to enter some search text.
Test:
Using the code below, load the app. The initial view (pic 1) shows the SearchBar hidden below the navigation bar.
Tapping on the status bar at the top, correctly positions the SearchBar below the navigation bar (pic 2).
Tapping on the search bar to enter text, re-positions the SearchBar again under the navigation bar (pic 3).
app.js:
var rows = [];
for (var i = 0; i < 50; i++) {
rows.push({ properties: { title: '\u263B Row '+ i }});
}
var win = Ti.UI.createWindow({
title: 'TEST',
extendEdges: [Ti.UI.EXTEND_EDGE_TOP, Ti.UI.EXTEND_EDGE_BOTTOM],
backgroundColor: '#ffffff',
navBarHidden: false
});
var nav = Ti.UI.iOS.createNavigationWindow({ window: win });
var sb = Ti.UI.createSearchBar();
var ls = Ti.UI.createListSection({
items: rows
});
var lv = Ti.UI.createListView({
contentInsets: { top: 64, bottom: 60 },
sections: [ls],
searchView: sb
});
win.add(lv);
nav.open();
Moving this ticket to engineering as I can reproduce this issue with the provided test case and iOS simulator.
Replacement of UISearchDisplayController with UISearchController in TIUIListView PR: https://github.com/appcelerator/titanium_mobile/pull/9066 Test Case1 :
Test Case 2 -// without navigation bar var rows = []; for (var i = 0; i < 20; i++) { rows.push({ properties: { title: 'Row '+ i , backgroundColor: 'red', searchableText:'Row '+i}}); } var win = Ti.UI.createWindow({ title: 'TEST', backgroundColor: '#ffffff', }); var sb = Ti.UI.createSearchBar(); var ls = Ti.UI.createListSection({ items: rows }); var lv = Ti.UI.createListView({ //top : 100, sections: [ls], searchView: sb, resultsBackgroundColor: 'green', resultsSeparatorColor: 'blue' }); sb.setHintText("test"); sb.addEventListener('change', function(e){ Ti.API.info(e.value); }); //when the return key is hit, remove focus from our searchBar sb.addEventListener('return', function(e){ sb.blur(); }); lv.addEventListener('itemclick', function(e) { Ti.API.info('click at index: ' + e.itemIndex); }); win.add(lv); win.open();Test Case 3 -// with navigation bar var rows = []; for (var i = 0; i < 20; i++) { rows.push({ properties: { title: 'Row '+ i , backgroundColor: 'red', searchableText:'Row '+i}}); } var win = Ti.UI.createWindow({ title: 'TEST', backgroundColor: '#ffffff', }); var nav = Ti.UI.iOS.createNavigationWindow({ window: win, }); var testView = Ti.UI.createView({ backgroundColor : 'green' }); var sb = Ti.UI.createSearchBar(); var ls = Ti.UI.createListSection({ items: rows }); var lv = Ti.UI.createListView({ dimBackgroundForSearch: false, sections: [ls], searchView: sb, }); testView.add(lv); sb.setHintText("test"); sb.addEventListener('change', function(e){ Ti.API.info(e.value); }); //when the return key is hit, remove focus from our searchBar sb.addEventListener('return', function(e){ sb.blur(); }); lv.addEventListener('itemclick', function(e) { Ti.API.info('click at index: ' + e.itemIndex); }); win.add(testView); nav.open();// With tab bar var rows = []; for (var i = 0; i < 20; i++) { rows.push({ properties: { title: 'Row '+ i , backgroundColor: 'red', searchableText:'Row '+i}}); } var win1 = Ti.UI.createWindow({ title: 'TEST', backgroundColor: '#ffffff', }); var sb = Ti.UI.createSearchBar(); var ls = Ti.UI.createListSection({ items: rows }); var lv = Ti.UI.createListView({ top : 20, left : 50, right : 20, sections: [ls], searchView: sb, resultsBackgroundColor: 'green', }); sb.setHintText("test"); sb.addEventListener('change', function(e){ Ti.API.info(e.value); }); //when the return key is hit, remove focus from our searchBar sb.addEventListener('return', function(e){ sb.blur(); }); lv.addEventListener('itemclick', function(e) { Ti.API.info('click at index: ' + e.itemIndex); }); win1.add(lv); var win2 = Ti.UI.createWindow({ backgroundColor: 'red', title: 'Red' }); win2.add(Ti.UI.createLabel({text: 'I am a red window.'})); var tab1 = Ti.UI.createTab({ window: win1, title: 'Blue' }), tab2 = Ti.UI.createTab({ window: win2, title: 'Red' }), tabGroup = Ti.UI.createTabGroup({ tabs: [tab1, tab2] }); tabGroup.open();For TIUITableView also the changes has been made in same PR as both were similar changes. Test Case for TIUITableView - Test Case 1-
Test Case 2 -// TIUITableView with navigation var rows = []; for (var i = 0; i < 20; i++) { rows.push({ title: 'Row '+ i}); } var win = Ti.UI.createWindow({ title: 'TEST', backgroundColor: '#ffffff', navBarHidden: false }); var nav = Ti.UI.iOS.createNavigationWindow({ window: win, }); var sb = Ti.UI.createSearchBar(); var lv = Ti.UI.createTableView({ hideSearchOnSelection: false, data: rows, search: sb, }); sb.setHintText("test"); sb.addEventListener('change', function(e){ Ti.API.info(e.value); }); //when the return key is hit, remove focus from our searchBar sb.addEventListener('return', function(e){ sb.blur(); }); //when the cancel button is tapped, remove focus from our searchBar sb.addEventListener('cancel', function(e){ //sb.blur(); }); lv.addEventListener('click', function(e) { Ti.API.info('click at index: ' + e.index); Ti.API.info('clicked row data: ' + e.rowData.title); }) win.add(lv); nav.open();Test Case 3 -// TiUITableView without navigation var rows = []; for (var i = 0; i < 20; i++) { rows.push({ title: 'Row '+ i}); } var win = Ti.UI.createWindow({ title: 'TEST', backgroundColor: '#ffffff', navBarHidden: false }); var sb = Ti.UI.createSearchBar(); var lv = Ti.UI.createTableView({ hideSearchOnSelection: false, data: rows, search: sb, }); sb.setHintText("test"); sb.addEventListener('change', function(e){ Ti.API.info(e.value); }); //when the return key is hit, remove focus from our searchBar sb.addEventListener('return', function(e){ sb.blur(); }); //when the cancel button is tapped, remove focus from our searchBar sb.addEventListener('cancel', function(e){ //sb.blur(); }); lv.addEventListener('click', function(e) { Ti.API.info('click at index: ' + e.index); Ti.API.info('clicked row data: ' + e.rowData.title); }) win.add(lv); win.open();// Tableview with tabbar var rows = []; for (var i = 0; i < 20; i++) { rows.push({ title: 'Row '+ i}); } var win1 = Ti.UI.createWindow({ title: 'TEST', backgroundColor: 'red', navBarHidden: false }); var sb = Ti.UI.createSearchBar(); var lv = Ti.UI.createTableView({ hideSearchOnSelection: false, dimBackgroundForSearch: true, data: rows, search: sb, }); sb.setHintText("test"); sb.addEventListener('change', function(e){ Ti.API.info(e.value); }); //when the return key is hit, remove focus from our searchBar sb.addEventListener('return', function(e){ sb.blur(); }); //when the cancel button is tapped, remove focus from our searchBar sb.addEventListener('cancel', function(e){ //sb.blur(); }); lv.addEventListener('click', function(e) { Ti.API.info('click at index: ' + e.index); Ti.API.info('clicked row data: ' + e.rowData.title); }) win1.add(lv); var win2 = Ti.UI.createWindow({ backgroundColor: 'red', title: 'Red' }); win2.add(Ti.UI.createLabel({text: 'I am a red window.'})); var tab1 = Ti.UI.createTab({ window: win1, title: 'Blue' }), tab2 = Ti.UI.createTab({ window: win2, title: 'Red' }), tabGroup = Ti.UI.createTabGroup({ tabs: [tab1, tab2] }); tabGroup.open();In this PR, Replacement of UISearchDisplayController with UISearchController in TIUIListView and TiUITableView has done. There is major change in TiUITableView and TIUIListView especially with search bar. So need more testing.
Test case ( search bar is not part of list view) -
var win = Ti.UI.createWindow({ backgroundColor: '#fff' }); var list = Ti.UI.createListView({ top: 50, keepSectionsInSearch: true, sections: [Ti.UI.createListSection({ headerTitle:"Line1", items: [{ properties: { title: "I", searchableText: "I", } },{ properties: { title: "Item 2", searchableText: "Item 2", } },{ properties: { title: "Item 3", searchableText: "Item 3", } } ] }), Ti.UI.createListSection({ headerTitle:"Line2", items: [{ properties: { title: "I4", searchableText: "I4", } },{ properties: { title: "Item 5", searchableText: "Item 5", } },{ properties: { title: "Item 6", searchableText: "Item 6", } } ] })] }) list.addEventListener("delete", function(e){ Ti.API.info("Deleted Row Index is is: " +e.itemIndex); Ti.API.info("Deleted Section Index is is: " +e.sectionIndex); }); var searchBar = Ti.UI.createSearchBar({ top:0, height:44, barColor:'#000', showCancel:true, }); searchBar.addEventListener('change', function(e){ list.searchText = e.value; }); searchBar.addEventListener('return', function(e){ searchBar.blur(); }); searchBar.addEventListener('cancel', function(e){ searchBar.blur(); }); win.add(searchBar); win.add(list); win.open();Backported PR (6_2_X) : https://github.com/appcelerator/titanium_mobile/pull/9296. [~hknoechel] Please review. Thanks.
FR Passed, using: MacOS 10.12.6 (16G24b) Studio 4.9.0.201705302345 Ti SDK 7.0.0.v20170802103048 & 6.2.0.v20170810132631 Appc NPM 4.2.9 Appc CLI 6.2.3 Alloy 1.9.13 Xcode 8.3.3 (8E3004b) Tested searchbar functionality when used with listview and tableview. No issues encountered. Tested using the provided sample code as well as the searchbar suite
Verified changes in 6.2.0.v20170811022027 & 7.0.0.v20170811094808