...

пятница, 30 августа 2013 г.

[Из песочницы] ViewPager управляем временем анимации переходов

Добрый день,

Недавно мне понадобилось сделать банерную галерейку с анимацией, проблема была с временем анимации и самой анимацией в 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);

}



Собственно все


Хочу заметить что описание не слишком подробное но хочу улучшить, по возможности пишите что лучше объяснить


This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at fivefilters.org/content-only/faq.php#publishers. Five Filters recommends:



Комментариев нет:

Отправить комментарий