PageTransformer是ViewPager內(nèi)部定義的接口,實(shí)現(xiàn)該接口并應(yīng)用于ViewPager可以控制ViewPager中item view的滑動(dòng)效果救湖。先上一張示例圖
接下來我們看一下PageTransformer源碼及api介紹抬旺,比較簡單
/**
* A PageTransformer is invoked whenever a visible/attached page is scrolled.
* This offers an opportunity for the application to apply a custom transformation
* to the page views using animation properties.
*
* <p>As property animation is only supported as of Android 3.0 and forward,
* setting a PageTransformer on a ViewPager on earlier platform versions will
* be ignored.</p>
*/
public interface PageTransformer {
/**
* Apply a property transformation to the given page.
*
* @param page Apply the transformation to this page
* @param position Position of page relative to the current front-and-center
* position of the pager. 0 is front and center. 1 is one full
* page position to the right, and -1 is one page position to the left.
*/
void transformPage(@NonNull View page, float position);
}
簡單看一下接口描述,直白的翻譯過來,大致意思是:當(dāng)附著于ViewPager中的頁面滑動(dòng)時(shí)谊娇,會(huì)觸發(fā)PageTransformer 實(shí)例(transformPage方法)。PageTransformer 支持用戶通過動(dòng)畫屬性自定義頁面滑動(dòng)效果罗晕。
PageTransformer只有一個(gè)方法: transformPage(@NonNull View page, float position)济欢。該方法的api描述,我想多數(shù)人都沒有搞清楚小渊,尤其是對(duì)position參數(shù)理解法褥,下面就著重講解一下該方法及參數(shù)。
在講解參數(shù)前酬屉,我們先定義兩個(gè)描述語:基準(zhǔn)參考點(diǎn)半等、page頁面間距歸一化
基準(zhǔn)參考點(diǎn)
基準(zhǔn)參考點(diǎn)揍愁,是指ViewPager處于(最近一次處于)SCROLL_STATE_IDLE狀態(tài)(此狀態(tài)下cureent page完整顯示,沒有滑動(dòng)偏移杀饵。備注:若處于滑動(dòng)過程莽囤,則取最近一次處于SCROLL_STATE_IDLE狀態(tài))時(shí)cureent page的position值,為0切距。 transformPage方法中的position都是相對(duì)于這個(gè)基準(zhǔn)參考點(diǎn)的相對(duì)值朽缎。以基準(zhǔn)參考點(diǎn)為中心,建立一維坐標(biāo)谜悟,左側(cè)為負(fù)话肖,右側(cè)為正,來描述page的position值赌躺。
page頁面寬度歸一化
這個(gè)歸一化是指狼牺,將page物理寬度歸一化為1,以此為基礎(chǔ)進(jìn)行page相對(duì)于基準(zhǔn)參考點(diǎn)的position值計(jì)算
根據(jù)以上兩個(gè)描述語的定義礼患,顯然相鄰page間距是1是钥。下面貼上SCROLL_STATE_IDLE狀態(tài)下示意圖:
接下來講解參數(shù):
參數(shù)page是ViewPager持有的頁面(包括cureent page)的rootView,position是page相對(duì)于基準(zhǔn)參考點(diǎn)的偏移量缅叠,滑動(dòng)過程中可標(biāo)識(shí)page的偏移程度悄泥,周期為1。根據(jù)基準(zhǔn)參考點(diǎn)及page頁面寬度歸一化的描述肤粱,在SCROLL_STATE_IDLE狀態(tài)下弹囚,current page的position為0,上一頁的position為-1.0领曼,下一頁的position為1.0鸥鹉,依此類推。position隨ViewaPger滑動(dòng)趨勢發(fā)生相應(yīng)變化:
向左滑動(dòng)時(shí)庶骄,page相對(duì)于基準(zhǔn)參考點(diǎn)向左偏移毁渗,position減小单刁;向右滑動(dòng)時(shí)page相對(duì)于基準(zhǔn)參考點(diǎn)向右偏移灸异,position變大,其絕對(duì)值反應(yīng)了page與基準(zhǔn)參考點(diǎn)間的距離羔飞》握粒滑動(dòng)示意圖如下
有了以上說明,我們就可以利用transformPage(@NonNull View page, float position)方法操控page滑動(dòng)效果了逻淌。根據(jù)page參數(shù)么伯,可以拿到page的真實(shí)物理寬度與高度,根據(jù)position計(jì)算動(dòng)效的參數(shù)值卡儒。下面貼出具有層疊效果的PageTransformer實(shí)例代碼:
public class HorizontalStackTransformerWithRotation implements ViewPager.PageTransformer {
private static final float CENTER_PAGE_SCALE = 0.8f;
private int offscreenPageLimit;
private ViewPager boundViewPager;
public HorizontalStackTransformerWithRotation(@NonNull ViewPager boundViewPager) {
this.boundViewPager = boundViewPager;
this.offscreenPageLimit = boundViewPager.getOffscreenPageLimit();
}
@Override
public void transformPage(@NonNull View view, float position) {
int pagerWidth = boundViewPager.getWidth();
float horizontalOffsetBase = (pagerWidth - pagerWidth * CENTER_PAGE_SCALE) / 2 / offscreenPageLimit + DisplayUtil.dp2px(15);
if (position >= offscreenPageLimit || position <= -1) {
view.setVisibility(View.GONE);
} else {
view.setVisibility(View.VISIBLE);
}
if (position >= 0) {
float translationX = (horizontalOffsetBase - view.getWidth()) * position;
view.setTranslationX(translationX);
}
if (position > -1 && position < 0) {
float rotation = position * 30;
view.setRotation(rotation);
view.setAlpha((position * position * position + 1));
} else if (position > offscreenPageLimit - 1) {
view.setAlpha((float) (1 - position + Math.floor(position)));
} else {
view.setRotation(0);
view.setAlpha(1);
}
if (position == 0) {
view.setScaleX(CENTER_PAGE_SCALE);
view.setScaleY(CENTER_PAGE_SCALE);
} else {
float scaleFactor = Math.min(CENTER_PAGE_SCALE - position * 0.1f, CENTER_PAGE_SCALE);
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
}
// test code: view初始化時(shí)蹦狂,設(shè)置了tag
String tag = (String) view.getTag();
// LogUtil.e("viewTag" + tag, "viewTag: " + (String) view.getTag() + " --- transformerPosition: " + position + " --- floor: " + Math.floor(position) + " --- childCount: "+ boundViewPager.getChildCount());
ViewCompat.setElevation(view, (offscreenPageLimit - position) * 5);
}
}
為了加深理解誓篱,您可以在初始化item view的時(shí)候,為其設(shè)置一個(gè)tag凯楔,tag值可設(shè)為item在列表中的index,并輸出日志觀察transformPage(View view, float position)方法中position變化情況
完整示例:https://github.com/670832188/TestApp