Недавно мне понадобилось сделать банерную галерейку с анимацией, проблема была с временем анимации и самой анимацией в ViewPager Переход был слишком быстрый, и если переходить с 1 элемента на 5 то не увидишь анимации 3-4 элементов
Приступим
Давайте попробуем разобраться в чем причина такого поведения ViewPager
void setCurrentItemInternal(int item, boolean smoothScroll, boolean always, int velocity) { if (mAdapter == null || mAdapter.getCount() <= 0) { setScrollingCacheEnabled(false); return; } if (!always && mCurItem == item && mItems.size() != 0) { setScrollingCacheEnabled(false); return; } if (item < 0) { item = 0; } else if (item >= mAdapter.getCount()) { item = mAdapter.getCount() - 1; } final int pageLimit = mOffscreenPageLimit; // Из-за данной строчки во время анимации мы не видим n-ые элементы if (item > (mCurItem + pageLimit) || item < (mCurItem - pageLimit)) { for (int i=0; i<mItems.size(); i++) { mItems.get(i).scrolling = true; } } final boolean dispatchSelected = mCurItem != item; if (mFirstLayout) { mCurItem = item; if (dispatchSelected && mOnPageChangeListener != null) { mOnPageChangeListener.onPageSelected(item); } if (dispatchSelected && mInternalPageChangeListener != null) { mInternalPageChangeListener.onPageSelected(item); } requestLayout(); } else { populate(item); scrollToItem(item, smoothScroll, velocity, dispatchSelected); // Здесь происходит анимация до y позиции и тут же высчитывается время анимации } }
Мы разобрали причину почему мы невидим анимации некоторых элементов в ViewPager теперь посмотри как же устроенна функция скроллинга до определенного элемента.
// зайдем в SmoothScrolltTo и посмотрим как высчитывается время анимации int duration = 0; //время анимации velocity = Math.abs(velocity); // скорость if (velocity > 0) { duration = 4 * Math.round(1000 * Math.abs(distance / velocity)); } else { final float pageWidth = width * mAdapter.getPageWidth(mCurItem); final float pageDelta = (float) Math.abs(dx) / (pageWidth + mPageMargin); duration = (int) ((pageDelta + 1) * 100); } duration = Math.min(duration, MAX_SETTLE_DURATION); mScroller.startScroll(sx, sy, dx, dy, duration);
Наверное здесь не нужно много объяснений, все предельно просто. Теперь приступим к добавлю нашего метода для скроллинга с произвольным временем за основу возьмем метод setCurrentItemInternal и smoothScrollTo итак преступим
public void setCurrentItem( int item, int duration){ if (mAdapter == null || mAdapter.getCount() <= 0) { setScrollingCacheEnabled(false); return; } int oldCurrentPos = getCurrentItem(); // запоминаем позицию if(oldCurrentPos == item){ // если нынешняя позиция равна элементу к которому нужно прокрутить возвращаемся return; }else{ // иначе выставляем отображение под элементов равное прокручиваемым элементам setOffscreenPageLimit(Math.abs(oldCurrentPos - item)); } if (item < 0) { item = 0; } else if (item >= mAdapter.getCount()) { item = mAdapter.getCount() - 1; } final int pageLimit = mOffscreenPageLimit; if (item > (mCurItem + pageLimit) || item < (mCurItem - pageLimit)) { // We are doing a jump by more than one page. To avoid // glitches, we want to keep all current pages in the view // until the scroll ends. for (int i=0; i<mItems.size(); i++) { mItems.get(i).scrolling = true; } } final boolean dispatchSelected = mCurItem != item; if (mFirstLayout) { // We don't have any idea how big we are yet and shouldn't have any pages either. // Just set things up and let the pending layout handle things. mCurItem = item; if (dispatchSelected && mOnPageChangeListener != null) { mOnPageChangeListener.onPageSelected(item); } if (dispatchSelected && mInternalPageChangeListener != null) { mInternalPageChangeListener.onPageSelected(item); } requestLayout(); } else { populate(item); final ItemInfo curItem = infoForPosition(item); int destX = 0; if(curItem != null){ final int width = getClientWidth(); destX = (int) (width * Math.max(mFirstOffset, Math.min(curItem.offset, mLastOffset))); } if(duration > 0){ int velocity = duration / Math.abs(oldCurrentPos - item); smoothScrollToWithDuration(destX, 0, duration); // скролим if(mOnPageChangeListener != null && curItem.position != item){ mOnPageChangeListener.onPageSelected(item); } if (curItem.position != item && mInternalPageChangeListener != null) { mInternalPageChangeListener.onPageSelected(item); } } } } void smoothScrollToWithDuration(int x, int y, int duration){ if (getChildCount() == 0) { // Nothing to do. setScrollingCacheEnabled(false); return; } int sx = getScrollX(); int sy = getScrollY(); int dx = x - sx; int dy = y - sy; if (dx == 0 && dy == 0) { completeScroll(true); populate(); setScrollState(SCROLL_STATE_IDLE); return; } setScrollingCacheEnabled(true); setScrollState(SCROLL_STATE_SETTLING); final int width = getClientWidth(); final int halfWidth = width / 2; final float distanceRatio = Math.min(1f, 1.0f * Math.abs(dx) / width); mScroller.startScroll(sx, sy, dx, dy, duration); // скролим до определенной страницы с произвольным временем if(mScroller.isFinished()){ setOffscreenPageLimit(DEFAULT_OFFSCREEN_PAGES); // восстанавливаем значение подэлементов } ViewCompat.postInvalidateOnAnimation(this); }
Собственно все
Хочу заметить что описание не слишком подробное но хочу улучшить, по возможности пишите что лучше объяснить
ссылка на оригинал статьи http://habrahabr.ru/post/191974/
Добавить комментарий