What you'll need
First of all you need a touch device or a simulator like the iPhone simulator to test your code. The code itself can be written in any text editor, however it is recommended to use an editor with a build in debugger or a test environment that supports debugging JavaScript touch events. You might be thinking that Firebug or Drosera is great for debugging, but how exactly would you trigger the touch events in your desktop browser? Well, you can't. This is why I'm using Dashcode from the iOS SDK for my JavaScript coding. More on using Dashcode in a later post.
Note that this code is written for WebKit based browsers, but should work in principle on other touch browsers as well.
The HTML
<div id="holder">
<div class="content">
your content here
</div>
</div>
Notice that the content is inside of a div within the holder div, this is because you can't scroll the div in which the touch event is attached to.
The CSS
#holder{
width: 300px;
height: 200px;
background-color: blue;
-webkit-box-shadow: 3px 3px 5px #000;
padding: 10px;
}
#holder div{
width:100%;
height:100%;
color: white;
overflow: auto;
-webkit-user-select: none;
}
Not much revolutionary here, but do note that we set the "overflow" property to auto on the content div, not the holder itself. Also, we set the "-webkit-user-select" to "none" on the content div, thereby preventing the user of selecting the content. This is optional.
The JavaScript
There are three main touch events:
- touchstart - Called when a finger touches the listening container (finger down)
- touchmove - Called repeatedly when a finger moves (finger down and moving)
- touchend - Called when a finger leaves the listening container (finger up)
Each of these methods gives us an event with a touches array. Remember, there might be more than one finger since these APIs are made to handle multitouch devices. To get a hold of the vertical position of one finger you would query the touches array for one finger and get it's pageY property, like this:
event.touches[0].pageY
From this we can calculate and set the scrollTop property of the content container. But, wait! If you try this the rest of the page will also scroll, not what we wanted. The reason why this happens is because the touch event bubbles all the way up to the window, making the browser think it needs to scroll the window because you have dragged your finger on it. We need to tell the event to stop bubbling, we will handle the event ourselves. We do this by calling:
event.preventDefault()
The complete JavaScript code will then look something like this:
var startPos;
function init()
{
var scrollArea = document.getElementById('holder');
scrollArea.addEventListener('touchstart', function(event){
touchstartHandler(event);
}, false);
scrollArea.addEventListener('touchmove', function(event){
touchmoveHandler(event);
}, false);
scrollArea.addEventListener('touchend', function(event){
touchendHandler(event);
}, false);
}
function touchstartHandler(e)
{
startPos = e.touches[0].pageY;
}
function touchmoveHandler(e)
{
var touch = e.touches[0];
var targetBox = e.currentTarget.getElementsByTagName("div")[0];
e.preventDefault();
var fingerMoved = startPos - touch.pageY;
startPos = touch.pageY;
targetBox.scrollTop = targetBox.scrollTop + fingerMoved;
}
This is just a simple example, but it's something you'll probably end up using a lot. Speaking of...
When should you override the default window scroll
On an iPhone there is not as much need for this method as you'll probably scroll the entire screen in most cases anyway. However, the iPad is a different story. Take a look at the iPad version of gMail created by Google. They are using this method with success, and they have added inertia scrolling as well. This can be accomplished using the last touch event we did not implement, touchend. Maybe more on this in a later post. Anyway, you should use you own scrolling when it's appropriate to scroll only a part of the app, like a spilt view list or something like that.