Dec 24, 2008

(Android) How to use horizontal scrolling in a ListView

ListView is a widget which shows items in a vertically scrolling list. I figure out a solution to add horizontal scrolling in a ListView. Here is my new object called MyListView, i used OnGestureListener's onScroll methods to manage the horizontal scrolling.


public class MyListView extends LinearLayout implements OnGestureListener {
private GestureDetector mGestureDetector;
private ListView mListView;

public MyListView(Context context) {
super(context);
mGestureDetector = new GestureDetector(this);
mGestureDetector.setIsLongpressEnabled(false);
mListView = new ListView(context);
mListView.setItemsCanFocus(true);
String[] items = createStrins();
mListView.setAdapter(new ArrayAdapter(context, android.R.layout.simple_list_item_single_choice, items));
this.addView(mListView, new LinearLayout.LayoutParams(350, LayoutParams.FILL_PARENT));
}

@Override
public boolean onDown(MotionEvent arg0) {
return false;
}

@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
return true;
}

@Override
public void onLongPress(MotionEvent e) {
//empty
}

@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
int scrollWidth = mListView.getWidth() - this.getWidth();
if ((this.getScrollX() >= 0) && (this.getScrollX() <= scrollWidth) && (scrollWidth > 0)) {
int moveX = (int)distanceX;
if (((moveX + this.getScrollX()) >= 0) && ((Math.abs(moveX) + Math.abs(this.getScrollX())) <= scrollWidth)) {
this.scrollBy(moveX, 0);
}
else {
if (distanceX >= 0) {
this.scrollBy(scrollWidth - Math.max(Math.abs(moveX), Math.abs(this.getScrollX())), 0);
}
else {
this.scrollBy(-Math.min(Math.abs(moveX), Math.abs(this.getScrollX())), 0);
}
}
}
return true;
}

@Override
public void onShowPress(MotionEvent e) {
//empty
}

@Override
public boolean onSingleTapUp(MotionEvent e) {
return false;
}

@Override
public boolean dispatchTouchEvent(MotionEvent ev){
mGestureDetector.onTouchEvent(ev);
return true;
}

private String[] createStrins() {
return new String[] {
"Abbaye de Belloc", "Abbaye du Mont des Cats", "Abertam", "Abondance"};
}
}

11 comments:

Dave Haupert said...

Thanks for posting this- I'm anxious to try it but been having trouble trying to declare this within an XML file. Do you have any tips or a sample project where you do so? I need to have it in an XML file, as the list adaptor I'm using requires it to be there. Thanks in advance!

Nan Hu said...

In your adapter, you should overrie getview method, you can inflate you xml in this method, is that what you want to know?

Dave Haupert said...

Hi Nan,

Thanks for your response!

Isn't the getview inflating done to get the view for an individual row? I'm referring to defining a control for this entire listview class you wrote. In other words, trying not to instantiate the scrollinglistview in code, but via XML. When I do I get an error regarding inflation. All the code I've seen for LayoutInflator seemed to be to get a row item.

Nan Hu said...

In my example, i use an ArrayAdapter to display content, the getView method is in your custom adapter class, you could pass a context reference in your custom adapter to get an layoutinflater, here is an example of getView.

@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = yourinflater.inflate(R.layout.yourlayout, parent, false);
holder = new ViewHolder();
holder.text = (TextView)convertView.findViewById(R.id.itemtext);
convertView.setTag(holder);
} else {
holder = (ViewHolder)convertView.getTag();
}
holder.text.setText(ITEMSTEXTS[position]);
return convertView;
}

private static class ViewHolder {
TextView text;
}

Anonymous said...

Thanks for the posting. I've give it a try but the vertical scrolling seems not working. I added in few more rows which take more spaces than the screen height and it just can't scroll down. Am I missing something?

Nan Hu said...

Try to log something in the OnGestureListener, you can check if the scroll event works.

Anonymous said...

I could not figure out how to use this. could you please pass me the source code.thanks

Nan Hu said...

Hi, with the HorizontalScrollView class, you can put a ListView in HorizontalScrollView to have the horizontal scrolling.

Skogsberg said...
This comment has been removed by the author.
Skogsberg said...

If you do this:
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
mGestureDetector.onTouchEvent(ev);
mListView.dispatchTouchEvent(ev);
return true;
}

scrolling vertically will work aswell.
Putting a ListView inside a HorizontalScrollView will ruin all the optimizations of the ListView, and it will force it to draw all its view instantly. This solution only draws the views that are visible and recycles them.

Anonymous said...

Works beautifully! Any ideas on how to hide the ListViews scrollbar and add vertical and horizontal scrollbars?