5

The goal is to implement a Gallery whose adapter returns ListViews (in other words, vertically scrolling ListViews embedded in a horizontally scrolling Gallery). It sort of works after a bit of work, but when attempting to scroll horizontally, the ListView looks very jittery, like there is some stickiness to it being centered. I have not observed this kind of behavior with any other type of View embedded in a Gallery.

Here is what I have tried:

Initially, I found that the ListView squashed touch events, so the gesture listener on the Gallery never gets fired.

So in the onCreate() method of the Activity, I created a GestureDetector:

galleryGestureDetector = new GestureDetector(this, gallery);

Then, inside the getView() method of the Gallery adapter, after the ListView has been inflated and configured, I have some code like this:

listView.setOnTouchListener(new OnTouchListener() {
    public boolean onTouch(View v, MotionEvent event) {
        galleryGestureDetector.onTouchEvent(event);
        return true;
    }
});

In this case I have even gone to the extreme step of returning true from the OnTouchListener to ensure that the onTouchEvent() method of the listView is never actually called. The same jittery behavior occurs. As a result, I think I can rule out competing onTouchEvent() implementations between the two views.

I tried abusing the TouchDelegate concept as well by extending the Gallery's touch rectangle to include the ListView and then forcing the ListView to delegate to it, but this was a futile effort as well.

I would throw up my hands and say it isn't possible currently, but the Social Networking app that packs with the DroidX somehow accomplishes it!

Jonathan Schneider
  • 26,852
  • 13
  • 75
  • 99
  • Maybe check that your list views aren't creating/inflating tons of views each time the gallery is rendered. Try caching them (or just using a single static field) just to see if that is the problem. – sksamuel Jan 02 '11 at 00:28
  • Good thought monkjack, and indeed, it looks like the Gallery was recycling the ListViews returned from its adapter after they went out of selection. I tried caching the views like you suggested and verified that of the 3 elements I am using to test solutions to this issue that only 3 views are ever inflated. Unfortunately, I see the same result... After the view slides over a small amount, it starts jittering like crazy. – Jonathan Schneider Jan 02 '11 at 02:07
  • Even more mysterious -- I noticed today that if I continue to try to scroll horizontally after the ListView starts jittering, the Gallery will sometimes get stuck between two Views. – Jonathan Schneider Jan 02 '11 at 19:34
  • If the Gallery Adapter returns a vertically oriented LinearLayout composed of a TextView and the ListView, the jittering behavior only occurs when you start dragging on the ListView. The animation is smooth if you start dragging on the TextView?!! – Jonathan Schneider Jan 02 '11 at 23:12
  • I have noticed that onInterceptTouchEvent is called on the ListView when the touch is started on the ListView, but not when the touch is started on the TextView... I wonder if this might be a contributing factor. – Jonathan Schneider Jan 03 '11 at 00:55
  • Look at this answer http://stackoverflow.com/a/5289219 –  Jan 04 '12 at 13:34

1 Answers1

5

The problem is that ListView is intercepting touch events from the Gallery and then altering the view position itself. This is what leads to the back and forth jittering effect that I see when I use the widgets as is. I consider this a bug in the Gallery widget, but in the meantime it can be fixed by subclassing Gallery like this:

public class BetterGallery extends Gallery {
private boolean scrollingHorizontally = false;

public BetterGallery(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
}

public BetterGallery(Context context, AttributeSet attrs) {
    super(context, attrs);
}

public BetterGallery(Context context) {
    super(context);
}

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    super.onInterceptTouchEvent(ev);
    return scrollingHorizontally;
}

@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
    scrollingHorizontally = true;
    return super.onScroll(e1, e2, distanceX, distanceY);
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    switch(event.getAction()) {
    case MotionEvent.ACTION_UP:
    case MotionEvent.ACTION_CANCEL:
        scrollingHorizontally = false;
    }

    return super.onTouchEvent(event);
}

}

If you use BetterGallery in place of Gallery, the whole thing works just fine!

Jonathan Schneider
  • 26,852
  • 13
  • 75
  • 99