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

The firstVisibleItem position is wrong when the top target view is out of screen. #39

Open
ghost opened this issue Jun 24, 2015 · 1 comment

Comments

@ghost
Copy link

ghost commented Jun 24, 2015

In the sample, in the list view's onScroll method.

Re-produce step:
Scroll up and make the top target disappear, then the firstVisibleItem is immediately 1 which should be 0.
It will be bigger than expected if you continue to scroll up.

@ghost
Copy link
Author

ghost commented Jun 25, 2015

I add adjustFirstVisibleItem method, and changes the CompositeAbsListViewOnScrollListener's onScroll method to deliver the modification to other onScrollListener.

 public class AbsListViewScrollTarget
        extends QuickReturnTargetView
        implements AbsListView.OnScrollListener {

    private final AbsListView listView;
    private int quickViewHeight;
    private int itemHeight;
    private int adjustedFirstVisibleItem;

    public AbsListViewScrollTarget(AbsListView listView, View targetView,
                                   int position) {
        this(listView, targetView, position, 0);
    }

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    public AbsListViewScrollTarget(AbsListView listView, View targetView,
                                   int position, int targetViewHeight) {
        super(targetView, position);

        quickViewHeight = targetViewHeight;
        this.listView = listView;
        QuickReturnAdapter adapter = getAdapter();

        if (adapter == null) {
            throw new UnsupportedOperationException(
                    "You need to set the listView adapter before adding a targetView");
        }

        if (position == POSITION_TOP) {
            adapter.setTargetViewHeight(targetViewHeight);
        }

        if (listView instanceof ListView) {
            adapter.setVerticalSpacing(((ListView) listView).getDividerHeight());
        } else if (listView instanceof GridView
                && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            adapter.setVerticalSpacing(((GridView) listView).getVerticalSpacing());
        }
    }

    @Override
    protected int getComputedScrollY() {
        if (listView.getChildCount() == 0 || listView.getAdapter() == null) {
            return 0;
        }

        int pos = listView.getFirstVisiblePosition();
        View view = listView.getChildAt(0);
        return getAdapter().getPositionVerticalOffset(pos) - view.getTop();
    }

    private QuickReturnAdapter getAdapter() {
        ListAdapter adapter = listView.getAdapter();

        if (adapter instanceof WrapperListAdapter) {
            adapter = ((WrapperListAdapter) adapter).getWrappedAdapter();
        }

        if (!(adapter instanceof QuickReturnAdapter)) {
            throw new UnsupportedOperationException(
                    "Your QuickReturn ListView adapter must be an instance of QuickReturnAdapter.");
        }

        return (QuickReturnAdapter) adapter;
    }

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
    }

    @Override
    public void onScroll(@NonNull AbsListView view, int firstVisibleItem,
                         int visibleItemCount, int totalItemCount) {
        if (listView.getAdapter() == null || quickReturnView == null) {
            return;
        }

        calculateItemHeight(firstVisibleItem);
        // The maxVerticalOffset is less than 1.
        int maxVerticalOffset = getAdapter().getMaxVerticalOffset() + itemHeight;
        int listViewHeight = listView.getHeight();
        int rawY = -Math.min(maxVerticalOffset > listViewHeight
                ? maxVerticalOffset - listViewHeight
                : listViewHeight, getComputedScrollY());

        int translationY = currentTransition.determineState(rawY, quickReturnView.getHeight());

        translateTo(translationY);
        Log.d(TAG, "maxVerticalOffset: " + maxVerticalOffset +
                ", listViewHeight: " + listViewHeight +
                ", rawY: " + rawY +
                ", getComputedScrollY(): " + getComputedScrollY() +
                ", translationY: " + translationY);

        adjustFirstVisibleItem(firstVisibleItem, rawY, translationY);
    }

    private void calculateItemHeight(int firstVisibleItem) {
        if (itemHeight == 0) {
            View view = listView.getAdapter().getView(firstVisibleItem, null, listView);
            view.measure(
                    View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
                    View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
            itemHeight = view.getMeasuredHeight();
        }
    }

    private void adjustFirstVisibleItem(int firstVisibleItem, int rawY, int translationY) {
        if (listView.getAdapter().getCount() == 0) return;
        if (translationY > 0) {
            return;
        }

        if (itemHeight == 0) return;

        int f;

        if (rawY > 0) {
            rawY = 0;
        }
        if (translationY > 0) {
            translationY = 0;
        }
        if (translationY < -quickViewHeight) {
            f = Math.abs(rawY + quickViewHeight) / itemHeight;
        } else if (-quickViewHeight < translationY && translationY < 0) {
            f = Math.abs(rawY + Math.abs(quickViewHeight + translationY)) / itemHeight;
        } else {
            f = Math.abs(rawY) / itemHeight;
        }

        Log.d(TAG, "actual first visible item: " + f);
        adjustedFirstVisibleItem = f;
    }

    public int getAdjustedFirstVisibleItem() {
        return adjustedFirstVisibleItem;
    }
}
public class CompositeAbsListViewOnScrollListener
        extends ArrayList<AbsListView.OnScrollListener>
        implements AbsListView.OnScrollListener {

    public void registerOnScrollListener(final AbsListView.OnScrollListener listener) {
        add(listener);
    }

    public void unregisterOnScrollListener(final AbsListView.OnScrollListener listener) {
        remove(listener);
    }

    @Override
    public void onScrollStateChanged(final AbsListView view, final int scrollState) {
        for (AbsListView.OnScrollListener listener : this) {
            listener.onScrollStateChanged(view, scrollState);
        }
    }

    @Override
    public void onScroll(final AbsListView view, final int firstVisibleItem,
                         final int visibleItemCount, final int totalItemCount) {
        if (this.size() <= 0) {
            return;
        }
        AbsListViewScrollTarget adjustedListener = (AbsListViewScrollTarget)this.get(0);
        adjustedListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
        int f = adjustedListener.getAdjustedFirstVisibleItem();
        Log.d("CompositeAbsList", "adjusted: " + f);
        for (int i = 1; i < this.size(); ++i) {
            this.get(i).onScroll(view, f, visibleItemCount, totalItemCount);
        }
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

0 participants