Friday, March 22, 2013

Smooth Scrolling List/TableView for Titanium Android

For those who have been using the Titanium TableView UI to render lists, you may have noticed that there is a significant lag on the scroll animation when the number of list items are increased. Most of the time, if there are images on the row, the list becomes choppy and sometimes the application crashes (especially on android).  Since most of the solutions I found only adds minimal improvement on the performance, I just accepted this issue as unresolvable until a titanium sdk update handles this.

However, after using different titanium views for a while, I accidentally discovered a viable alternative to the TableView. After seeing WebViews render lists containing a lot of items with ease, I realized that I can use it as a substitute for my TableViews.

To create a "ListView" type of UI on the WebView, I used the html Table on the code like below: (Please note that I have used Mustache for rendering the data on the html template)

1:  <table border="0" style="width:100%;">  
2:                 {{#table_rows}}  
3:                 <tr onclick="Ti.App.fireEvent('app:handleRowSelect', { index : '{{row_index}}' })">  
4:                      <td>  
5:                           <img src="{{{image_url}}}" style="width:320px; height:240px; position:relative; left:10px; top:5px;"/>  
6:                      </td>  
7:                 </tr>  
8:                 {{/table_rows}}  
9:  </table>   

As you can seen on the code, I just used styles to make the rows look like a list on a TableView.  You can also see that I am firing an event whenever a row is clicked. I'll explain later how it is used.. Here is what the views look like when running on Android tablet:



You can make them look almost exactly the same so the user wouldn't notice that you are indeed using only a WebView instead of a ListView on android.

To simulate the TableView "click" event handler, you must declare an event handler on your application to capture the event fired from your html:

1:  function handleRowSelect(e) {  
2:   alert('You have selected the row with index ' + e.index);  
3:  }  
4:    
5:  Ti.App.addEventListener('app:handleRowSelect', handleRowSelect);  

Whenever the app:handleRowSelect is fired from the HTML, the handleRowSelect function will be called and the event data will be passed as parameters to this function. From the HTML code above, the   Event is fired with an object that contains the index of the row: Ti.App.fireEvent('app:handleRowSelect', { index : '{{row_index}}' }) and from this, you will be able to perform any operation on the data corresponding to the row selected.

You can try and see for yourself the huge performance improvement from using the WebView for large lists on android from here

Thursday, March 7, 2013

Gap Appears on HTML div When Using Titanium Webview on Android



I encountered this irritating bug when using a WebView on my application and I was trying to make a div that has a fixed position on the page. At first I thought I set the styles wrong but a further investigation confirms that a gap is really being generated when displaying the div on the WebView.

After looking a bit on my code I found out that Hardware Acceleration affects the WebView and causes this bug to appear. On my application, the setting (for hardware acceleration) can be found on the /platform/android/AndroidManifest.xml file.

Here is the part where the property is set:

1:  <application android:icon="@drawable/appicon"  
2:            android:hardwareAccelerated="true"   
3:            android:label="AndroidWebViewElemGaps" android:name="AndroidwebviewelemgapsApplication"  
4:            android:debuggable="false">  

Removing this setting fixes the WebView but if you really need hardware acceleration for your app, you are out of luck for the mean time. It's worth noting though that not all devices are affected by this bug. Here is the app running on smartphone without any problems:



Source code for my test project can be found in here.

Monday, February 25, 2013

Titanium Mobile Opening New Window Closes the Application on Android

I encountered this error while testing the application on someone else's Android device. I wondered why the application suddenly crashes whenever I open something on a new window. At first I thought it has something to do with memory allocation errors, but when I checked the logs, it shows nothing. Then finally, when I can't see anything wrong with the code, I checked the device and look for the differences of the device from the one I was using. Finally I saw this checkbox under android Settings -> Developer Options:


Apparently, enabling this setting closes the main activity of the android application even if it is still needed. To prevent this from happening, you need to change the initialization of the new window a bit.

In Titanium Android, when creating a window, setting the property navBarHidden to true will often create a new activity like the code below:

1:  var newWin = Ti.UI.createWindow({  
2:            navBarHidden : true,  
3:            backgroundColor : 'red',  
4:            top : 0,  
5:            left : 0,  
6:            right : 0,  
7:            bottom : 0  
8:       });  

To prevent a new activity from being called, just use the property modal and set it to true like the code below:

1:  var newWin = Ti.UI.createWindow({  
2:            navBarHidden : true,  
3:            backgroundColor : 'blue',  
4:            top : 0,  
5:            left : 0,  
6:            right : 0,  
7:            bottom : 0,  
8:            modal : true  
9:       });  

The full source code for the demo can be see here

Thursday, February 21, 2013

Custom Font on Local Html for Titanium Mobile SDK WebView for Android

While trying to load a locally generated html on the android webview, I noticed that it was not able to render the text content with the custom font face I was using. After some searching, I found out that this issue is not only present on titanium sdk but also from the base android sdk as well (here is the link for the solution on android: Changing Font Face on Android Webview). Using essentially the same approach for the titanium code, here is what I did:

1. Put the font file on the Resource directory of the Titanium project. In here, I am using Airstream.ttf for my custom font face and I placed it in a subfolder named 'fonts' on the Resource folder.

2. Set the css code to use the font face accordingly.
<style type="text/css">
  body {
    font-family:Airstream;
    font-size:20pt;
  }
  @font-face {
     font-family : "Airstream";
     src:url("Airstream.ttf");
  }
</style>

3. On your application code, copy the font file to the directory where your local html (to be rendered on the WebView) will be written. In my code, I just used the default application directory.

1:  var fontFile = Ti.Filesystem.getFile(Ti.Filesystem.resourcesDirectory + 'fonts/', 'Airstream.ttf');  
2:  var fontCopy = Ti.Filesystem.getFile(Ti.Filesystem.applicationDataDirectory, 'Airstream.ttf');  
3:  if (!fontCopy.exists()) {  
4:       fontFile.copy(Ti.Filesystem.applicationDataDirectory + 'Airstream.ttf');  
5:  }  

4. Write the html file in the same directory as the font file and load it on the webview:

1:  var htmlFile = Ti.Filesystem.getFile(Ti.Filesystem.applicationDataDirectory, 'test.html');  
2:  htmlFile.write(htmlContent);  
3:  if (htmlFile.exists()) {  
4:       webView.setUrl(htmlFile.nativePath);  
5:  }  

Here is what it looks like on the device: