This type of view is fairly common in the mobile world, but doesn’t come out of the box with the Android SDK. Think of the home screen(s) on an Android device. You can slide between each home screen and when you lift your finger, it “snaps” to the most appropriate screen. This is fairly simple to build yourself using the existing HorizontalScrollView (or regular ScrollView for vertical scrolling) and adding some code on top of it to handle snapping to each screen. In this post, I’ll show you how I implemented this view for a rotating article feature. Continue reading
Author Archives: Joel Douglass
44 Responses to "Android: Creating a “Snapping” Horizontal Scroll View"
Leave a Reply:
44 Responses to "Android: Creating a “Snapping” Horizontal Scroll View"
-
Thankyou for this!
I had been searching for an example on how to implement this.
I expected it to be pretty straight forward, and am happy to see it is. -
P.S. I was having a strange issue with the GestureDetector not working.
Turned out it was a silent “NullPointerException” being thrown in onFling().
The e1 MotionEvent was always null.. not sure why, doesn’t matter.
since I just modified the 2 if statements to have this.
if (velocityX SWIPE_THRESHOLD_VELOCITY)
{
…
}
else if (velocityX > 0 && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY)
{
…
}Works like a charm!!
-
Is this not the exact behaviour of android.widget.Gallery ?
-
the projects zip would be nice :)
-
Gallery is somewhat limited in that all the child views have to be the same size. I’m working on backing your view with an adapter like a listview so that views can be recycled. In your examples you have pretty lightweight views, but I’d like to load heavier views and loading 30-40 of them like above would not be feasible memory wise.
-
As people have noted this can be done with a Gallery (and I’ve just done this actually :) )
To get the snapping you override the gallery’s onFling event and, instead of passing the events to super.onFling, you drop the motionevents and instead fake an onKeyPress event with the left / right dpad keys.
This also stops the weird bounce animation effect gallery has, and stops the user from being able to fling their way through more than one view at a time :)
-
I’m new to Android development, and this post is exactly what I’m trying to do, but I’m having trouble figuring out how to set up the layout xmls and also the array for the articles. Can anyone offer some guidance in these areas? Thanks in advance for any assistance.
-
Gallery still doesn’t recycle views, you’ll notice that it’s always passing a null view to the adapter on getView. For lightweight views no problem. I’ve taken your implementation and added view recycling. Once I clean this up I’ll post it for others.
-
Looks like the 2.2 Gallery has implemented recycling, but on 2.1 devices you’re stuck with the old implementation. Also, Gallery is dropping the views off screen which in the case of a widget like we are after here, nothing is being kept on either side of the displayed view because those are ‘off-screen’.
On another note, I’m also seeing that onFling is always being passed null for the first motion event. There are sporadic reports of this on SO and the google group, but no real solutions. Something is intercepted it somewhere in the stack and mucking with it.
-
Hey,
could you post a whole example and not just your class file? would be really helpful for me!
-
Hi
Thank you for your great example. project zip would really be very nice, or you maybe can at least help me with one thing.as soon as I put textViews inside, everything works fine, but actually I need custom component to be in the horizontal view.
I fail trying to draw only one simple rectangle in fullscreen mode, with 10px margin from the edge of screen. I can only do it in first “page” but it never scrolls to another page.
in my application, only first screen is always drawn, although I put different canvas.drawText to each sub-view.
I would really appreciate, if you could help me with that
Thanks a lot
Marek
-
Would really appreciate it if you could make this a zipped project which can be downloaded.
I’m trying to implement a “gallery like” view, but correct me if I’m wrong but from what I can gather you cannot have different layouts per view. This sample code would be very helpful for me to implement it.
-
@Jonathan Have you finished your version with view recycling? Would love to see it if you have.
-
I’m having an issue with getting the onFling to work as described in this example. I’ve discovered, that in order for the more advanced gestures to work, one needs to consume the onDown event.
In this case it means that one needs to override the onDown in the custom MyGestureDetector and always return true.
Altogether the solution is lovely, thank you very much. I had troubles making the default Gallery widget work with downloadable content and here I can limit the amount amount amount amount amount amount amount user can move until the content gets downloaded.
-
But you don’t write an xml android file?
-
It works fine ,thank u.But if I scroll 20% then it does not move to the next image .then how to do this.
-
I am new to Android and Java, please could you tell me how I use this class in an Android project. This is just what I am looking for.
Thanks -
Hi
I have been looking around for something like this. How do I implement it? I’m new to this type of coding so not sure where to put it and how to link it? Thanks from a novice :) -
Great work. I’ve incorporate the scroll logic. However, on my phone, smoothScrollTo doesn’t always work. By that, I mean that there are times when ACTION_UP is called, the code correctly computes the next page to scroll to (as per the log), but smoothScrollTo() doesn’t scroll all the way to the next page.
I’m running Android 2.2 on an LG Optimus. Any one else have this problem?
-
Ah nevermind. I was forgetting to return true when catching ACTION_UP events. It seems that if you return false, the child views (or something else) interferes with the scrolling.
-
This works amazing!
Anybody has an idea how to set the position to a certain x-position? -
It’s been a great article. Very very helpful in quest of what I wanted to achieve. Thanks man!
-
very helpful code mate thanks
-
hey mate, when I add this to an activity in a tabhost, the content is flushed out every time I change the activity view back and forth, you any idea why that might be happening?
-
Android’s Gallery Widget has a lot of limitations and features that you need to get rid of in order to implement this behavior consistently. I have extended Gallery successfully for a widget I had created before, but I needed to create another “snapping” widget that made more sense as a ScrollView, and your article helped me a lot. It’s working very well and a ScrollView is a lot easier to extend and work with than the Gallery (e.g. no Adapters needed).
So thanks for this — very useful!
-
Very helpful, and better than Gallery for various reasons. For my particular layout adding the Views via xml & changing the layout width to DispayMetrics.widthPixels programmatically worked a little better. In any case, I owe you a beer!
-
I was tweaking away, googling, etc. And I came across this:
http://android-developers.blogspot.com/2011/08/horizontal-view-swiping-with-viewpager.htmlSeems the way to go
-
Can anybody post a full version of code here, not just the class ?
-
Would u please give me an example for this part of the code:
for(int i = 0; i< items.size();i++){
LinearLayout featureLayout = (LinearLayout) View.inflate(this.getContext(),R.layout.unlocked_page,null);
//…//Create the view for each screen in the scroll view
//…
internalWrapper.addView(featureLayout);
}'Coz I didn't understand how it works… Firstly, we defined "private ArrayList mItems = null;" and we never changed it, or at least i didn't get what we need to do over there, how we can use it… I just got little bit confused :/ Thanks in advance
-
We used a Gallery for Android TweetDeck.
I also had to do some further magic to ensure that the list views could still scroll vertically. Took days reading the Android sources to figure out how.
-
Update on the silent null exception where e1 is null:
I was getting this too – a quick google implies that it is caused by having an onclick listener on a child of the scrollable view which is trying to highjack one of the gestures.
It looks like this is negatively affecting the scrolling experience – right to left SWIPES are not working – only drags to 50%.
I have not been able to find a fix to this problem. Any chance you could take a look?
All the best and thanks for this code!
Max. -
Big Thanks for this article. Maybe you can achieve similar behavior with Gallery-solution but then you can’t (well, you can, but it is way more complicated) use scrollable views so the Gallery-solution is completely useless when talking about lists or grids. When you want to swipe between several lists or grids or ScrollViews, then this solution is definitely easier.
-
project code for this example is more useful please share zip file
-
yes, share project archive please
-
Android viewPager/ viewfliper is the good replacement for this… like google play
-
where is the xml part?
-
Hi Joel,
First, congratulations for this post, very intersting, i was searching for this a while. Can you give all your project ? For example ArticleListItem and the layout xml. I need run and adapter to my project. I cant run this example, i make some modifications, but isn´t the same result.
Thanks
Daniel Leite -
The scrolling behavior with this code works beautifully. And this is still relevant as the Gallery has been deprecated. Thank you! For other newbies like me who need to figure out how to put together all the pieces there is some code at androidprogrammingmadeeasy.blogspot.com/2011/08/creating-custom-horizontal-scroll-view.html (though I recommend the code in this blog for the onTouch and onFling events).
-
hi
thank a lote
i used your code
god bless you -
hi
i found a simpler and native built-in method for snapping pages : using viewpager http://architects.dzone.com/articles/android-tutorial-using
Thankyou for this!
I had been searching for an example on how to implement this.
I expected it to be pretty straight forward, and am happy to see it is.
P.S. I was having a strange issue with the GestureDetector not working.
Turned out it was a silent “NullPointerException” being thrown in onFling().
The e1 MotionEvent was always null.. not sure why, doesn’t matter.
since I just modified the 2 if statements to have this.
if (velocityX SWIPE_THRESHOLD_VELOCITY)
{
…
}
else if (velocityX > 0 && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY)
{
…
}
Works like a charm!!
Shane,
Thanks for your feedback. I am not seeing the NullPointerException, so I’m not sure what could be going on there without digging in further. Either way, that shouldn’t be a silent failure, so I updated the code to at the minimum write to the log!
Is this not the exact behaviour of android.widget.Gallery ?
the projects zip would be nice :)
@chrisschell: I haven’t used it, but you’re right. It looks like the android.widget.Gallery would most likely serve this same purpose. Thanks for pointing this out, I’m not sure how it was missed!
Gallery is somewhat limited in that all the child views have to be the same size. I’m working on backing your view with an adapter like a listview so that views can be recycled. In your examples you have pretty lightweight views, but I’d like to load heavier views and loading 30-40 of them like above would not be feasible memory wise.
As people have noted this can be done with a Gallery (and I’ve just done this actually :) )
To get the snapping you override the gallery’s onFling event and, instead of passing the events to super.onFling, you drop the motionevents and instead fake an onKeyPress event with the left / right dpad keys.
This also stops the weird bounce animation effect gallery has, and stops the user from being able to fling their way through more than one view at a time :)
I’m new to Android development, and this post is exactly what I’m trying to do, but I’m having trouble figuring out how to set up the layout xmls and also the array for the articles. Can anyone offer some guidance in these areas? Thanks in advance for any assistance.
Gallery still doesn’t recycle views, you’ll notice that it’s always passing a null view to the adapter on getView. For lightweight views no problem. I’ve taken your implementation and added view recycling. Once I clean this up I’ll post it for others.
Looks like the 2.2 Gallery has implemented recycling, but on 2.1 devices you’re stuck with the old implementation. Also, Gallery is dropping the views off screen which in the case of a widget like we are after here, nothing is being kept on either side of the displayed view because those are ‘off-screen’.
On another note, I’m also seeing that onFling is always being passed null for the first motion event. There are sporadic reports of this on SO and the google group, but no real solutions. Something is intercepted it somewhere in the stack and mucking with it.
Hey,
could you post a whole example and not just your class file? would be really helpful for me!
Hi
Thank you for your great example. project zip would really be very nice, or you maybe can at least help me with one thing.as soon as I put textViews inside, everything works fine, but actually I need custom component to be in the horizontal view.
I fail trying to draw only one simple rectangle in fullscreen mode, with 10px margin from the edge of screen. I can only do it in first “page” but it never scrolls to another page.
in my application, only first screen is always drawn, although I put different canvas.drawText to each sub-view.
I would really appreciate, if you could help me with that
Thanks a lot
Marek
Would really appreciate it if you could make this a zipped project which can be downloaded.
I’m trying to implement a “gallery like” view, but correct me if I’m wrong but from what I can gather you cannot have different layouts per view. This sample code would be very helpful for me to implement it.
@Jonathan Have you finished your version with view recycling? Would love to see it if you have.
I’m having an issue with getting the onFling to work as described in this example. I’ve discovered, that in order for the more advanced gestures to work, one needs to consume the onDown event.
In this case it means that one needs to override the onDown in the custom MyGestureDetector and always return true.
Altogether the solution is lovely, thank you very much. I had troubles making the default Gallery widget work with downloadable content and here I can limit the amount amount amount amount amount amount amount user can move until the content gets downloaded.
But you don’t write an xml android file?
It works fine ,thank u.But if I scroll 20% then it does not move to the next image .then how to do this.
I am new to Android and Java, please could you tell me how I use this class in an Android project. This is just what I am looking for.
Thanks
Hi
I have been looking around for something like this. How do I implement it? I’m new to this type of coding so not sure where to put it and how to link it? Thanks from a novice :)
Great work. I’ve incorporate the scroll logic. However, on my phone, smoothScrollTo doesn’t always work. By that, I mean that there are times when ACTION_UP is called, the code correctly computes the next page to scroll to (as per the log), but smoothScrollTo() doesn’t scroll all the way to the next page.
I’m running Android 2.2 on an LG Optimus. Any one else have this problem?
Ah nevermind. I was forgetting to return true when catching ACTION_UP events. It seems that if you return false, the child views (or something else) interferes with the scrolling.
This works amazing!
Anybody has an idea how to set the position to a certain x-position?
It’s been a great article. Very very helpful in quest of what I wanted to achieve. Thanks man!
very helpful code mate thanks
hey mate, when I add this to an activity in a tabhost, the content is flushed out every time I change the activity view back and forth, you any idea why that might be happening?
Android’s Gallery Widget has a lot of limitations and features that you need to get rid of in order to implement this behavior consistently. I have extended Gallery successfully for a widget I had created before, but I needed to create another “snapping” widget that made more sense as a ScrollView, and your article helped me a lot. It’s working very well and a ScrollView is a lot easier to extend and work with than the Gallery (e.g. no Adapters needed).
So thanks for this — very useful!
Very helpful, and better than Gallery for various reasons. For my particular layout adding the Views via xml & changing the layout width to DispayMetrics.widthPixels programmatically worked a little better. In any case, I owe you a beer!
I was tweaking away, googling, etc. And I came across this:
http://android-developers.blogspot.com/2011/08/horizontal-view-swiping-with-viewpager.html
Seems the way to go
Can anybody post a full version of code here, not just the class ?
Would u please give me an example for this part of the code:
for(int i = 0; i< items.size();i++){
LinearLayout featureLayout = (LinearLayout) View.inflate(this.getContext(),R.layout.unlocked_page,null);
//…
//Create the view for each screen in the scroll view
//…
internalWrapper.addView(featureLayout);
}
'Coz I didn't understand how it works… Firstly, we defined "private ArrayList mItems = null;" and we never changed it, or at least i didn't get what we need to do over there, how we can use it… I just got little bit confused :/ Thanks in advance
We used a Gallery for Android TweetDeck.
I also had to do some further magic to ensure that the list views could still scroll vertically. Took days reading the Android sources to figure out how.
Update on the silent null exception where e1 is null:
I was getting this too – a quick google implies that it is caused by having an onclick listener on a child of the scrollable view which is trying to highjack one of the gestures.
It looks like this is negatively affecting the scrolling experience – right to left SWIPES are not working – only drags to 50%.
I have not been able to find a fix to this problem. Any chance you could take a look?
All the best and thanks for this code!
Max.
Pingback: HorizontalScrollView does not show children?
Big Thanks for this article. Maybe you can achieve similar behavior with Gallery-solution but then you can’t (well, you can, but it is way more complicated) use scrollable views so the Gallery-solution is completely useless when talking about lists or grids. When you want to swipe between several lists or grids or ScrollViews, then this solution is definitely easier.
project code for this example is more useful please share zip file
yes, share project archive please
Pingback: Android: Adding Layouts to HorizontalScrollView | Software development support, software risk,bugs for bugs, risk analysis,
Android viewPager/ viewfliper is the good replacement for this… like google play
where is the xml part?
Hi Joel,
First, congratulations for this post, very intersting, i was searching for this a while. Can you give all your project ? For example ArticleListItem and the layout xml. I need run and adapter to my project. I cant run this example, i make some modifications, but isn´t the same result.
Thanks
Daniel Leite
The scrolling behavior with this code works beautifully. And this is still relevant as the Gallery has been deprecated. Thank you! For other newbies like me who need to figure out how to put together all the pieces there is some code at androidprogrammingmadeeasy.blogspot.com/2011/08/creating-custom-horizontal-scroll-view.html (though I recommend the code in this blog for the onTouch and onFling events).
hi
thank a lote
i used your code
god bless you
hi
i found a simpler and native built-in method for snapping pages : using viewpager http://architects.dzone.com/articles/android-tutorial-using