Creating a "pull and release" refresh mechanism

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.

Note

Complete source code for this recipe can be found in the /Chapter 2/Recipe 9 folder, while the complete source code for this entire chapter can be found in the /Chapter 2/RecipeFinder folder.

How to do it...

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();
}

How it works...

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:

  1. When the TableView is being pulled down by the user, using a tap and hold gesture (pulling = true)
  2. When the TableView has finished pulling but has not yet started to reload the data from our remote data source (pulling = true and reloading = false)
  3. When our pulling has completed but we are waiting for the data to finish being returned from our remote data source (pulling = false and reloading = true)
  4. Finally, when our remote data source has finished streaming the required data and the header pull view can be closed, and the scrolling offset of our table can return to normal (pulling = false and reloading = false)
    How it works...
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.189.171.125