Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for GridLayoutManager #83

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
PROJECT_VERSION=0.5.1
PROJECT_VERSION=0.5.2
PROJECT_GROUP_ID=com.brandongogetap
PROJECT_VCS_URL=https://github.com/bgogetap/StickyHeaders.git
PROJECT_DESCRIPTION=StickyHeaders - Easy way to add sticky headers to RecyclerView
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
package com.brandongogetap.stickyheaders;

import android.support.annotation.NonNull;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;

import com.brandongogetap.stickyheaders.exposed.StickyHeader;
import com.brandongogetap.stickyheaders.exposed.StickyHeaderHandler;
import com.brandongogetap.stickyheaders.exposed.StickyHeaderListener;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

final class LayoutManagerHelper {

private int headerElevation = StickyHeaderPositioner.NO_ELEVATION;
private StickyHeaderHandler headerHandler;
private List<Integer> headerPositions = new ArrayList<>();
private final LinearLayoutManager layoutManager;
private ViewRetriever.RecyclerViewRetriever viewRetriever;
private StickyHeaderPositioner positioner;
private StickyHeaderListener stickyHeaderListener;
private int left;
private int top;
private int right;
private int bottom;

LayoutManagerHelper(@NonNull final LinearLayoutManager layoutManager, StickyHeaderHandler stickyHeaderHandler) {
this.layoutManager = layoutManager;
this.headerHandler = stickyHeaderHandler;
}

void handleVerticalScroll(final int scroll) {
if (Math.abs(scroll) > 0) {
if (positioner != null) {
positioner.updateHeaderState(
layoutManager.findFirstVisibleItemPosition(), getVisibleHeaders(), viewRetriever, layoutManager.findFirstCompletelyVisibleItemPosition() == 0);
}
}
}

public void onAttachedToWindow(RecyclerView view) {
Preconditions.validateParentView(view);
viewRetriever = new ViewRetriever.RecyclerViewRetriever(view);
positioner = new StickyHeaderPositioner(view);
positioner.setElevateHeaders(headerElevation);
positioner.setListener(stickyHeaderListener);
if (headerPositions.size() > 0) {
// Layout has already happened and header positions are cached. Catch positioner up.
positioner.setHeaderPositions(headerPositions);
runPositionerInit();
}
}

void handleHorizontalScroll(int scroll) {
if (Math.abs(scroll) > 0) {
if (positioner != null) {
positioner.updateHeaderState(
layoutManager.findFirstVisibleItemPosition(), getVisibleHeaders(), viewRetriever, layoutManager.findFirstCompletelyVisibleItemPosition() == 0);
}
}
}

void runPositionerInit() {
positioner.reset(layoutManager.getOrientation());
positioner.updateHeaderState(layoutManager.findFirstVisibleItemPosition(), getVisibleHeaders(), viewRetriever, layoutManager.findFirstCompletelyVisibleItemPosition() == 0);
}

private Map<Integer, View> getVisibleHeaders() {
Map<Integer, View> visibleHeaders = new LinkedHashMap<>();

for (int i = 0; i < layoutManager.getChildCount(); i++) {
View view = layoutManager.getChildAt(i);
int dataPosition = layoutManager.getPosition(view);
if (headerPositions.contains(dataPosition)) {
visibleHeaders.put(dataPosition, view);
}
}
return visibleHeaders;
}

void cacheHeaderPositions() {
headerPositions.clear();
List<?> adapterData = headerHandler.getAdapterData();
if (adapterData == null) {
if (positioner != null) {
positioner.setHeaderPositions(headerPositions);
}
return;
}

for (int i = 0; i < adapterData.size(); i++) {
if (adapterData.get(i) instanceof StickyHeader) {
headerPositions.add(i);
}
}
if (positioner != null) {
positioner.setHeaderPositions(headerPositions);
}
}

void setStickyHeaderListener(StickyHeaderListener stickyHeaderListener) {
if (positioner != null) {
positioner.setListener(stickyHeaderListener);
}
this.stickyHeaderListener = stickyHeaderListener;
}

/**
* Enable or disable elevation for Sticky Headers.
* <p>
* If you want to specify a specific amount of elevation, use
* {@link StickyLayoutManager#elevateHeaders(int)}
*
* @param elevateHeaders Enable Sticky Header elevation. Default is false.
*/
void elevateHeaders(boolean elevateHeaders) {
this.headerElevation = elevateHeaders ?
StickyHeaderPositioner.DEFAULT_ELEVATION : StickyHeaderPositioner.NO_ELEVATION;
elevateHeaders(headerElevation);
}

/**
* Enable Sticky Header elevation with a specific amount.
*
* @param dp elevation in dp
*/
void elevateHeaders(int dp) {
this.headerElevation = dp;
if (positioner != null) {
positioner.setElevateHeaders(dp);
}
}

void removeAndRecycleViews() {
if (positioner != null) {
positioner.clearHeader();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package com.brandongogetap.stickyheaders;

import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.Px;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;

import com.brandongogetap.stickyheaders.exposed.StickyHeaderHandler;
import com.brandongogetap.stickyheaders.exposed.StickyHeaderListener;

public class StickyGridLayoutManager extends GridLayoutManager {

private LayoutManagerHelper layoutManagerHelper;

public StickyGridLayoutManager(@NonNull final Context context, final int span, @NonNull final StickyHeaderHandler headerHandler) {
super(context, span);
init(headerHandler);
}

private void init(StickyHeaderHandler stickyHeaderHandler) {
Preconditions.checkNotNull(stickyHeaderHandler, "StickyHeaderHandler == null");
layoutManagerHelper = new LayoutManagerHelper(this, stickyHeaderHandler);
}

/**
* Register a callback to be invoked when a header is attached/re-bound or detached.
*
* @param listener The callback that will be invoked, or null to unset.
*/
public void setStickyHeaderListener(@Nullable StickyHeaderListener listener) {
layoutManagerHelper.setStickyHeaderListener(listener);
}

/**
* Enable or disable elevation for Sticky Headers.
* <p>
* If you want to specify a specific amount of elevation, use
* {@link StickyGridLayoutManager#elevateHeaders(int)}
*
* @param elevateHeaders Enable Sticky Header elevation. Default is false.
*/
public void elevateHeaders(boolean elevateHeaders) {
layoutManagerHelper.elevateHeaders(elevateHeaders);
}

/**
* Enable Sticky Header elevation with a specific amount.
*
* @param dp elevation in dp
*/
public void elevateHeaders(int dp) {
layoutManagerHelper.elevateHeaders(dp);
}

@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
super.onLayoutChildren(recycler, state);
layoutManagerHelper.cacheHeaderPositions();
if (layoutManagerHelper != null) {
layoutManagerHelper.runPositionerInit();
}
}

@Override
public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
int scroll = super.scrollVerticallyBy(dy, recycler, state);
layoutManagerHelper.handleVerticalScroll(scroll);
return scroll;
}

@Override
public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {
int scroll = super.scrollHorizontallyBy(dx, recycler, state);
layoutManagerHelper.handleHorizontalScroll(scroll);
return scroll;
}

@Override
public void removeAndRecycleAllViews(RecyclerView.Recycler recycler) {
super.removeAndRecycleAllViews(recycler);
layoutManagerHelper.removeAndRecycleViews();
}

@Override
public void onAttachedToWindow(RecyclerView view) {
layoutManagerHelper.onAttachedToWindow(view);
super.onAttachedToWindow(view);
}
}
Loading