Rewrite
I didn't have much luck with passing the scrolling actions in one ListView to another. So I chose a different method: passing the MotionEvent
. This lets each ListView
calculate their own smooth scroll, fast scroll, or anything else.
First, we'll need some class variables:
ListView listView;
ListView listView2;
View clickSource;
View touchSource;
int offset = 0;
Every method that I add to listView
will be almost identical for listView2
, the only difference is that listView2
will reference listView
(not itself). I didn't include the repetitive listView2
code.
Second, let's start with the OnTouchListener:
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;
}
});
To prevent circular logic: listView
calls listView2
calls listView
calls... I used a class variable touchSource
to determine when a MotionEvent
should be passed. I assumed that you don't want a row click in listView
to also click in listView2
, so I used another class variable clickSource
to prevent this.
Third, the OnItemClickListener:
listView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if(parent == clickSource) {
// Do something with the ListView was clicked
}
}
});
Fourth, passing every touch event isn't perfect because occasional discrepancies appear. The OnScrollListener is perfect for eliminating these:
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) {}
});
(Optional) Lastly, you mentioned that you have trouble since listView
and listView2
begin at different heights in your layout... I highly recommend modifying your layout to balance the ListViews, but I found a way to address this. However it is a little tricky.
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:
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]);
}
};
I assume that a half second delay is long enough to render the layout and start the timer in onResume()
:
handler.sendEmptyMessageDelayed(0, 500);
If you do use an offset I want to be clear that listView2
's OnScroll method subtracts the offset rather than adds it:
listView2.setSelectionFromTop(firstVisibleItem, view.getChildAt(0).getTop() - offset);
Hope that helps!