The proper solution is to turn the visibility of that view back on before it's recycled and then turn it back off before it's drawn.
((BaseAdapter) getAdapter()).notifyDataSetChanged();
mDownY = mLastEventY;
final int switchViewStartTop = switchView.getTop();
mobileView.setVisibility(View.VISIBLE);
switchView.setVisibility(View.INVISIBLE);
updateNeighborViewsForID(mMobileItemId);
final ViewTreeObserver observer = getViewTreeObserver();
observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
public boolean onPreDraw() {
observer.removeOnPreDrawListener(this);
replace with,
mobileView.setVisibility(VISIBLE);
((BaseAdapter) getAdapter()).notifyDataSetChanged();
mDownY = mLastEventY;
final int switchViewStartTop = switchView.getTop();
updateNeighborViewsForID(mMobileItemId);
final ViewTreeObserver observer = getViewTreeObserver();
observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
public boolean onPreDraw() {
observer.removeOnPreDrawListener(this);
View mobileView = getViewForID(mMobileItemId);
if (mobileView != null) mobileView.setVisibility(INVISIBLE);
The stableid solution is wrong. The IDs are stable and telling it that they aren't is in error. It simply kluges the system into recycling the views the old way. Which was in fact a bad way of doing it and was fixed in lollipop. This is a much more correct solution. Rather than predicting how the .notifyDataSetChanged will affect the views and turning on and off the proper elements given whatever version you're using. This one will turn on the visibility in all cases. Then in the predraw listener to find the view again and turns it back invisible, before it's drawn and after it's in its proper state.
And it doesn't matter, if that view is the same one or not, or some future version with some different way of doing it, or a bad adapter that doesn't actually recycle the views, etc. Stable Ids or non-stable ids (flagged not stable, they still have to be actually stable, but that's easily fixable), it's the way to properly do it and future proofed.
The problem here is that which recycled view you're going to get isn't actually clear (they are half trash recycled views after all), not things you can safely store properties in. The behavior was changed in Lollipop to keep stable views actually stable if they can, you could check in the adapter function and the recycled view will likely already have your data because it will give you the same view back again maximally often. Which is something you want, which is why Lollipop does it that way.
The problem here is that the code says mobileView should be made to be visible (the one you're moving), and the switchView should be made invisible (the one you're switching with). But, these are going to be recycled so they are technically ambiguous which one you'll get back, and depends entirely on how the system is recycling the views, and it's completely allowed to change that behavior for the better, and did.
Ps. I bother to check for null because I personally swap the views at the midway point and it can sometimes end up being null if you hit things just right.
int deltaYTotal = (mHoverCellOriginalBounds.bottom + mHoverCellOriginalBounds.top) / 2
+ mTotalOffset + deltaY;
...
boolean isBelow = (belowView != null) && (deltaYTotal > belowView.getTop());
boolean isAbove = (aboveView != null) && (deltaYTotal < aboveView.getBottom());