Created
March 6, 2018 14:19
-
-
Save Anrimian/08eff1269559fe191014cff50d210dd2 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class StickyHeaderViewManager<T> { | |
@Nonnull | |
private View headerView; | |
@Nonnull | |
private RecyclerView recyclerView; | |
@Nonnull | |
private StickyHeaderViewWrapper<T> viewWrapper; | |
@Nonnull | |
private Class<T> headerDataClass; | |
private List<?> items; | |
public StickyHeaderViewManager(@Nonnull View headerView, | |
@Nonnull RecyclerView recyclerView, | |
@Nonnull Class<T> headerDataClass, | |
@Nonnull StickyHeaderViewWrapper<T> viewWrapper) { | |
this.headerView = headerView; | |
this.viewWrapper = viewWrapper; | |
this.recyclerView = recyclerView; | |
this.headerDataClass = headerDataClass; | |
} | |
public void attach(@Nonnull List<?> items) { | |
this.items = items; | |
if (ViewCompat.isLaidOut(headerView)) { | |
bindHeader(recyclerView); | |
} else { | |
headerView.post(() -> bindHeader(recyclerView)); | |
} | |
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { | |
@Override | |
public void onScrolled(RecyclerView recyclerView, int dx, int dy) { | |
super.onScrolled(recyclerView, dx, dy); | |
bindHeader(recyclerView); | |
} | |
}); | |
} | |
private void bindHeader(RecyclerView recyclerView) { | |
if (items.isEmpty()) { | |
headerView.setVisibility(View.GONE); | |
return; | |
} else { | |
headerView.setVisibility(View.VISIBLE); | |
} | |
View topView = recyclerView.getChildAt(0); | |
if (topView == null) { | |
return; | |
} | |
int topPosition = recyclerView.getChildAdapterPosition(topView); | |
if (!isValidPosition(topPosition)) { | |
return; | |
} | |
if (topPosition == 0 && topView.getTop() == recyclerView.getTop()) { | |
headerView.setVisibility(View.GONE); | |
return; | |
} else { | |
headerView.setVisibility(View.VISIBLE); | |
} | |
T stickyItem; | |
Object firstItem = items.get(topPosition); | |
if (headerDataClass.isInstance(firstItem)) { | |
stickyItem = headerDataClass.cast(firstItem); | |
headerView.setTranslationY(0); | |
} else { | |
stickyItem = findNearestHeader(topPosition); | |
int secondPosition = topPosition + 1; | |
if (isValidPosition(secondPosition)) { | |
Object secondItem = items.get(secondPosition); | |
if (headerDataClass.isInstance(secondItem)) { | |
View secondView = recyclerView.getChildAt(1); | |
if (secondView != null) { | |
moveViewFor(secondView); | |
} | |
} else { | |
headerView.setTranslationY(0); | |
} | |
} | |
} | |
if (stickyItem != null) { | |
viewWrapper.bindView(stickyItem); | |
} | |
} | |
private void moveViewFor(View secondView) { | |
if (secondView.getTop() <= headerView.getBottom()) { | |
headerView.setTranslationY(secondView.getTop() - headerView.getHeight()); | |
} else { | |
headerView.setTranslationY(0); | |
} | |
} | |
private T findNearestHeader(int position) { | |
for (int i = position; position >= 0; i--) { | |
Object item = items.get(i); | |
if (headerDataClass.isInstance(item)) { | |
return headerDataClass.cast(item); | |
} | |
} | |
return null; | |
} | |
private boolean isValidPosition(int position) { | |
return !(position == RecyclerView.NO_POSITION || items.isEmpty() || position >= items.size()); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public interface StickyHeaderViewWrapper<T> { | |
void bindView(T data); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment