What happens if you want the user to be able to refresh the feed data in our table? You could create a regular button, or possibly check for new data at arbitrary time intervals. Alternatively, you could implement a cool 'pull and release' refresh mechanism made very popular by Twitter applications such as Tweetie and Twitter for Android.
In the final recipe for our Recipe Finder app, we will implement the very same type of refresh mechanism for our recipes feed, using the table view's headerPullView
property.
Open your recipes.js
file and type in the following code under the "Ti.include
" statements. This is where will be creating the pull view and adding our user interface components to it, before creating the event listeners that will perform the data request.
//this variable defines whether the user is currently pulling //the refresh mechanism or not var pulling = false; //defines whether we're currently fetching data or not var reloading = false; //let's create our 'pull to refresh' view var tableHeader = Ti.UI.createView({ backgroundImage: 'images/header.png', width:320, height:81 }); var arrowImage = Ti.UI.createView({ backgroundImage:"images/arrow-down.png", width: 40, height: 40, bottom: 20, left:20 }); var statusLabel = Ti.UI.createLabel({ text:"Pull to refresh...", left:85, width:200, bottom:28, height:"auto", color:"#000", textAlign:"center", font:{fontSize:20,fontWeight:"bold"}, shadowColor:"#999", shadowOffset:{x:0,y:1} }); var actInd = Titanium.UI.createActivityIndicator({ left:20, bottom:20, width: 40, height: 40 }); tableHeader.add(actInd); tableHeader.add(arrowImage); tableHeader.add(statusLabel); //define our table view var tblRecipes = Titanium.UI.createTableView({ height: 366, width: 320, top: 0, left: 0, rowHeight: 70, search: searchBar, filterAttribute:'filter' //here is the search filter which //appears in TableViewRow }); //add the header pull view tblRecipes.headerPullView = tableHeader; tblRecipes.addEventListener('scroll',function(e) { var offset = e.contentOffset.y; if (offset <= -80.0 && !pulling) { pulling = true; arrowImage.backgroundImage = 'images/arrow-up.png'; statusLabel.text = "Release to refresh..."; } else if (pulling && offset > -80.0 && offset < 0) { pulling = false; arrowImage.backgroundImage = 'images/arrow-down.png'; statusLabel.text = "Pull to refresh..."; } }); tblRecipes.addEventListener('scrollEnd',function(e) { if (pulling && !reloading && e.contentOffset.y <= -80.0) { reloading = true; pulling = false; arrowImage.hide(); actInd.show(); statusLabel.text = "Reloading recipes..."; tblRecipes.setContentInsets({top:80},{animated:true}); //null out the existing recipe data tblRecipes.data = null; data = []; //open up the recipes xml feed xhr.open('GET', 'http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20feed%20where%20url%3D%22http%3A%2F%2Fwww.cuisine.com.au%2Ffeed%2Fall-recipes%22&format=json&diagnostics=false'), //and fetch it again xhr.send(); } });
Finally, in your xhr.open()
method, we will do a check to see if this is the first time we're loading data or whether this is a reload call made by our "pull and release" mechanism. If it's the latter, we'll hide the header pull view and reset the contents of it back to its original state.
//check to see if we are refreshing the data via our //pull and release mechanism if(reloading == true){ //when done, reset the header to its original style tblRecipes.setContentInsets({top:0},{animated:true}); reloading = false; statusLabel.text = "Pull to refresh..."; actInd.hide(); arrowImage.backgroundImage = 'images/arrow-down.png'; arrowImage.show(); }
What we are doing here can really be broken up into two main components. First, we're creating a header view using standard UI components. Second, we're using events to know when our header view has been 'pulled' down far enough so that we can perform a refresh on our recipes data from the XML/JSON feed.
We know how far the header view has been pulled down via the contentOffset
property of our TableView. In this case, we are executing the refresh of the data when the content offset hits 80px, which is the height of both the header view and also the height of the TableView's data rows from the top of the screen.
Finally, the two variables called pulling
and reloading
are used in conjunction so we can determine the series of steps in our "pull and release" refresh mechanism programmatically:
pulling = true
)pulling = true
and reloading = false
)pulling = false
and reloading = true
)pulling = false
and reloading = false
)18.189.171.125