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

Adjusting the Visibility Last Group #156

Open
pollux- opened this issue Feb 3, 2016 · 11 comments
Open

Adjusting the Visibility Last Group #156

pollux- opened this issue Feb 3, 2016 · 11 comments

Comments

@pollux-
Copy link

pollux- commented Feb 3, 2016

If Last Group Header is at the bottom of the list, if we click on that item header, it will expand the child item but we need to manually scroll to see the last item. Any workaround is possible, like when we expand the last item, it should scroll to show the content below the header...

@zeetherocker
Copy link

I have the same question, any workarounds would be awesome, Thanks

@paul-turner
Copy link
Contributor

This has been at the back of my mind as well, some related questions:

  1. Should it scroll down to try and show all the children on every expand (ie not just the last item in the row)?
  2. Should it only happen when the user has fully scrolled to the bottom of the list?
  3. What happens when the list of children is longer than the screen? (do we scroll to the bottom or only until the header reaches the top?)
  4. Should this be configurable to be on/off?

My opinions right now, which may change as I talk with more people on this:

  1. Probably not, users know that rows are expanding beneath.
  2. Probably, if the last row is partially visible the user knows there is more to scroll.
  3. Easiest = scroll all the way to the bottom, maybe more correct = scroll until the last parent has reached the top
  4. Some might prefer no scrolling on the last item, so probably yes.

Haven't started to look into how to do this all yet, I think it will cause some custom code based on the type of LayoutManager.

This may be possible without changes to the library, maybe if you listen for expand events, see when an expand happens to the last item, and if so scroll down to the correct position/item. This might be preferred rather than changes to the library so I welcome opinions there as well (and if it is feasible).

@falkontre
Copy link

falkontre commented Feb 9, 2016

I'm using a coarse approach...

Simply, I use the RecyclerView.smoothScrollToPosition in the onListItemExpanded listener method.

With this snipper, I manage to close all the parents, except the one I'm expanding, and scroll only if children are out of the screen.

@Override
    public void onListItemExpanded(int position) {
        List<? extends ParentListItem> parentItemList = adapter.getParentItemList();
        for (int i = 0; i < parentItemList.size(); i++) {
            if (i != position) {
                adapter.collapseParent(i);
            }
        }
        listView.smoothScrollToPosition(position + parentItemList.get(position).getChildItemList().size());
    }

@ankit-agg
Copy link

ankit-agg commented May 26, 2016

Slightly changing @falkontre proposed solution made it work for me. Put the following code inside the adapter.

int lastPos = -1;
@Override
public void onParentListItemExpanded(int position) {
    List<? extends ParentListItem> parentItemList = this.getParentItemList();
    collapseAllParents();
    int finalPos = position;
    if (lastPos != -1 && lastPos < position) {
        finalPos = position - parentItemList.get(lastPos).getChildItemList().size();
    }
    expandParent(finalPos);
    mRecyclerView.smoothScrollToPosition(finalPos);
    lastPos = position;
}

@holakeshav
Copy link

holakeshav commented Aug 19, 2016

@falkontre

I do not think this will work.

listView.smoothScrollToPosition(position + parentItemList.get(position).getChildItemList().size())

Use:

mLayoutManager.scrollToPositionWithOffset(position, offset);

@ghost
Copy link

ghost commented Oct 25, 2016

I have a question. When I use the above code (by ankit-agg and also by falkontre) inside adapter. And it shows recycler view object undefined. Rightly because we cannot access recyclerview object is not passed inside the adapter. So is there any way to work around with it?

@dgreenhalgh
Copy link
Contributor

@Tier5 You won't need to pass a reference to the RecyclerView into its Adapter. Instead, the adapter is attached to a RecyclerView, and you can obtain a reference to it in onAttachedToRecyclerView(RecyclerView).

@ChintanRathod
Copy link

This worked for me.
recyclerView.smoothScrollToPosition(position);

@ghost
Copy link

ghost commented Dec 9, 2016

I fix this issue by writing custom LayoutManager

public  class ExpandableLayoutManager extends LinearLayoutManager {

    private Handler mHandler;

    public ExpandableLayoutManager(Context context) {
        super(context);
        init();
    }

    public ExpandableLayoutManager(Context context, int orientation, boolean reverseLayout) {
        super(context, orientation, reverseLayout);
        init();
    }

    public ExpandableLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init();
    }

    private void init() {
        mHandler = new Handler();
    }

    @Override
    public void onItemsAdded(RecyclerView recyclerView, int positionStart, int itemCount) {
        super.onItemsAdded(recyclerView, positionStart, itemCount);

        if (positionStart == 0) return;
        mHandler.postDelayed(() -> {
            View parent = findViewByPosition(positionStart - 1);
            if (parent == null)
                return;

            int inHeight = parent.getTop() + parent.getHeight();


            setSmoothScrollbarEnabled(true);

            for (int i = positionStart; i < itemCount + positionStart; i++) {
                View child = getChildAt(i);
                if (child == null) {
                    recyclerView.smoothScrollToPosition(positionStart - 1);
                    return;
                }

                inHeight += child.getHeight();
            }

            if (inHeight > getHeight())
                recyclerView.smoothScrollToPosition(positionStart - 1);

        }, 120);
    }

    @Override
    public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state,
                                       int position) {
        RecyclerView.SmoothScroller smoothScroller = new TopSnappedSmoothScroller(recyclerView.getContext());
        smoothScroller.setTargetPosition(position);
        startSmoothScroll(smoothScroller);
    }


    private class TopSnappedSmoothScroller extends LinearSmoothScroller {
        public TopSnappedSmoothScroller(Context context) {
            super(context);

        }

        @Override
        public PointF computeScrollVectorForPosition(int targetPosition) {
            return ExpandableLayoutManager.this
                    .computeScrollVectorForPosition(targetPosition);
        }

        @Override
        public int calculateDyToMakeVisible(View view, int snapPreference) {
            return super.calculateDyToMakeVisible(view, snapPreference) + 24;
        }

        @Override
        protected int getVerticalSnapPreference() {
            return SNAP_TO_START;
        }


        @Override
        protected int calculateTimeForScrolling(int dx) {
            int time = super.calculateTimeForScrolling(dx);
            return time < 120 ? 120 : time;
        }

    }

@Corical
Copy link

Corical commented Jan 26, 2017

@isamorodov, thanks, working beautifully.

@Corical
Copy link

Corical commented Feb 16, 2017

On point 4, I doubt it. User expanded to see the sub-contents, so it should scroll.

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

No branches or pull requests

9 participants