Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Here's my attempt at gallery that works with vertical <code>ScrollViews</code>.</p> <p>It uses its own instance of <code>GestureDetector</code> and feeds it with <code>MotionEvents</code> from <code>onInterceptTouchEvent</code>. </p> <p>When gesture detector recognizes a scroll, we determine whether it's horizontal or vertical and lock on the direction until the gesture is finished. This avoids diagonal scrolling. </p> <p>If it's a horizontal scroll, <code>onInterceptTouchEvent</code> will return true so that future motion events go to inherited <code>Gallery.onTouchEvent</code> to do the actual scrolling.</p> <p><code>Gallery</code>'s own gesture detector (<code>mGestureDetector</code> in <code>Gallery.java</code>) doesn't get all motion events and thus sometimes reports huge sudden scrolls that cause gallery to jump around. I've put in a a nasty hack that discards those. </p> <p>The code:</p> <pre><code>import android.content.Context; import android.util.AttributeSet; import android.view.GestureDetector; import android.view.MotionEvent; import android.widget.Gallery; public class BetterGallery extends Gallery { /* This gets set when we detect horizontal scrolling */ private boolean scrollingHorizontally = false; /* This gets set during vertical scrolling. We use this to avoid detecting * horizontal scrolling when vertical scrolling is already in progress * and vice versa. */ private boolean scrollingVertically = false; /* Our own gesture detector, Gallery's mGestureDetector is private. * We'll feed it with motion events from `onInterceptTouchEvent` method. */ private GestureDetector mBetterGestureDetector; public BetterGallery(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); mBetterGestureDetector = new GestureDetector(new BetterGestureListener()); } public BetterGallery(Context context, AttributeSet attrs) { super(context, attrs); mBetterGestureDetector = new GestureDetector(new BetterGestureListener()); } public BetterGallery(Context context) { super(context); mBetterGestureDetector = new GestureDetector(new BetterGestureListener()); } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { // Limit velocity so we don't fly over views return super.onFling(e1, e2, 0, velocityY); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { // Documentation on this method's contract: // http://developer.android.com/reference/android/view/ViewGroup.html#onInterceptTouchEvent(android.view.MotionEvent) // Reset our scrolling flags if ACTION_UP or ACTION_CANCEL switch (ev.getAction()) { case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: scrollingHorizontally = false; scrollingVertically = false; } // Feed our gesture detector mBetterGestureDetector.onTouchEvent(ev); // Intercept motion events if horizontal scrolling is detected return scrollingHorizontally; } @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { // Hack: eat jerky scrolls caused by stale state in mGestureDetector // which we cannot directly access if (Math.abs(distanceX) &gt; 100) return false; return super.onScroll(e1, e2, distanceX, distanceY); } @Override public boolean onTouchEvent(MotionEvent event) { // Reset our scrolling flags if ACTION_UP or ACTION_CANCEL switch(event.getAction()) { case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: scrollingHorizontally = false; scrollingVertically = false; } super.onTouchEvent(event); return scrollingHorizontally; } private class BetterGestureListener implements GestureDetector.OnGestureListener { @Override public boolean onDown(MotionEvent arg0) { return false; } @Override public boolean onFling(MotionEvent arg0, MotionEvent arg1, float arg2, float arg3) { return false; } @Override public void onLongPress(MotionEvent arg0) { } @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { if (scrollingHorizontally || scrollingVertically) { // We already know we're scrolling, ignore this callback. // This avoids changing scrollingHorizontally / scrollingVertically // flags mid-scroll. return false; } scrollingHorizontally |= Math.abs(distanceX) &gt; Math.abs(distanceY); // It's a scroll, and if it's not horizontal, then it has to be vertical scrollingVertically = !scrollingHorizontally; return false; } @Override public void onShowPress(MotionEvent arg0) { } @Override public boolean onSingleTapUp(MotionEvent arg0) { return false; } } } </code></pre> <p>Warning: word "Better" in class name is likely misleading!</p> <p><strong>Update:</strong></p> <p>Forgot to mention, I've also set the activity to forward its <code>onTouchEvent</code> to gallery:</p> <pre><code>@Override public boolean onTouchEvent(MotionEvent event) { return mGallery.onTouchEvent(event); } </code></pre> <p><strong>Update 2:</strong></p> <p>I've made some improvements to this code and put it up on <a href="https://bitbucket.org/cuu508/friendlygallery" rel="nofollow noreferrer">bitbucket</a>. There's also an example app. It demonstrates that this widget has issues with ListView as child :-/</p> <p><img src="https://i.stack.imgur.com/qx2Cx.png" alt="enter image description here"></p> <p><strong>Update 3:</strong></p> <p>Switched from <code>Gallery</code> to <code>HorizontalScrollView</code> as the base class for my custom widget. <a href="http://cuu508.wordpress.com/2011/07/20/horizontal-scrolling-widget-based-on-horizontalscrollview/" rel="nofollow noreferrer">More on this here</a>. Flings work, ListViews and ExpandableListViews as children work, tested on Android 1.6, 2.2, 2.3.4. Its behaviour is now quite close to that of Google apps, IMO.</p> <p><strong>Update 4:</strong></p> <p>Google has published <a href="http://android-developers.blogspot.com/2011/08/horizontal-view-swiping-with-viewpager.html" rel="nofollow noreferrer">ViewPager</a>!</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload