From aa96bb6654e12f2c68b9f9f6021437e320aab0e3 Mon Sep 17 00:00:00 2001 From: Shamyl Zakariya Date: Mon, 25 Jul 2016 13:31:26 -0700 Subject: [PATCH] Add support for partial vs full items when searching for first visible item --- README.md | 2 +- .../stickyheadersapp/ui/DemoActivity.java | 9 ++-- stickyheaders/build.gradle | 2 +- .../StickyHeaderLayoutManager.java | 44 ++++++++++++------- 4 files changed, 34 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index e6c77d9..8b063c8 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Adapter and LayoutManager for Android RecyclerView which enables sticky header p ## Download minSdkVersion: 11 ``` -compile 'org.zakariya.stickyheaders:stickyheaders:0.7.2' +compile 'org.zakariya.stickyheaders:stickyheaders:0.7.3' ``` diff --git a/app/src/main/java/org/zakariya/stickyheadersapp/ui/DemoActivity.java b/app/src/main/java/org/zakariya/stickyheadersapp/ui/DemoActivity.java index ec713ce..7405833 100644 --- a/app/src/main/java/org/zakariya/stickyheadersapp/ui/DemoActivity.java +++ b/app/src/main/java/org/zakariya/stickyheadersapp/ui/DemoActivity.java @@ -29,7 +29,7 @@ public class DemoActivity extends AppCompatActivity { private static final String TAG = DemoActivity.class.getSimpleName(); private static final String STATE_SCROLL_POSITION = "DemoActivity.STATE_SCROLL_POSITION"; - public static final boolean SHOW_ADAPTER_POSITIONS = false; + public static final boolean SHOW_ADAPTER_POSITIONS = true; RecyclerView recyclerView; ProgressBar progressBar; @@ -112,10 +112,11 @@ private void showInspectDialog() { return; } + boolean fullVisibleOnly = true; StickyHeaderLayoutManager layoutManager = (StickyHeaderLayoutManager) recyclerView.getLayoutManager(); - SectioningAdapter.HeaderViewHolder headerViewHolder = layoutManager.getFirstVisibleHeaderViewHolder(); - SectioningAdapter.ItemViewHolder itemViewHolder = layoutManager.getFirstVisibleItemViewHolder(); - SectioningAdapter.FooterViewHolder footerViewHolder = layoutManager.getFirstVisibleFooterViewHolder(); + SectioningAdapter.HeaderViewHolder headerViewHolder = layoutManager.getFirstVisibleHeaderViewHolder(fullVisibleOnly); + SectioningAdapter.ItemViewHolder itemViewHolder = layoutManager.getFirstVisibleItemViewHolder(fullVisibleOnly); + SectioningAdapter.FooterViewHolder footerViewHolder = layoutManager.getFirstVisibleFooterViewHolder(fullVisibleOnly); ArrayList inspections = new ArrayList<>(); diff --git a/stickyheaders/build.gradle b/stickyheaders/build.gradle index a59b854..8f5996f 100644 --- a/stickyheaders/build.gradle +++ b/stickyheaders/build.gradle @@ -3,7 +3,7 @@ apply plugin: 'com.jfrog.bintray' apply plugin: 'com.github.dcendents.android-maven' group = 'org.zakariya.stickyheaders' -version = '0.7.2' +version = '0.7.3' android { compileSdkVersion 23 diff --git a/stickyheaders/src/main/java/org/zakariya/stickyheaders/StickyHeaderLayoutManager.java b/stickyheaders/src/main/java/org/zakariya/stickyheaders/StickyHeaderLayoutManager.java index 3110e92..d230664 100644 --- a/stickyheaders/src/main/java/org/zakariya/stickyheaders/StickyHeaderLayoutManager.java +++ b/stickyheaders/src/main/java/org/zakariya/stickyheaders/StickyHeaderLayoutManager.java @@ -126,7 +126,7 @@ public Parcelable onSaveInstanceState() { } // Check if we're detached; if not, update - if(adapter != null) + if (adapter != null) updateFirstAdapterPosition(); SavedState state = new SavedState(); state.firstViewAdapterPosition = firstViewAdapterPosition; @@ -142,10 +142,10 @@ public void onRestoreInstanceState(Parcelable state) { } if (state instanceof SavedState) { - pendingSavedState = (SavedState)state; + pendingSavedState = (SavedState) state; requestLayout(); } else { - Log.e(TAG, "onRestoreInstanceState: invalid saved state class, expected: " + SavedState.class.getCanonicalName() + " got: " + state.getClass().getCanonicalName() ); + Log.e(TAG, "onRestoreInstanceState: invalid saved state class, expected: " + SavedState.class.getCanonicalName() + " got: " + state.getClass().getCanonicalName()); } } @@ -178,7 +178,7 @@ public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State int totalVendedHeight = 0; // If we emptied the view with a notify, we may overshoot and fail to draw - if(firstViewAdapterPosition > state.getItemCount()) + if (firstViewAdapterPosition > state.getItemCount()) firstViewAdapterPosition = 0; // walk through adapter starting at firstViewAdapterPosition stacking each vended item @@ -320,7 +320,7 @@ public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerVi isHeader = itemViewType == SectioningAdapter.TYPE_HEADER; // If it's still a header, we don't need to do anything right now - if(isHeader) + if (isHeader) break; } @@ -444,31 +444,34 @@ public void scrollToPosition(int position) { } /** + * @param fullyVisibleOnly if true, the search will be limited to the first item not hanging off top of screen or partially obscured by a header * @return the viewholder for the first visible item (not header or footer) */ @Nullable - public SectioningAdapter.ItemViewHolder getFirstVisibleItemViewHolder() { - return (SectioningAdapter.ItemViewHolder) getFirstVisibleViewHolderOfType(SectioningAdapter.TYPE_ITEM); + public SectioningAdapter.ItemViewHolder getFirstVisibleItemViewHolder(boolean fullyVisibleOnly) { + return (SectioningAdapter.ItemViewHolder) getFirstVisibleViewHolderOfType(SectioningAdapter.TYPE_ITEM, fullyVisibleOnly); } /** + * @param fullyVisibleOnly if true, the search will be limited to the first header not hanging off top of screen * @return the viewholder for the first visible header (not item or footer) */ @Nullable - public SectioningAdapter.HeaderViewHolder getFirstVisibleHeaderViewHolder() { - return (SectioningAdapter.HeaderViewHolder) getFirstVisibleViewHolderOfType(SectioningAdapter.TYPE_HEADER); + public SectioningAdapter.HeaderViewHolder getFirstVisibleHeaderViewHolder(boolean fullyVisibleOnly) { + return (SectioningAdapter.HeaderViewHolder) getFirstVisibleViewHolderOfType(SectioningAdapter.TYPE_HEADER, fullyVisibleOnly); } /** + * @param fullyVisibleOnly if true, the search will be limited to the first footer not hanging off top of screen or partially obscured by a header * @return the viewholder for the first visible footer (not header or item) */ @Nullable - public SectioningAdapter.FooterViewHolder getFirstVisibleFooterViewHolder() { - return (SectioningAdapter.FooterViewHolder) getFirstVisibleViewHolderOfType(SectioningAdapter.TYPE_FOOTER); + public SectioningAdapter.FooterViewHolder getFirstVisibleFooterViewHolder(boolean fullyVisibleOnly) { + return (SectioningAdapter.FooterViewHolder) getFirstVisibleViewHolderOfType(SectioningAdapter.TYPE_FOOTER, fullyVisibleOnly); } @Nullable - SectioningAdapter.ViewHolder getFirstVisibleViewHolderOfType(int baseType) { + SectioningAdapter.ViewHolder getFirstVisibleViewHolderOfType(int baseType, boolean fullyVisibleOnly) { if (getChildCount() == 0) { return null; } @@ -478,7 +481,7 @@ SectioningAdapter.ViewHolder getFirstVisibleViewHolderOfType(int baseType) { // our items is below this value int firstHeaderBottom = 0; if (baseType != SectioningAdapter.TYPE_HEADER) { - SectioningAdapter.HeaderViewHolder firstHeader = getFirstVisibleHeaderViewHolder(); + SectioningAdapter.HeaderViewHolder firstHeader = getFirstVisibleHeaderViewHolder(false); if (firstHeader != null) { firstHeaderBottom = getDecoratedBottom(firstHeader.itemView); } @@ -501,13 +504,20 @@ SectioningAdapter.ViewHolder getFirstVisibleViewHolderOfType(int baseType) { continue; } - // filter out items which are fully obscured by a header + // filter out items which are partially or fully obscured by a header + int t = getDecoratedTop(v); int b = getDecoratedBottom(v); - if (b <= firstHeaderBottom + 1) { - continue; + + if (fullyVisibleOnly) { + if (t < firstHeaderBottom) { + continue; + } + } else { + if (b <= firstHeaderBottom + 1) { + continue; + } } - int t = getDecoratedTop(v); if (t < top) { top = t; topmostView = v;