Android ViewPager.PageTransformer詳解

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末锦募,一起剝皮案震驚了整個(gè)濱河市摆屯,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌糠亩,老刑警劉巖虐骑,帶你破解...
    沈念sama閱讀 221,430評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異赎线,居然都是意外死亡廷没,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,406評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門垂寥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來颠黎,“玉大人,你說我怎么就攤上這事滞项∠凉椋” “怎么了?”我有些...
    開封第一講書人閱讀 167,834評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵文判,是天一觀的道長过椎。 經(jīng)常有香客問我,道長戏仓,這世上最難降的妖魔是什么疚宇? 我笑而不...
    開封第一講書人閱讀 59,543評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮赏殃,結(jié)果婚禮上敷待,老公的妹妹穿的比我還像新娘。我一直安慰自己嗓奢,他們只是感情好讼撒,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,547評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著股耽,像睡著了一般根盒。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上物蝙,一...
    開封第一講書人閱讀 52,196評(píng)論 1 308
  • 那天炎滞,我揣著相機(jī)與錄音,去河邊找鬼诬乞。 笑死册赛,一個(gè)胖子當(dāng)著我的面吹牛钠导,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播森瘪,決...
    沈念sama閱讀 40,776評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼牡属,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了扼睬?” 一聲冷哼從身側(cè)響起逮栅,我...
    開封第一講書人閱讀 39,671評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎窗宇,沒想到半個(gè)月后措伐,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,221評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡军俊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,303評(píng)論 3 340
  • 正文 我和宋清朗相戀三年侥加,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片粪躬。...
    茶點(diǎn)故事閱讀 40,444評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡担败,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出短蜕,到底是詐尸還是另有隱情氢架,我是刑警寧澤,帶...
    沈念sama閱讀 36,134評(píng)論 5 350
  • 正文 年R本政府宣布朋魔,位于F島的核電站岖研,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏警检。R本人自食惡果不足惜孙援,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,810評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望扇雕。 院中可真熱鬧拓售,春花似錦、人聲如沸镶奉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,285評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽哨苛。三九已至鸽凶,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間建峭,已是汗流浹背玻侥。 一陣腳步聲響...
    開封第一講書人閱讀 33,399評(píng)論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留亿蒸,地道東北人凑兰。 一個(gè)月前我還...
    沈念sama閱讀 48,837評(píng)論 3 376
  • 正文 我出身青樓掌桩,卻偏偏與公主長得像,于是被迫代替她去往敵國和親姑食。 傳聞我的和親對(duì)象是個(gè)殘疾皇子波岛,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,455評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容