Open MarioNoll opened 5 years ago
Hi there,
I ran into the same scenario where I was using ViewPager2 and wanted to use ScrollingPagerIndicator Library along with it.
So, I came up with the following solution.
Create a File with the following Code
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import androidx.viewpager2.widget.ViewPager2;
import ru.tinkoff.scrollingpagerindicator.ScrollingPagerIndicator;
public class ViewPager2Attacher implements ScrollingPagerIndicator.PagerAttacher<ViewPager2> {
private RecyclerView.AdapterDataObserver dataSetObserver;
private RecyclerView.Adapter attachedAdapter;
private ViewPager2.OnPageChangeCallback onPageChangeListener;
private ViewPager2 pager;
@Override
public void attachToPager(@NonNull final ScrollingPagerIndicator indicator, @NonNull final ViewPager2 pager) {
attachedAdapter = pager.getAdapter();
if (attachedAdapter == null) {
throw new IllegalStateException("Set adapter before call attachToPager() method");
}
this.pager = pager;
indicator.setDotCount(attachedAdapter.getItemCount());
indicator.setCurrentPosition(pager.getCurrentItem());
dataSetObserver = new RecyclerView.AdapterDataObserver() {
@Override
public void onChanged() {
indicator.reattach();
}
};
attachedAdapter.registerAdapterDataObserver(dataSetObserver);
onPageChangeListener = new ViewPager2.OnPageChangeCallback() {
boolean idleState = true;
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixel) {
final float offset;
// ViewPager2 may emit negative positionOffset for very fast scrolling
if (positionOffset < 0) {
offset = 0;
} else if (positionOffset > 1) {
offset = 1;
} else {
offset = positionOffset;
}
indicator.onPageScrolled(position, offset);
}
@Override
public void onPageSelected(int position) {
if (idleState) {
indicator.setDotCount(attachedAdapter.getItemCount());
indicator.setCurrentPosition(pager.getCurrentItem());
}
}
@Override
public void onPageScrollStateChanged(int state) {
idleState = state == ViewPager2.SCROLL_STATE_IDLE;
}
};
pager.registerOnPageChangeCallback(onPageChangeListener);
}
@Override
public void detachFromPager() {
attachedAdapter.unregisterAdapterDataObserver(dataSetObserver);
pager.unregisterOnPageChangeCallback(onPageChangeListener);
}
}
and then attach ViewPager2 with ScrollingPagerIndicator using the following line
{ScrollingPagerIndicator}.attachToPager({ViewPager2}, ViewPager2Attacher())
Voila! That's it.
Enjoy!
@vishal1337 Looking at the current v.1.2.0
looks the same as your proposed solution. However there's an issue with it if you're using an adapter like ListAdapter
that dispatches insert / delete / changed events and not a general change event via notifyDataSetChanged
resulting in crashes / inconsistencies.
attachToRecyclerView
has the correct implementation. A workaround is using the attachToRecyclerView
and using ViewPager2.getChild(0) as RecyclerView
as the target but this should be fixed in the library.
Works fine:
Before: indicator.attachToPager(viewPager2)
After: indicator.attachToRecyclerView(viewPager2.getChildAt(0) as RecyclerView)
Would be nice to use this with ViewPager2.