package com.github.tibolte.agendacalendarview.utils; import com.github.tibolte.agendacalendarview.agenda.AgendaListView; import android.util.SparseArray; import android.view.View; /** * Helper class calculating the scrolling distance in the AgendaListView. */ public class ListViewScrollTracker { private AgendaListView mListView; private SparseArray<Integer> mPositions; private SparseArray<Integer> mListViewItemHeights = new SparseArray<>(); private int mFirstVisiblePosition; private int mReferencePosition = -1; // Position of the current date in the Agenda listView // region Constructor and Accessor(s) public ListViewScrollTracker(AgendaListView listView) { mListView = listView; } public int getReferencePosition() { return mReferencePosition; } // endregion // region Public methods /** * Call from an AbsListView.OnScrollListener to calculate the incremental offset (change in * scroll offset * since the last calculation). * * @param firstVisiblePosition First visible item position in the list. * @param visibleItemCount Number of visible items in the list. * @return The incremental offset, or 0 if it wasn't possible to calculate the offset. */ public int calculateIncrementalOffset(int firstVisiblePosition, int visibleItemCount) { // Remember previous positions, if any SparseArray<Integer> previousPositions = mPositions; // Store new positions mPositions = new SparseArray<>(); for (int i = 0; i < visibleItemCount; i++) { mPositions.put(firstVisiblePosition + i, mListView.getListChildAt(i).getTop()); } if (previousPositions != null) { // Find position which exists in both mPositions and previousPositions, then return the difference // of the new and old Y values. for (int i = 0; i < previousPositions.size(); i++) { int previousPosition = previousPositions.keyAt(i); int previousTop = previousPositions.get(previousPosition); Integer newTop = mPositions.get(previousPosition); if (newTop != null) { return newTop - previousTop; } } } return 0; // No view's position was in both previousPositions and mPositions } /** * Call from an AbsListView.OnScrollListener to calculate the scrollY (Here * we definite as the distance in pixels compared to the position representing the current * date). * * @param firstVisiblePosition First visible item position in the list. * @param visibleItemCount Number of visible items in the list. * @return Distance in pixels compared to current day position (negative if firstVisiblePosition less than mReferencePosition) */ public int calculateScrollY(int firstVisiblePosition, int visibleItemCount) { mFirstVisiblePosition = firstVisiblePosition; if (mReferencePosition < 0) { mReferencePosition = mFirstVisiblePosition; } if (visibleItemCount > 0) { View c = mListView.getListChildAt(0); // this is the first visible row int scrollY = -c.getTop(); mListViewItemHeights.put(firstVisiblePosition, c.getMeasuredHeight()); if (mFirstVisiblePosition >= mReferencePosition) { for (int i = mReferencePosition; i < firstVisiblePosition; ++i) { if (mListViewItemHeights.get(i) == null) { mListViewItemHeights.put(i, c.getMeasuredHeight()); } scrollY += mListViewItemHeights.get(i); // add all heights of the views that are gone } return scrollY; } else { for (int i = mReferencePosition - 1; i >= firstVisiblePosition; --i) { if (mListViewItemHeights.get(i) == null) { mListViewItemHeights.put(i, c.getMeasuredHeight()); } scrollY -= mListViewItemHeights.get(i); } return scrollY; } } return 0; } public void clear() { mPositions = null; } // endregion }