Hi,
I'm using latest continuous build Titanium 3.3.1 (2014/07/25 13:09 3b7fb31). I'm testing on a Nexus 7 Android v4.4.4.
I've been trying to create the "pull to refresh" functionality on a ListView. Ti does not provide a pull to refresh method for Android out of the box. It does for iOS and it works fine.
I'm trying with a ScollView and the touchstart, scroll, touchend events. It's not the best, I know, but I can't find any other solution. The problem I'm facing is that if I set ScrollView.contentHeight = 'auto', the scroll event is not fired (why why why?) . The touchend event is fired but e.y is 0.
If I set contentHeight to 4000 (to say any number), this works fine, but the ListView is cut to 4000.
Here's the code... a complete app.js so you can test it. I had to cut it into several code portions.. This editor did not allow me to paste it into one piece... so... place the whole code into a app.js file.
ANY idea is welcome.
var win = Ti.UI.createWindow({ backgroundColor:'white' }); ///// some functions ... don't worry about this var Global = {}; Global.isAndroid = function(){ return Ti.Platform.osname==='android'; }; Global.isTablet = function(){ var platform = Ti.Platform.osname; switch (platform) { case 'ipad': return true; case 'android': var psc = Ti.Platform.Android.physicalSizeCategory; var tiAndroid = Ti.Platform.Android; return psc === tiAndroid.PHYSICAL_SIZE_CATEGORY_LARGE || psc === tiAndroid.PHYSICAL_SIZE_CATEGORY_XLARGE; default: return Math.min( Ti.Platform.displayCaps.platformHeight, Ti.Platform.displayCaps.platformWidth ) >= 400; } }; var Misc = {}; Misc.dpRatio = function(theValue) { var ratio; if (!Global.isAndroid()){ if (Global.isTablet()){ ratio = 2; }else{ ratio = 1; } }else{ ratio = (Ti.Platform.displayCaps.platformWidth/(Titanium.Platform.displayCaps.dpi / 160))/320; } return (theValue * ratio)+'dp'; }; /////////////////////// // drag pull for Android vars var isChecking = false, offset = 0, checkOffset = 230, pullingOffset = 50, pulling = false, touching = true, reloading = false; /// HEADER var tableHeader = Ti.UI.createView({ backgroundColor: '#aaa', width:Misc.dpRatio(320), height:Misc.dpRatio(60), top:0 }); var border = Ti.UI.createView({ backgroundColor:'transparent', bottom:0, height:Misc.dpRatio(2) }); tableHeader.add(border); var imageArrow = Ti.UI.createImageView({ image:'images/whiteArrow.png', left:Misc.dpRatio(20), bottom:Misc.dpRatio(20), width:Misc.dpRatio(23), height:Misc.dpRatio(23) }); tableHeader.add(imageArrow); var labelStatus = Ti.UI.createLabel({ color:'#576c89', font:{fontSize:Misc.dpRatio(13), fontWeight:'bold'}, text:L('pull_refresh'), textAlign:'center', left:Misc.dpRatio(55), bottom:Misc.dpRatio(30), width:Misc.dpRatio(200) }); tableHeader.add(labelStatus); var labelLastUpdated = Ti.UI.createLabel({ color:'#576c89', font:{fontSize:Misc.dpRatio(12)}, text:'Last Updated: ' + getFormattedDate(), textAlign:'center', left:Misc.dpRatio(55), bottom:Misc.dpRatio(15), width:Misc.dpRatio(200) }); tableHeader.add(labelLastUpdated); var actInd = Ti.UI.createActivityIndicator({ left:Misc.dpRatio(20), bottom:Misc.dpRatio(13), width:Misc.dpRatio(30), height:Misc.dpRatio(30) }); tableHeader.add(actInd); //////////
var myTemplate = { childTemplates: [ { type: 'Ti.UI.View', bindId: 'row' , properties: { backgroundColor:'yellow', height: Ti.UI.SIZE, width: Ti.UI.FILL }, childTemplates: [ { // Image justified left type: 'Ti.UI.ImageView', // Use an image view for the image bindId: 'pic', // Maps to a custom pic property of the item data properties: { // Sets the image view properties width: '50dp', height: '50dp', left: 0 } }, { // Title type: 'Ti.UI.Label', // Use a label for the title bindId: 'info', // Maps to a custom info property of the item data properties: { // Sets the label properties color: 'black', font: { fontFamily:'Arial', fontSize: '20dp', fontWeight:'bold' }, left: '60dp', top: 0, } }, { // Subtitle type: 'Ti.UI.Label', // Use a label for the subtitle bindId: 'es_info', // Maps to a custom es_info property of the item data properties: { // Sets the label properties color: 'gray', font: { fontFamily:'Arial', fontSize: '14dp' }, left: '60dp', top: '25dp', } } ] } ] }; var listView = Ti.UI.createListView({ // Maps myTemplate dictionary to 'template' string templates: { 'template': myTemplate }, //'refreshTemplate': refreshTemplate}, // Use 'template', that is, the myTemplate dict created earlier // for all items as long as the template property is not defined for an item. defaultItemTemplate: 'template' }); var sections = createSections(); listView.setSections(sections); //////////////////////////// var sv = Ti.UI.createScrollView({ top:0, height: Ti.UI.FILL, contentWidth: Ti.UI.FILL, contentHeight: 4000, /// HERE'S THE PROBLEM!!!!! test with 'auto' scrollType: 'vertical', backgroundColor: 'red' }); sv.add(listView); win.add(sv); sv.addEventListener('scroll', scroll); sv.addEventListener('touchstart',touchStart); sv.addEventListener('touchmove',touchMove); sv.addEventListener('touchend',touchEnd); win.open();
// set the initial position of the scrollView's content var init = setInterval(function(e){ if (offset==checkOffset) { //Ti.API.debug('we have just done what the scrollView\'s contentOffset should be doing'); clearInterval(init); } sv.scrollTo(0,checkOffset); },100); function scroll(e){ if (e.y != null){ offset = e.y; } //Ti.API.info('scroll, offset: ' + offset + ' pulling: '+ pulling + ' touching: ' + touching); //var tolerance = 500; //Ti.API.info('near bottom ',sv.getContentHeight(), listView.getRect().height, sv.getRect().height, e.y , (listView.getRect().height - e.y) <= (sv.getRect().height + tolerance)); if (!touching && offset <= checkOffset){ Ti.API.info('not touching'); pullListener({active: false}); stop(); }else if (offset <= pullingOffset && !pulling) { pulling = true; pullListener({active: true}); } else if (pulling && offset > pullingOffset && offset < checkOffset) { pulling = false; pullListener({active: false}); } } function touchStart(e){ //Ti.API.info('touchStart'); touching = true; } function touchMove(e){ //Ti.API.info('touchMove'); touching = true; } function touchEnd(e){ Ti.API.info('touchEnd, offset: '+ offset+ ' pulling: '+ pulling+' reloading: '+ reloading); touching = false; if (offset <= pullingOffset) { if (pulling && !reloading) { reloading = true; pulling = false; reloadTableData(); } } else if (offset < checkOffset){ pulling = false; resetPullHeader(); stop(); } } function stop(){ reloading = false; sv.scrollTo(0,checkOffset); } function reloadTableData() { lastIndex = 0; resetPullHeader(); refresh(); if (Global.isAndroid()) stop(); } function resetPullHeader(){ actInd.hide(); imageArrow.transform=Ti.UI.create2DMatrix(); imageArrow.show(); labelStatus.text = L('pull_refresh'); labelLastUpdated.text = 'Last Updated: ' + getFormattedDate(); } function pullListener(e){ if (e.active == false) { var unrotate = Ti.UI.create2DMatrix(); imageArrow.animate({transform:unrotate, duration:180}); labelStatus.text = L('pull_refresh'); } else { var rotate = Ti.UI.create2DMatrix().rotate(180); imageArrow.animate({transform:rotate, duration:180}); labelStatus.text = 'Release to reload...'; } } function pullendListener(e){ labelStatus.text = 'Loading ...'; imageArrow.hide(); actInd.show(); setTimeout(function(){ reloadTableData(); }, 1000); } //fake function refresh(){ // here you should call your API to get more data Ti.API.info('refreshing'); } function getFormattedDate(){ var date = new Date(); return date.getMonth() + '/' + date.getDate() + '/' + date.getFullYear() + ' ' + date.getHours() + ':' + date.getMinutes(); }
function createSections(){ var sections = []; var refreshSection = Ti.UI.createListSection({headerView: tableHeader}); sections.push(refreshSection); var fruitSection = Ti.UI.createListSection({ headerTitle: 'Fruits / Frutas'}); var fruitDataSet = [ // the text property of info maps to the text property of the title label // the text property of es_info maps to text property of the subtitle label // the image property of pic maps to the image property of the image view { info: {text: 'Apple'}, es_info: {text: 'Manzana afdsfs fdsf sdfdskrmwekrj fdsklfjsdlkfj erlkjewlrkj fsdfj ds sdlfkjdsl wekj fdslkjsd ewrkljlfksd lkjlewkj lkjlkjdslfj ewlj;kfpkf;ds ;sldfk;slkfwe ;lk;l fsdofipores;lrk fsd;lk ;lk ;lk;lk fdsf'}, pic: {image: 'apple.png'}}, { info: {text: 'Banana'}, es_info: {text: 'Banana'}, pic: {image: 'banana.png'}} ]; fruitSection.setItems(fruitDataSet); sections.push(fruitSection); var vegSection = Ti.UI.createListSection({ headerTitle: 'Vegetables / Verduras'}); var vegDataSet = [ { info: {text: 'Carrot'}, es_info: {text: 'Zanahoria'}, pic: {image: 'carrot.png'}}, { info: {text: 'Potato'}, es_info: {text: 'Patata dasklj lkjkljf fjfdskjfdskfj lkjlksdjf kjkfdsjk lewkjr visrjsifjslkj lskjkdjfaltkjakljfksjdtk rlj '}, pic: {image: 'potato.png'}} ]; vegSection.setItems(vegDataSet); sections.push(vegSection); var grainSection = Ti.UI.createListSection({ headerTitle: 'Grains / Granos'}); var grainDataSet = [ { info: {text: 'Corn'}, es_info: {text: 'Maiz'}, pic: {image: 'corn.png'}}, { info: {text: 'Rice'}, es_info: {text: 'Arroz'}, pic: {image: 'rice.png'}} ]; grainSection.setItems(grainDataSet); sections.push(grainSection); var grainSection = Ti.UI.createListSection({ headerTitle: 'Grains / Granos'}); var grainDataSet = [ { info: {text: 'Corn'}, es_info: {text: 'Maiz'}, pic: {image: 'corn.png'}}, { info: {text: 'Rice'}, es_info: {text: 'Arroz'}, pic: {image: 'rice.png'}} ]; grainSection.setItems(grainDataSet); sections.push(grainSection); var grainSection = Ti.UI.createListSection({ headerTitle: 'Grains / Granos'}); var grainDataSet = [ { info: {text: 'Corn'}, es_info: {text: 'Maiz'}, pic: {image: 'corn.png'}}, { info: {text: 'Rice'}, es_info: {text: 'Arroz'}, pic: {image: 'rice.png'}} ]; grainSection.setItems(grainDataSet); sections.push(grainSection); var grainSection = Ti.UI.createListSection({ headerTitle: 'Grains / Granos'}); var grainDataSet = [ { info: {text: 'Corn'}, es_info: {text: 'Maiz'}, pic: {image: 'corn.png'}}, { info: {text: 'Rice'}, es_info: {text: 'Arroz'}, pic: {image: 'rice.png'}} ]; grainSection.setItems(grainDataSet); sections.push(grainSection); var grainSection = Ti.UI.createListSection({ headerTitle: 'Grains / Granos'}); var grainDataSet = [ { info: {text: 'Corn'}, es_info: {text: 'Maiz'}, pic: {image: 'corn.png'}}, { info: {text: 'Rice'}, es_info: {text: 'Arroz'}, pic: {image: 'rice.png'}} ]; grainSection.setItems(grainDataSet); sections.push(grainSection);
var grainSection = Ti.UI.createListSection({ headerTitle: 'Grains / Granos'}); var grainDataSet = [ { info: {text: 'Corn'}, es_info: {text: 'Maiz'}, pic: {image: 'corn.png'}}, { info: {text: 'Rice'}, es_info: {text: 'Arroz'}, pic: {image: 'rice.png'}} ]; grainSection.setItems(grainDataSet); sections.push(grainSection); var grainSection = Ti.UI.createListSection({ headerTitle: 'Grains / Granos'}); var grainDataSet = [ { info: {text: 'Corn'}, es_info: {text: 'Maiz'}, pic: {image: 'corn.png'}}, { info: {text: 'Rice'}, es_info: {text: 'Arroz'}, pic: {image: 'rice.png'}} ]; grainSection.setItems(grainDataSet); sections.push(grainSection); var grainSection = Ti.UI.createListSection({ headerTitle: 'Grains / Granos'}); var grainDataSet = [ { info: {text: 'Corn'}, es_info: {text: 'Maiz'}, pic: {image: 'corn.png'}}, { info: {text: 'Rice'}, es_info: {text: 'Arroz'}, pic: {image: 'rice.png'}} ]; grainSection.setItems(grainDataSet); sections.push(grainSection); var grainSection = Ti.UI.createListSection({ headerTitle: 'Grains / Granos'}); var grainDataSet = [ { info: {text: 'Corn'}, es_info: {text: 'Maiz'}, pic: {image: 'corn.png'}}, { info: {text: 'Rice'}, es_info: {text: 'Arroz'}, pic: {image: 'rice.png'}} ]; grainSection.setItems(grainDataSet); sections.push(grainSection); var grainSection = Ti.UI.createListSection({ headerTitle: 'Grains / Granos'}); var grainDataSet = [ { info: {text: 'Corn'}, es_info: {text: 'Maiz'}, pic: {image: 'corn.png'}}, { info: {text: 'Rice'}, es_info: {text: 'Arroz'}, pic: {image: 'rice.png'}} ]; grainSection.setItems(grainDataSet); sections.push(grainSection); var grainSection = Ti.UI.createListSection({ headerTitle: 'Grains / Granos'}); var grainDataSet = [ { info: {text: 'Corn'}, es_info: {text: 'Maiz'}, pic: {image: 'corn.png'}}, { info: {text: 'Rice'}, es_info: {text: 'Arroz'}, pic: {image: 'rice.png'}} ]; grainSection.setItems(grainDataSet); sections.push(grainSection); var grainSection = Ti.UI.createListSection({ headerTitle: 'Grains / Granos'}); var grainDataSet = [ { info: {text: 'Corn'}, es_info: {text: 'Maiz'}, pic: {image: 'corn.png'}}, { info: {text: 'Rice'}, es_info: {text: 'Arroz'}, pic: {image: 'rice.png'}} ]; grainSection.setItems(grainDataSet); sections.push(grainSection); var grainSection = Ti.UI.createListSection({ headerTitle: 'Grains / Granos'}); var grainDataSet = [ { info: {text: 'Corn'}, es_info: {text: 'Maiz'}, pic: {image: 'corn.png'}}, { info: {text: 'Rice'}, es_info: {text: 'Arroz'}, pic: {image: 'rice.png'}} ]; grainSection.setItems(grainDataSet); sections.push(grainSection); var grainSection = Ti.UI.createListSection({ headerTitle: 'Grains / Granos'}); var grainDataSet = [ { info: {text: 'Corn'}, es_info: {text: 'Maiz'}, pic: {image: 'corn.png'}}, { info: {text: 'Rice'}, es_info: {text: 'Arroz'}, pic: {image: 'rice.png'}} ]; grainSection.setItems(grainDataSet); sections.push(grainSection); var grainSection = Ti.UI.createListSection({ headerTitle: 'Grains / Granos'}); var grainDataSet = [ { info: {text: 'Corn'}, es_info: {text: 'Maiz'}, pic: {image: 'corn.png'}}, { info: {text: 'Rice'}, es_info: {text: 'Arroz'}, pic: {image: 'rice.png'}} ]; grainSection.setItems(grainDataSet); sections.push(grainSection); var grainSection = Ti.UI.createListSection({ headerTitle: 'Grains / Granos'}); var grainDataSet = [ { info: {text: 'Corn'}, es_info: {text: 'Maiz'}, pic: {image: 'corn.png'}}, { info: {text: 'Rice'}, es_info: {text: 'Arroz'}, pic: {image: 'rice.png'}} ]; grainSection.setItems(grainDataSet); sections.push(grainSection);
var grainSection = Ti.UI.createListSection({ headerTitle: 'Grains / Granos'}); var grainDataSet = [ { info: {text: 'Corn'}, es_info: {text: 'Maiz'}, pic: {image: 'corn.png'}}, { info: {text: 'Rice'}, es_info: {text: 'Arroz'}, pic: {image: 'rice.png'}} ]; grainSection.setItems(grainDataSet); sections.push(grainSection); var grainSection = Ti.UI.createListSection({ headerTitle: 'Grains / Granos'}); var grainDataSet = [ { info: {text: 'Corn'}, es_info: {text: 'Maiz'}, pic: {image: 'corn.png'}}, { info: {text: 'Rice'}, es_info: {text: 'Arroz'}, pic: {image: 'rice.png'}} ]; grainSection.setItems(grainDataSet); sections.push(grainSection); var grainSection = Ti.UI.createListSection({ headerTitle: 'Grains / Granos'}); var grainDataSet = [ { info: {text: 'Corn'}, es_info: {text: 'Maiz'}, pic: {image: 'corn.png'}}, { info: {text: 'Rice'}, es_info: {text: 'Arroz'}, pic: {image: 'rice.png'}} ]; grainSection.setItems(grainDataSet); sections.push(grainSection); var grainSection = Ti.UI.createListSection({ headerTitle: 'Grains / Granos'}); var grainDataSet = [ { info: {text: 'Corn'}, es_info: {text: 'Maiz'}, pic: {image: 'corn.png'}}, { info: {text: 'Rice'}, es_info: {text: 'Arroz'}, pic: {image: 'rice.png'}} ]; grainSection.setItems(grainDataSet); sections.push(grainSection); var grainSection = Ti.UI.createListSection({ headerTitle: 'Grains / Granos'}); var grainDataSet = [ { info: {text: 'Corn'}, es_info: {text: 'Maiz'}, pic: {image: 'corn.png'}}, { info: {text: 'Rice'}, es_info: {text: 'Arroz'}, pic: {image: 'rice.png'}} ]; grainSection.setItems(grainDataSet); sections.push(grainSection); return sections; };