前言
上一篇叨叨ViewPager那些事兒(一)說了一點(diǎn)ViewPager概況球订,這篇打算說說實(shí)際應(yīng)用翻默。
從動(dò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)
兩個(gè)參數(shù)是何含義
第一個(gè)參數(shù)為各頁卡對象,第二個(gè)是各個(gè)頁卡對于當(dāng)前所展示頁卡的相對位置斥赋,例如璃哟,當(dāng)前頁卡的position為0氛琢,下一張位置為1,前一張則為-1随闪。而ViewPager滑動(dòng)中阳似,position的值是處于平滑變化中的,這就為我們處理動(dòng)畫提供了機(jī)會(huì)铐伴。
撮奏?為何position < -1
和position > 1
時(shí)設(shè)置可見度為0
如前問分析,position < -1
和position > 1
指代頁卡所處區(qū)間為[-Infinity,-1)和(1,+Infinity]当宴,在可見范圍之外畜吊,從節(jié)省繪制資源的角度出發(fā),自然可見度為0即供。
定拟?position (0,1]
區(qū)間時(shí)為何要設(shè)置偏移度為(pageWidth * -position)
官方注釋Counteract the default slide transition
,抵消頁面滑動(dòng)時(shí)的默認(rèn)偏移量。如頁面處在中間時(shí)偏移量為0*width
逗嫡,移至右邊為1*width
青自,從中間往右移除時(shí)position
從0-->1
漸變,默認(rèn)偏移量為position*width
驱证?滑動(dòng)動(dòng)畫的縮放效果如何計(jì)算
如效果圖示延窜,當(dāng)下一張頁卡相對位置從1-->0
變化時(shí),scale的變化方向?yàn)?code>MIN_SCALE(m)-->1抹锄,不妨列個(gè)公式
(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得出變化量币狠。
理論儲(chǔ)備到位之后,自力更生的第一步就是砾层,實(shí)踐漩绵!
下邊我們來寫一個(gè)左右位移,同時(shí)展示三張卡片的動(dòng)畫肛炮,預(yù)想中效果大概是這樣
根據(jù)設(shè)想計(jì)算止吐,左右兩邊的頁卡大小應(yīng)為中間大頁卡的0.9倍,左右頁卡的偏移量約為±0.2倍頁卡寬铸董。
故設(shè)定
MIN_Trans_INDEX = 0.2f
,MIN_SCALE_INDEX = 0.9f
祟印。如上分析,我們只關(guān)心[-1,1]區(qū)間頁卡的動(dòng)畫粟害,每單位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頁卡滑動(dòng)過程中的默認(rèn)偏移量絕對值為pageWidth * position颤芬,故需在上式基礎(chǔ)上減pageWidth * position悲幅,|translationx|=|position|*pageWidth*MIN_Trans_INDEX
計(jì)算完畢,寫入代碼后發(fā)現(xiàn)站蝠,效果是出來了汰具,但是反應(yīng)好像永遠(yuǎn)。慢半拍菱魔。當(dāng)前頁滑動(dòng)到位后留荔,下一頁才出現(xiàn),體驗(yàn)不太美妙澜倦,如下動(dòng)圖所示
查看代碼后思考聚蝶,應(yīng)該是[-1,1]位置限定導(dǎo)致,左右兩頁分別滑動(dòng)到-1和1時(shí)才開始做動(dòng)畫藻治,而此時(shí)這兩張頁卡已經(jīng)出現(xiàn)在屏幕上碘勉,所以看起來就像“慢了半拍”。
嘗試增加一點(diǎn)“緩沖量”桩卵,改動(dòng)如下
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)行验靡。這才是想要的效果嘛
問題來了
之前遇到過一個(gè)現(xiàn)象,刷新ViewPager雏节,調(diào)用notifyDataSetChanged()
胜嗓,如下。
誒钩乍,怎么肥事辞州!左右兩邊的頁卡去哪了!冷靜一下件蚕,刷新時(shí)對當(dāng)前頁卡重繪孙技,若不需滾動(dòng)产禾,則pageoffset始終為0,transformer的動(dòng)畫效果無法顯示牵啦⊙乔椋看來要想平穩(wěn)刷新,還需手動(dòng)更新單條數(shù)據(jù)哈雏。
行動(dòng)起來楞件,更改如下邏輯
@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) {//需要滾動(dòng)時(shí)裳瘪,調(diào)用notifyDataSetChanged重走instantiateItem和destroyItem邏輯
mPagerAdapter.notifyDataSetChanged();
mViewPager.setCurrentItem(3);
isNeedNotify = false;
}
//僅需更新當(dāng)前頁時(shí)則單獨(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í)想的方案黄伊,是實(shí)現(xiàn)更新的一條思路但感覺不夠優(yōu),歡迎各路大神指點(diǎn)派殷。
最后
本想多寫一點(diǎn)还最,但動(dòng)畫已經(jīng)占了不少篇幅,先在這結(jié)束吧毡惜。這個(gè)系列會(huì)努力補(bǔ)充拓轻,歡迎多多指點(diǎn)和關(guān)注。