Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p><strong>Rewrite</strong></p> <p>I didn't have much luck with passing the scrolling actions in one ListView to another. So I chose a different method: passing the <code>MotionEvent</code>. This lets each <code>ListView</code> calculate their own smooth scroll, fast scroll, or anything else.</p> <p><strong>First,</strong> we'll need some class variables:</p> <pre><code>ListView listView; ListView listView2; View clickSource; View touchSource; int offset = 0; </code></pre> <p>Every method that I add to <code>listView</code> will be almost identical for <code>listView2</code>, the only difference is that <code>listView2</code> will reference <code>listView</code> (not itself). I didn't include the repetitive <code>listView2</code> code.</p> <p><strong>Second,</strong> let's start with the OnTouchListener:</p> <pre><code>listView = (ListView) findViewById(R.id.engNameList); listView.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { if(touchSource == null) touchSource = v; if(v == touchSource) { listView2.dispatchTouchEvent(event); if(event.getAction() == MotionEvent.ACTION_UP) { clickSource = v; touchSource = null; } } return false; } }); </code></pre> <p>To prevent circular logic: <code>listView</code> calls <code>listView2</code> calls <code>listView</code> calls... I used a class variable <code>touchSource</code> to determine when a <code>MotionEvent</code> should be passed. I assumed that you don't want a row click in <code>listView</code> to also click in <code>listView2</code>, so I used another class variable <code>clickSource</code> to prevent this. </p> <p><strong>Third,</strong> the OnItemClickListener:</p> <pre><code>listView.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView&lt;?&gt; parent, View view, int position, long id) { if(parent == clickSource) { // Do something with the ListView was clicked } } }); </code></pre> <p><strong>Fourth,</strong> passing every touch event isn't perfect because occasional discrepancies appear. The OnScrollListener is perfect for eliminating these:</p> <pre><code>listView.setOnScrollListener(new OnScrollListener() { @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { if(view == clickSource) listView2.setSelectionFromTop(firstVisibleItem, view.getChildAt(0).getTop() + offset); } @Override public void onScrollStateChanged(AbsListView view, int scrollState) {} }); </code></pre> <p><strong>(Optional) Lastly,</strong> you mentioned that you have trouble since <code>listView</code> and <code>listView2</code> begin at different heights in your layout... I <strong>highly</strong> recommend modifying your layout to balance the ListViews, but I found a way to address this. However it is a little tricky.<br> You cannot calculate the difference in height between the two layouts until after the entire layout have been rendered, but there is no callback for this moment... so I use a simple handler:</p> <pre><code>Handler handler = new Handler() { @Override public void handleMessage(Message msg) { // Set listView's x, y coordinates in loc[0], loc[1] int[] loc = new int[2]; listView.getLocationInWindow(loc); // Save listView's y and get listView2's coordinates int firstY = loc[1]; listView2.getLocationInWindow(loc); offset = firstY - loc[1]; //Log.v("Example", "offset: " + offset + " = " + firstY + " + " + loc[1]); } }; </code></pre> <p>I <em>assume</em> that a half second delay is long enough to render the layout and start the timer in <code>onResume()</code>:</p> <pre><code>handler.sendEmptyMessageDelayed(0, 500); </code></pre> <p>If you do use an offset I want to be clear that <code>listView2</code>'s OnScroll method subtracts the offset rather than adds it:</p> <pre><code>listView2.setSelectionFromTop(firstVisibleItem, view.getChildAt(0).getTop() - offset); </code></pre> <p>Hope that helps!</p>
 

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