title: Android ListView - stop scrolling at 'whole' row position
body: <p>Sorry for the confusing title, I cannot express the problem very concisely...</p>
  <p>I have an Android app with a ListView that uses a circular / &quot;infinite&quot; adapter, which basically means I can scroll it up or down as much as I want and the items will wrap around when it reaches the top or bottom, making it seem to the user as if he is spinning an infinitely long list of (~100) repeating items.</p>
  <p>The point of this setup is to let the user select a random item, simply by spinning / flinging the listview and waiting to see where it stops. I decreased the friction of the Listview so it flings a bit faster and longer and this seems to work really nice. Finally I placed a partially transparent image on top of the ListView to block out the top and bottom items (with a transition from transparent to black), making it seem as if the user is &quot;selecting&quot; the item in the middle, as if they were on a rotating &quot;wheel&quot; that they control by flinging.</p>
  <p>There is one obvious problem: after flinging the ListView does not stop at a particular item, but it can stop hovering between two items (where the first visible item is then only partially shown). I want to avoid this because in that case it is not obvious which item has been &quot;randomly selected&quot;.</p>
  <p>Long story short: after the ListView has finished scrolling after flinging, I want it to stop on a &quot;whole&quot; row, instead of on a partially visible row.</p>
  <p>Right now I implemented this behavior by checking when the scrolling has stopped, and then selecting the first visible item, as such:</p>
  <pre><code>    lv = this.getListView();
      
      lv.setFriction(0.005f);
      lv.setOnScrollListener(new OnScrollListener() {
          public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {}
  
          public void onScrollStateChanged(AbsListView view, int scrollState) {
              if (scrollState == OnScrollListener.SCROLL_STATE_IDLE) 
              {
                  if (isAutoScrolling) return;
                  
                  isAutoScrolling = true;
                  int pos = lv.getFirstVisiblePosition();
                  lv.setSelection(pos);
                  isAutoScrolling = false;
              }
          }
      });
  </code></pre>
  <p>This works reasonably well, apart from one glaringly obvious problem... The first visible item might only be visible for a pixel or two. In that case, I want the ListView to jump &quot;up&quot; for those two pixels so that the <em>second</em> visible item is selected. Instead, of course, the first visible item is selected which means the ListView jumps &quot;down&quot; almost an entire row (minus those two pixels).</p>
  <p>In short, instead of jumping to the first visible item, I want it to jump to the item that is visible the most. If the first visible item is less than half visible, I want it to jump to the second visible item.</p>
  <p>Here's an illustration that hopefully conveys my point. The left most ListView (of each pair) shows the state after flinging has stopped (where it comes to a halt), and the right ListView shows how it looks after it made the &quot;jump&quot; by selecting the first visible item. On the left I show the current (wrong) situation: Item B is only barely visible, but it is still the first visible item so the listView jumps to select that item - which is not logical because it has to scroll almost an entire item height to get there. It would be much more logical to scroll to Item C (which is depicted on the right) because that is &quot;closer&quot;.</p>
  <p><a href="https://i.stack.imgur.com/b19Pn.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/b19Pn.jpg" alt="Image" /></a><br />
  <sub>(source: <a href="http://nickthissen.nl/Images/lv.jpg" rel="nofollow noreferrer">nickthissen.nl</a>)</sub></p>
  <p>How can I achieve this behavior? The only way I can think of is to somehow measure how much of the first visible item is visible. If that is more than 50%, then I jump to that position. If it is less than 50%, I jump to that position + 1. However I have no clue how to measure that...</p>
  <p>Any idea's?</p>