前言
上一篇叨叨ViewPager那些事兒(一)說了一點(diǎn)ViewPager概況,這篇打算說說實(shí)際應(yīng)用。
從動畫效果說起
先祭上一份谷歌官方的Transformer示例
效果如下
代碼實(shí)現(xiàn)是這樣
public class DepthPageTransformer implements ViewPager.PageTransformer {
private static final float MIN_SCALE = 0.75f;
public void transformPage(View view, float position) {
int pageWidth = view.getWidth();
if (position < -1) { // [-Infinity,-1)
// This page is way off-screen to the left.
view.setAlpha(0);
} else if (position <= 0) { // [-1,0]
// Use the default slide transition when moving to the left page
view.setAlpha(1);
view.setTranslationX(0);
view.setScaleX(1);
view.setScaleY(1);
} else if (position <= 1) { // (0,1]
// Fade the page out.
view.setAlpha(1 - position);
// Counteract the default slide transition
view.setTranslationX(pageWidth * -position);
// Scale the page down (between MIN_SCALE and 1)
float scaleFactor = MIN_SCALE
+ (1 - MIN_SCALE) * (1 - Math.abs(position));
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
} else { // (1,+Infinity]
// This page is way off-screen to the right.
view.setAlpha(0);
}
}
}
乍一看有點(diǎn)懵懂,一步一問 慢慢來
?transformPage(View view, float position)
兩個參數(shù)是何含義
第一個參數(shù)為各頁卡對象,第二個是各個頁卡對于當(dāng)前所展示頁卡的相對位置,例如,當(dāng)前頁卡的position為0,下一張位置為1,前一張則為-1。而ViewPager滑動中,position的值是處于平滑變化中的,這就為我們處理動畫提供了機(jī)會。
?為何position < -1
和position > 1
時設(shè)置可見度為0
如前問分析,position < -1
和position > 1
指代頁卡所處區(qū)間為[-Infinity,-1)和(1,+Infinity],在可見范圍之外,從節(jié)省繪制資源的角度出發(fā),自然可見度為0。
?position (0,1]
區(qū)間時為何要設(shè)置偏移度為(pageWidth * -position)
官方注釋Counteract the default slide transition
,抵消頁面滑動時的默認(rèn)偏移量。如頁面處在中間時偏移量為0*width
,移至右邊為1*width
,從中間往右移除時position
從0-->1
漸變,默認(rèn)偏移量為position*width
?滑動動畫的縮放效果如何計算
如效果圖示,當(dāng)下一張頁卡相對位置從1-->0
變化時,scale的變化方向?yàn)?code>MIN_SCALE(m)-->1,不妨列個公式
(1-position)/(position-0)=(m-scale)/(scale-1)
即s=(1-position)/(1-position*m)
(對。。跟示例代碼不一樣。。但是效果一樣哦。。
也可以理解為1-scale=|(m-1)|/(1-0)*position
,scale從1-->m,位置從0-->1,即每單位position的變化量為|(m-1)|/(1-0),乘上position得出變化量。
理論儲備到位之后,自力更生的第一步就是,實(shí)踐!
下邊我們來寫一個左右位移,同時展示三張卡片的動畫,預(yù)想中效果大概是這樣
根據(jù)設(shè)想計算,左右兩邊的頁卡大小應(yīng)為中間大頁卡的0.9倍,左右頁卡的偏移量約為±0.2倍頁卡寬。
故設(shè)定
MIN_Trans_INDEX = 0.2f
,MIN_SCALE_INDEX = 0.9f
。如上分析,我們只關(guān)心[-1,1]區(qū)間頁卡的動畫,每單位position的scale變化量絕對值為(1-MIN_SCALE_INDEX)/(1-0),即
1-scale=|position|*(1-MIN_SCALE_INDEX)/(1-0)
即scale=1-|position|*(1-MIN_SCALE_INDEX)
同理,每單位position的translationx變化量為pageWidth*(1-MIN_Trans_INDEX)/(1-0),即
|0-translationx|=|position|*pageWidth*(1-MIN_Trans_INDEX)
即|translationx|=|position|*pageWidth*(1-MIN_Trans_INDEX)
,然而viewpager頁卡滑動過程中的默認(rèn)偏移量絕對值為pageWidth * position,故需在上式基礎(chǔ)上減pageWidth * position,|translationx|=|position|*pageWidth*MIN_Trans_INDEX
計算完畢,寫入代碼后發(fā)現(xiàn),效果是出來了,但是反應(yīng)好像永遠(yuǎn)。慢半拍。當(dāng)前頁滑動到位后,下一頁才出現(xiàn),體驗(yàn)不太美妙,如下動圖所示
查看代碼后思考,應(yīng)該是[-1,1]位置限定導(dǎo)致,左右兩頁分別滑動到-1和1時才開始做動畫,而此時這兩張頁卡已經(jīng)出現(xiàn)在屏幕上,所以看起來就像“慢了半拍”。
嘗試增加一點(diǎn)“緩沖量”,改動如下
public class MyTransPageTransformer implements ViewPager.PageTransformer {
private static final float MIN_Trans_INDEX = 0.2f;
private static final float MIN_SCALE_INDEX = 0.9f;
@Override
public void transformPage(@NonNull View page, float position) {
int pageWidth = page.getWidth();
if (position < -1.1) { // [-Infinity,-1.1)
// This page is way off-screen to the left.
page.setAlpha(0);
} else if (position <= 0) { // [-1.1,0]
// Use the default slide transition when moving to the left page
page.setAlpha(1);
page.setTranslationX(-pageWidth * position * MIN_Trans_INDEX);
page.setScaleX((1 - MIN_SCALE_INDEX) * position + 1);
page.setScaleY((1 - MIN_SCALE_INDEX) * position + 1);
Log.i("test", page.getTag()+"--"+((1 - MIN_SCALE_INDEX) * position + 1));
} else if (position <= 1.1) { // (0,1.1]
// Fade the page out.
page.setAlpha(1);
// Counteract the default slide transition
page.setTranslationX(-pageWidth * position * MIN_Trans_INDEX);
page.setScaleX(1 - (1 - MIN_SCALE_INDEX) * position);
page.setScaleY(1 - (1 - MIN_SCALE_INDEX) * position);
} else { // (1.1,+Infinity]
// This page is way off-screen to the right.
page.setAlpha(0);
}
}
}
再次運(yùn)行。這才是想要的效果嘛
問題來了
之前遇到過一個現(xiàn)象,刷新ViewPager,調(diào)用notifyDataSetChanged()
,如下。
誒,怎么肥事!左右兩邊的頁卡去哪了!冷靜一下,刷新時對當(dāng)前頁卡重繪,若不需滾動,則pageoffset始終為0,transformer的動畫效果無法顯示??磥硪肫椒€(wěn)刷新,還需手動更新單條數(shù)據(jù)。
行動起來,更改如下邏輯
@Override
public void onClick(View v) {
if (v.getId() == R.id.tv_notify) {
if (mCurPageIndex == 3) {//測試,代表邏輯需跳轉(zhuǎn)到的頁卡
isNeedNotify = true;
}
//更新當(dāng)前頁卡數(shù)據(jù)
updateViewPager(mCurPageIndex);
}
}
private void updateViewPager(int position) {
if (isNeedNotify) {//需要滾動時,調(diào)用notifyDataSetChanged重走instantiateItem和destroyItem邏輯
mPagerAdapter.notifyDataSetChanged();
mViewPager.setCurrentItem(3);
isNeedNotify = false;
}
//僅需更新當(dāng)前頁時則單獨(dú)刷新當(dāng)前頁卡view
MyViewPagerItem item = mPageItemList.get(position);
if (item != null) {
PageItemBean bean = new PageItemBean();
bean.num = position;
bean.tip = mContext.getString(R.string.num_tip, position + 1 + "");
item.updateUI(bean);
}
}
重跑程序,問題解決,Demo先放下。
為解決問題臨時想的方案,是實(shí)現(xiàn)更新的一條思路但感覺不夠優(yōu),歡迎各路大神指點(diǎn)。
最后
本想多寫一點(diǎn),但動畫已經(jīng)占了不少篇幅,先在這結(jié)束吧。這個系列會努力補(bǔ)充,歡迎多多指點(diǎn)和關(guān)注。