Skip to content

Commit

Permalink
Fixed #117 - ViewHolder for sticky headers has to be a type of Flexib…
Browse files Browse the repository at this point in the history
…leViewHolder. As consequence IHeader item interface and its Abstract implementation have now the signature changed with FlexibleViewHolder. This assure that StickyHeaderHelper will receive the correct ViewHolder type without failures.

Also IExpandable item interface and its abstract implementation have ExpandableViewHolder in the signature.
  • Loading branch information
davideas committed Jun 18, 2016
1 parent afa159a commit 69ef319
Show file tree
Hide file tree
Showing 12 changed files with 217 additions and 116 deletions.
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
package eu.davidea.samples.flexibleadapter.models;

import android.support.v7.widget.RecyclerView;

import java.io.Serializable;

import eu.davidea.flexibleadapter.items.AbstractFlexibleItem;
import eu.davidea.viewholders.FlexibleViewHolder;

/**
* This class will benefit of the already implemented methods (getter and setters) in
* {@link eu.davidea.flexibleadapter.items.AbstractFlexibleItem}.
*
* It is used as Base item for all example models.
*/
public abstract class AbstractModelItem<VH extends RecyclerView.ViewHolder>
public abstract class AbstractModelItem<VH extends FlexibleViewHolder>
extends AbstractFlexibleItem<VH>
implements Serializable {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@

/**
* A sticky header helper, to use only with {@link FlexibleAdapter}.
* <p>Header ViewHolders must be of type {@link FlexibleViewHolder}.</p>
*
* @since 25/03/2016 Created
*/
Expand All @@ -45,8 +46,6 @@ public class StickyHeaderHelper extends OnScrollListener {
private ViewGroup mStickyHolderLayout;
private FlexibleViewHolder mStickyHeaderViewHolder;
private OnStickyHeaderChangeListener mStickyHeaderChangeListener;

/* Header state, used to not call getSectionHeader() all the time */
private int mHeaderPosition = RecyclerView.NO_POSITION;


Expand Down Expand Up @@ -146,10 +145,8 @@ private void updateHeader(int headerPosition, boolean updateHeaderContent) {
if (mHeaderPosition != headerPosition) {
mHeaderPosition = headerPosition;
FlexibleViewHolder holder = getHeaderViewHolder(headerPosition);
if (mStickyHeaderViewHolder != holder && holder.isStickyHeader()) {
if (FlexibleAdapter.DEBUG) Log.v(TAG, "swapHeader newPosition=" + mHeaderPosition);
swapHeader(holder);
}
if (FlexibleAdapter.DEBUG) Log.v(TAG, "swapHeader newHeaderPosition=" + mHeaderPosition);
swapHeader(holder);
} else if (updateHeaderContent && mStickyHeaderViewHolder != null) {
mAdapter.onBindViewHolder(mStickyHeaderViewHolder, mHeaderPosition);
ensureHeaderParent();
Expand Down Expand Up @@ -226,22 +223,26 @@ public void clearHeader() {
}
}

@SuppressWarnings({"unchecked", "ConstantConditions"})
@SuppressWarnings("unchecked")
private int getHeaderPosition(int adapterPosHere) {
if (adapterPosHere == RecyclerView.NO_POSITION) {
View firstChild = mRecyclerView.getChildAt(0);
adapterPosHere = mRecyclerView.getChildAdapterPosition(firstChild);
}
IHeader header = mAdapter.getSectionHeader(adapterPosHere);
//Header cannot be sticky if it's also an Expandable in collapsed status, RV will raise an exception
if (header == null || mAdapter.isExpandable(header) && !mAdapter.isExpanded(header)) {
return RecyclerView.NO_POSITION;
}
return mAdapter.getGlobalPositionOf(header);
}

/**
* Gets the header view for the associated position. If it doesn't exist
* yet, it will be created, measured, and laid out.
* Gets the header view for the associated header position. If it doesn't exist yet, it will
* be created, measured, and laid out.
*
* @param position the adapter position to get the header view for
* @return Header ViewHolder of the associated header position
* @param position the adapter position to get the header view
* @return ViewHolder of type FlexibleViewHolder of the associated header position
*/
@SuppressWarnings("unchecked")
private FlexibleViewHolder getHeaderViewHolder(int position) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,23 @@
*/
package eu.davidea.flexibleadapter.items;

import android.support.v7.widget.RecyclerView;
import eu.davidea.viewholders.ExpandableViewHolder;

/**
* Generic implementation of {@link IExpandable} interface combined with {@link IHeader} interface
* with most useful methods to manage expandable sections with sticky headers and sub items of
* type {@link ISectionable}.<br/>
* This abstract class extends also {@link AbstractExpandableItem}.
* <p>Call {@code super()} in the constructor to auto-configure the section status as shown,
* expanded, not selectable.</p>
* type {@link ISectionable}.
* <p>This abstract class extends {@link AbstractExpandableItem}.</p>
* Call {@code super()} in the constructor to auto-configure the section status as: shown,
* expanded, not selectable.
*
* @param <VH> {@link ExpandableViewHolder}
* @param <S> The sub item of type {@link ISectionable}
* @author Davide Steduto
* @since 01/04/2016 Created
* <br/>18/06/2016 Changed signature with ExpandableViewHolder
*/
public abstract class AbstractExpandableHeaderItem<VH extends RecyclerView.ViewHolder, S extends ISectionable>
public abstract class AbstractExpandableHeaderItem<VH extends ExpandableViewHolder, S extends ISectionable>
extends AbstractExpandableItem<VH, S>
implements IHeader<VH> {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,23 @@
*/
package eu.davidea.flexibleadapter.items;

import android.support.v7.widget.RecyclerView;

import java.util.ArrayList;
import java.util.List;

import eu.davidea.viewholders.ExpandableViewHolder;

/**
* Generic implementation of {@link IExpandable} interface with most useful methods to manage
* expansion and sub items.<br/>
* This abstract class extends also {@link AbstractFlexibleItem}.
* expansion and sub items.
* <p>This abstract class extends {@link AbstractFlexibleItem}.</p>
*
* @param <VH> {@link ExpandableViewHolder}
* @param <S> The sub item of type {@link IFlexible}
* @author Davide Steduto
* @since 17/01/2016 Created
* <br/>18/06/2016 Changed signature with ExpandableViewHolder
*/
public abstract class AbstractExpandableItem<VH extends RecyclerView.ViewHolder, S extends IFlexible>
public abstract class AbstractExpandableItem<VH extends ExpandableViewHolder, S extends IFlexible>
extends AbstractFlexibleItem<VH>
implements IExpandable<VH, S> {

Expand Down Expand Up @@ -67,7 +70,7 @@ public final List<S> getSubItems() {
}

public final boolean hasSubItems() {
return mSubItems!= null && mSubItems.size() > 0;
return mSubItems != null && mSubItems.size() > 0;
}

public IFlexible setSubItems(List<S> subItem) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
* Generic implementation of {@link IFlexible} interface with most useful methods to manage
* selection and view holder methods.
*
* @param <VH> {@link RecyclerView.ViewHolder}
* @author Davide Steduto
* @since 20/01/2016 Created
*/
Expand All @@ -37,22 +38,26 @@ public abstract class AbstractFlexibleItem<VH extends RecyclerView.ViewHolder>

/* Item flags recognized by the FlexibleAdapter */
protected boolean mEnabled = true, mHidden = false,
mSelectable = true, mDraggable = false, mSwipeable = false;
mSelectable = true, mDraggable = false, mSwipeable = false;

/*---------------*/
/* BASIC METHODS */
/*---------------*/

/**
* You <b>must</b> implement this method to compare items Identifiers.
* You <b>must</b> implement this method to compare items identifiers.
* <p>Adapter needs this method to distinguish them and pick up correct items.</p>
* See <a href="http://developer.android.com/reference/java/lang/Object.html#writing_equals">Writing a correct
* {@code equals} method</a> to implement your own {@code equals} method.
* <p>The general contract for the {@code equals} and {@link
* #hashCode()} methods is that if {@code equals} returns {@code true} for
* any two objects, then {@code hashCode()} must return the same value for
* these objects. This means that subclasses of {@code Object} usually
* override either both methods or neither of them.
* See <a href="http://developer.android.com/reference/java/lang/Object.html#writing_equals">
* Writing a correct {@code equals} method</a> to implement your own {@code equals} method.
* <p>Basic Java implementation:
* <pre>
* public boolean equals(Object o) {
* return this == o;
* }</pre></p>
* <p>When used with {@code HashMap}, the general contract for the {@code equals} and
* {@link #hashCode()} methods is that if {@code equals} returns {@code true} for any two
* objects, then {@code hashCode()} must return the same value for these objects. This means
* that subclasses of {@code Object} usually override either both methods or neither of them.
*
* @param o instance to compare
* @return true if items are equals, false otherwise.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,21 @@
*/
package eu.davidea.flexibleadapter.items;

import android.support.v7.widget.RecyclerView;
import eu.davidea.viewholders.FlexibleViewHolder;

/**
* Generic implementation of {@link IHeader} interface.
* <p>By default this item is hidden, not selectable.</p>
* This abstract class extends also {@link AbstractFlexibleItem}.
* Generic implementation of {@link IHeader} interface. By default this item is hidden and not
* selectable.
* <p>This abstract class extends {@link AbstractFlexibleItem}.</p>
* The ViewHolder must be of type {@link FlexibleViewHolder} to assure correct StickyHeader
* behaviours.
*
* @param <VH> {@link FlexibleViewHolder}
* @author Davide Steduto
* @since 17/01/2016 Created
* <br/>18/06/2016 Changed signature with FlexibleViewHolder
*/
public abstract class AbstractHeaderItem<VH extends RecyclerView.ViewHolder>
public abstract class AbstractHeaderItem<VH extends FlexibleViewHolder>
extends AbstractFlexibleItem<VH>
implements IHeader<VH> {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,31 +18,35 @@
import android.support.v7.widget.RecyclerView;

/**
* Abstract class for items that holds a header item.
* Generic implementation of {@link ISectionable} interface for items that holds a header item.
* This class represents an item in the section.
* <p>This abstract class extends {@link AbstractFlexibleItem}.</p>
*
* @param <VH>
* @param <T>
* @param <VH> {@link RecyclerView.ViewHolder}
* @param <H> The header item of type {@link IHeader}
* @author Davide Steduto
* @since 20/01/2016 Created
*/
public abstract class AbstractSectionableItem<VH extends RecyclerView.ViewHolder, T extends IHeader>
public abstract class AbstractSectionableItem<VH extends RecyclerView.ViewHolder, H extends IHeader>
extends AbstractFlexibleItem<VH>
implements ISectionable<VH, T> {
implements ISectionable<VH, H> {

/**
* The header of this item
*/
protected T header;
protected H header;

public AbstractSectionableItem(T header) {
public AbstractSectionableItem(H header) {
this.header = header;
}

@Override
public T getHeader() {
public H getHeader() {
return header;
}

@Override
public void setHeader(T header) {
public void setHeader(H header) {
this.header = header;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@
*/
package eu.davidea.flexibleadapter.items;

import android.support.v7.widget.RecyclerView;

import java.util.List;

import eu.davidea.viewholders.ExpandableViewHolder;

/**
* Interface to manage expanding operations on items with
* {@link eu.davidea.flexibleadapter.FlexibleAdapter}.
Expand All @@ -31,8 +31,9 @@
* @see IHolder
* @see ISectionable
* @since 17/01/2016 Created
* <br/>18/06/2016 Changed signature with ExpandableViewHolder
*/
public interface IExpandable<VH extends RecyclerView.ViewHolder, S extends IFlexible>
public interface IExpandable<VH extends ExpandableViewHolder, S extends IFlexible>
extends IFlexible<VH> {

/*--------------------*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*/
package eu.davidea.flexibleadapter.items;

import android.support.v7.widget.RecyclerView;
import eu.davidea.viewholders.FlexibleViewHolder;

/**
* Wrapper empty interface to identify if the current item is a header.
Expand All @@ -27,7 +27,8 @@
* @see IHolder
* @see ISectionable
* @since 15/02/2016 Created
* <br/>18/06/2016 Changed signature with FlexibleViewHolder
*/
public interface IHeader<VH extends RecyclerView.ViewHolder> extends IFlexible<VH> {
public interface IHeader<VH extends FlexibleViewHolder> extends IFlexible<VH> {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package eu.davidea.viewholders;

import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.FrameLayout;

import eu.davidea.flexibleadapter.FlexibleAdapter;

/**
* This Class separates the initialization of an eventual StickyHeader ViewHolder from a Normal
* ViewHolder. It improves code readability of FlexibleViewHolder.
*
* @author Davide Steduto
* @since 18/06/2016 Created
*/
abstract class ContentViewHolder extends RecyclerView.ViewHolder {

private int mBackupPosition = RecyclerView.NO_POSITION;
private View contentView;

public ContentViewHolder(View view, FlexibleAdapter adapter, boolean stickyHeader) {
//Since itemView is declared "final", the split is done before the View is initialized
super(stickyHeader ? new FrameLayout(view.getContext()) : view);

if (stickyHeader) {
itemView.setLayoutParams(adapter.getRecyclerView().getLayoutManager()
.generateLayoutParams(view.getLayoutParams()));
((FrameLayout) itemView).addView(view);//Add View after setLayoutParams
contentView = view;
}
}

/*-----------------------*/
/* STICKY HEADER METHODS */
/*-----------------------*/

/**
* In case this ViewHolder represents a Header Item, this method returns the contentView of the
* FrameLayout, otherwise it returns the basic itemView.
*
* @return the real contentView
*/
public View getContentView() {
return contentView != null ? contentView : itemView;
}

/**
* Overcomes the situation of returning an unknown position (-1) of ViewHolders created out of
* the LayoutManager (ex. StickyHeaders).
* <p><b>NOTE:</b> Always call this method, instead of {@code getAdapterPosition()}, in case
* of StickyHeaders use case.</p>
*
* @return the Adapter position result of {@link #getAdapterPosition()} OR the backup position
* preset and known, if the previous result was {@link RecyclerView#NO_POSITION}.
* @see #setBackupPosition(int)
*/
public int getFlexibleAdapterPosition() {
int position = getAdapterPosition();
if (position == RecyclerView.NO_POSITION) {
position = mBackupPosition;
}
return position;
}

/**
* Restore the Adapter position if the original Adapter position is unknown.
* <p>Called by StickyHeaderHelper to support the clickListeners events.</p>
*
* @param backupPosition the known position of this ViewHolder
*/
public void setBackupPosition(int backupPosition) {
mBackupPosition = backupPosition;
}

}
Loading

0 comments on commit 69ef319

Please sign in to comment.