1. 程式人生 > >一個卡片式的ViewPager,帶你玩轉ViewPager的PageTransformer屬性!

一個卡片式的ViewPager,帶你玩轉ViewPager的PageTransformer屬性!

ViewPager的基本用法不必多說,這都很簡單,我們可以在ViewPager中載入一個ImageView,也可以載入一個Fragment,這都是目前非常常見的用法。那麼我今天說的是ViewPager中的PageTransformer屬性,用好這個屬性可以讓我們的應用更加出彩,OK,那我們就開始吧!

本文將從如下幾方面來介紹:

1.clipChildren屬性
2.一個頁面顯示多個ViewPager的Item
3.初識PagerTransformer
4.進一步瞭解PagerTransformer
5.ViewPager結合CardView

1.clipChildren屬性

clipChildren屬性表示是否限制子控制元件在該容器所在的範圍內,clipChildren屬性配合layout_gravity屬性,可以用來設定多餘部分的顯示位置,我這裡舉一個簡單的例子,比如喜馬拉雅FM這個應用的首頁:

大家注意看這個應用底部導航欄中中間一個是要比另外四個高的,這種效果很多人就會想到使用一個RelativeLayout佈局來實現,其實不用那麼麻煩,這種效果一個clipChildren屬性就能實現,示例Demo如下:

程式碼:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:clipChildren="false"
    tools:context="org.lenve.clipchildren.MainActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="48dp"
        android:layout_alignParentBottom="true"
        android:background="#03b9fc"
        android:orientation="horizontal">

        <ImageView
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:src="@mipmap/ic_launcher"/>

        <ImageView
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:src="@mipmap/ic_launcher"/>

        <ImageView
            android:layout_width="0dp"
            android:layout_height="72dp"
            android:layout_gravity="bottom"
            android:layout_weight="1"
            android:src="@mipmap/ic_launcher"/>

        <ImageView
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:src="@mipmap/ic_launcher"/>

        <ImageView
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:src="@mipmap/ic_launcher"/>
    </LinearLayout>
</RelativeLayout>

大家看只需要在根節點新增clipChildren屬性,然後在第三個ImageView上新增layout_gravity屬性即可,layout_gravity屬性值為bottom表示控制元件大小超出後控制元件底部對齊。效果如下:

OK,上面是對clipChildren屬性一個簡單介紹,算是一個鋪墊,接下來我們來看看ViewPager。

2.一個頁面顯示多個ViewPager的Item

我們要來解決的第一個問題是如何在一個頁面上顯示ViewPager的多個item,一共有兩種解決方案,第一種就是我們上文所說的clipChildren屬性,第二種是clipToPadding屬性,我們先來看看使用第一種屬性設定的ViewPager:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:clipChildren="false"
    tools:context="org.lenve.myviewpagercards.MainActivity">

    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="200dp"
        android:layout_marginLeft="60dp"
        android:layout_marginRight="60dp"
        android:clipChildren="false"></android.support.v4.view.ViewPager>
</RelativeLayout>

只需要在父容器和ViewPager中都新增上clipChildren屬性,然後給ViewPager設定左右兩個margin,使其不致於把整個螢幕佔滿,就是這麼簡單,我們再來看看ViewPager的Adapter:
public class MyVpAdater extends PagerAdapter {
    private List<Integer> list;
    private Context context;

    public MyVpAdater(Context context, List<Integer> list) {
        this.context = context;
        this.list = list;
    }

    @Override
    public int getCount() {
        return list.size();
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view == object;
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        ImageView iv = new ImageView(context);
        iv.setImageResource(list.get(position));
        container.addView(iv);
        return iv;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        container.removeView((View) object);
    }
}

最後再來看看Activity中的程式碼:
ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);
        viewPager.setPageMargin(80);
        viewPager.setOffscreenPageLimit(3);
        List<Integer> list = new ArrayList<>();
        list.add(R.drawable.p001);
        list.add(R.drawable.p002);
        list.add(R.drawable.p003);
        list.add(R.drawable.p004);
        list.add(R.drawable.p005);
        MyVpAdater adater = new MyVpAdater(this, list);
        viewPager.setAdapter(adater);

比我們一般使用ViewPager多了兩行程式碼,一個是setOffscreenPageLimit,這個是設定預載入的頁數,我們知道預設情況下這個引數為1,也就是左右各預載入一頁,但是我們這裡要讓左右各預載入兩頁,原因一會再說,另外一個PageMargin就好說了,就是設定ViewPager中兩頁之間的距離。OK,那我們來看看顯示效果:

OK,就是這麼簡單,這樣,我們現在已經可以在一個頁面上來顯示多個ViewPager中的item,接下來我們先來看看PageTransformer的簡單使用。

3.初識PagerTransformer

我們知道可以給ViewPager設定一個setPagerTransformer屬性,設定時候需要我們自己來實現PagerTransformer介面,實現這個介面的時候要實現該介面中的方法,transformPage,該方法接收兩個引數,其中一個是position,如果你直接列印position出來可能會看得你雲裡霧裡,實際上position表示的是第一個引數View的position,把這兩個引數一起打印出來就可以找到規律了:

比如從第1頁滑動到第2頁:

第一頁position的變化為  [0,-1]

第二頁position的變化為  [1,0]

知道了這個我們就可以寫一個簡單的切換動畫了,我希望頁面上正中間的item是正常的,兩邊的item都有一點透明度。那我們可以使用如下方式來定義:

public class AlphaTransformer implements ViewPager.PageTransformer {
    private float MINALPHA = 0.5f;

    /**
     * position取值特點:
     * 假設頁面從0~1,則:
     * 第一個頁面position變化為[0,-1]
     * 第二個頁面position變化為[1,0]
     *
     * @param page
     * @param position
     */
    @Override
    public void transformPage(View page, float position) {
        if (position < -1 || position > 1) {
            page.setAlpha(MINALPHA);
        } else {
            //不透明->半透明
            if (position < 0) {//[0,-1]
                page.setAlpha(MINALPHA + (1 + position) * (1 - MINALPHA));
            } else {//[1,0]
                //半透明->不透明
                page.setAlpha(MINALPHA + (1 - position) * (1 - MINALPHA));
            }
        }
    }
}

定義好了之後再設定給ViewPager即可:
viewPager.setPageTransformer(false, new AlphaTransformer());

我們再來看看執行效果:

OK,透明度的效果已經有了。很簡單吧!

4.進一步瞭解PagerTransformer

上面是一個簡答的效果,遵循這個思路,我們可以做出更多的效果,比如下面這個效果:

這是一個非常常見的效果,實現思路和前文一致,就是讓ImageView動態縮放。那我們來看看這裡的PagerTransformer:

public class ScaleTransformer implements ViewPager.PageTransformer {
    private static final float MIN_SCALE = 0.70f;
    private static final float MIN_ALPHA = 0.5f;

    @Override
    public void transformPage(View page, float position) {
        if (position < -1 || position > 1) {
            page.setAlpha(MIN_ALPHA);
            page.setScaleX(MIN_SCALE);
            page.setScaleY(MIN_SCALE);
        } else if (position <= 1) { // [-1,1]
            float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position));
            if (position < 0) {
                float scaleX = 1 + 0.3f * position;
                Log.d("google_lenve_fb", "transformPage: scaleX:" + scaleX);
                page.setScaleX(scaleX);
                page.setScaleY(scaleX);
            } else {
                float scaleX = 1 - 0.3f * position;
                page.setScaleX(scaleX);
                page.setScaleY(scaleX);
            }
            page.setAlpha(MIN_ALPHA + (scaleFactor - MIN_SCALE) / (1 - MIN_SCALE) * (1 - MIN_ALPHA));
        }
    }
}

然後給ViewPager設定相應的PagerTransformer:
viewPager.setPageTransformer(false, new ScaleTransformer());

就是這麼簡單。其它複雜的旋轉平移等都是按照這個思路來實現,這裡不再贅述。

5.ViewPager結合CardView

如果你還不會使用CardView,可以參考我之前的文章Android5.0之CardView的使用,那今天我們來看看ViewPager結合CardView會產生怎樣的效果呢?

那麼在這之前,我想先介紹一個屬性,那就是clipToPadding,這個屬性是什麼意思呢?它表示是否允許ViewGroup在ViewGroup的padding中進行繪製,預設情況下該屬性的值為true,即不允許在ViewGroup的padding中進行繪製。那如果我設定了false呢?我們來看看:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="org.lenve.myviewpagercards2.MainActivity">

    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="200dp"
        android:clipToPadding="false"
        android:paddingBottom="24dp"
        android:paddingLeft="48dp"
        android:paddingRight="48dp"
        android:paddingTop="24dp"></android.support.v4.view.ViewPager>
</RelativeLayout>

ViewPager的Adapter如下:
public class MyAdapter extends PagerAdapter {
    private List<Integer> list;
    private Context context;

    public MyAdapter(Context context, List<Integer> list) {
        this.context = context;
        this.list = list;
    }

    @Override
    public int getCount() {
        return list.size();
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view == object;
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        ImageView iv = new ImageView(context);
        iv.setImageResource(list.get(position));
        container.addView(iv);
        return iv;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        container.removeView((View) object);
    }
}

Activity中的程式碼:
        ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);
        List<Integer> list = new ArrayList<>();
        list.add(R.drawable.p001);
        list.add(R.drawable.p002);
        list.add(R.drawable.p003);
        list.add(R.drawable.p004);
        list.add(R.drawable.p005);
        MyAdapter adapter = new MyAdapter(this, list);
        viewPager.setAdapter(adapter);
        viewPager.setPageMargin(20);

顯示效果如下:

OK,那這個clipToPadding屬性是我們在一個頁面中顯示多個ViewPager  item的第二種方式。這個CardView式的ViewPager我們就使用這種方式來實現。先來看看效果圖:

整體思路和上文其實是一致的,我們來看看activity的佈局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="org.lenve.myviewpagercards2.MainActivity">

    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="300dp"
        android:clipToPadding="false"
        android:paddingBottom="24dp"
        android:paddingLeft="80dp"
        android:paddingRight="80dp"
        android:paddingTop="24dp"></android.support.v4.view.ViewPager>
</RelativeLayout>

ViewPager中每一個item的佈局:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView android:id="@+id/cardview"
                                    xmlns:android="http://schemas.android.com/apk/res/android"
                                    xmlns:app="http://schemas.android.com/apk/res-auto"
                                    android:layout_width="match_parent"
                                    android:layout_height="wrap_content"
                                    android:orientation="vertical"
                                    app:cardCornerRadius="10dp">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="300dp">

        <TextView
            android:id="@+id/tv"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:gravity="center"
            android:text="我是一個TextView"/>

        <Button
            android:layout_width="96dp"
            android:layout_height="36dp"
            android:textColor="#ffffff"
            android:layout_below="@id/tv"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="12dp"
            android:background="@color/colorAccent"
            android:text="我是一個按鈕"/>
    </RelativeLayout>
</android.support.v7.widget.CardView>

Adapter:
public class MyAdapter extends PagerAdapter {
    private List<Integer> list;
    private Context context;
    private LayoutInflater inflater;

    public MyAdapter(Context context, List<Integer> list) {
        this.context = context;
        this.list = list;
        inflater = LayoutInflater.from(context);
    }
    @Override
    public int getCount() {
        return list.size();
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view == object;
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        View view = inflater.inflate(R.layout.vp_item, container, false);
        container.addView(view);
        return view;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        container.removeView((View) object);
    }
}

Activity中的程式碼:
ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);
        List<Integer> list = new ArrayList<>();
        list.add(R.drawable.p001);
        list.add(R.drawable.p002);
        list.add(R.drawable.p003);
        list.add(R.drawable.p004);
        list.add(R.drawable.p005);
        MyAdapter adapter = new MyAdapter(this, list);
        viewPager.setAdapter(adapter);
        viewPager.setPageMargin((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                48, getResources().getDisplayMetrics()));
        viewPager.setPageTransformer(false, new ScaleTransformer(this));

最後再來看看我們定義的PageTransformer:
public class ScaleTransformer implements ViewPager.PageTransformer {
    private Context context;
    private float elevation;

    public ScaleTransformer(Context context) {
        this.context = context;
        elevation = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                20, context.getResources().getDisplayMetrics());
    }

    @Override
    public void transformPage(View page, float position) {
        if (position < -1 || position > 1) {

        } else {
            if (position < 0) {
                ((CardView) page).setCardElevation((1 + position) * elevation);
            } else {
                ((CardView) page).setCardElevation((1 - position) * elevation);
            }
        }
    }
}

很簡單,我只是對CardView的陰影做了處理 ,其他屬性都沒改,這樣就有了我們剛才看到的效果。

參考資料:

以上。

相關推薦

一個片式ViewPagerViewPager的PageTransformer屬性

ViewPager的基本用法不必多說,這都很簡單,我們可以在ViewPager中載入一個ImageView,也可以載入一個Fragment,這都是目前非常常見的用法。那麼我今天說的是ViewPager中的PageTransformer屬性,用好這個屬性可以讓我們的應用更加出彩

一個簡單的例子理解haproxy

如果你對haproxy啥都不懂,這篇文章將對你有很大的幫助。大神請繞行! haproxy是一個性能不輸於nginx的工具。和nginx功能類似,可以實現負載均衡。他與nginx不同的是,haproxy既可以實現基於http的七層架構,又可以實現基於tcp/udp的四層架構。 [[email&

ET錢包糖果秒變現

之前跟大家分享過如何在ET錢包中通過PRA糖果盒領取糖果代幣,今天跟大家聊一聊如何將ET錢包賬戶中的糖果代幣變現成EOS代幣。我們選擇在【Newdex交易所】交易。 Newdex交易所是什麼? Newdex是目前全球成交量最大的,基於EOS主鏈搭建的去中心化交易所。 玩家在近期上

Android中的反射機制再也不怕private修飾了

前言 在前面寫一些Android原始碼分析的文章中,比如fork程序,SystemServer啟動服務,ActivityThread載入等都會涉及到反射的大量運用,讓我覺得很有必要針對反射機制寫一篇部落格進行總結 相關知識點 在講解反射前先說明一些知識點以做鋪

應用之星H5頁面和app開發不懂技術的看過來

智慧手機更新換代日新月異,其功能已經滿足我們的日常需求了,那麼手機內的應用程式是不是還沒有徹底滿足你的個性化需求?沒有一款按照你意願發展的app?如果是的話,那麼恭喜你,今天的這篇文章就是為你而準備。看完這篇文章後,相信你完全可以定製一款屬於自己的專屬應用app,而且這個

公開課 | 獨家首發:微軟Hackathon冠軍隊新零售堪比外掛的祕笈分享

大家好,文摘菌又來搞事情啦~本次公開課,大資料文摘邀請到了【微軟大中華區 零售解決方案新創業黑客鬆】大賽上海站冠軍團隊成員之一、觀遠資料合夥人周遠(位元組)。他將從賽題背景、資料探索、特徵工程、模型調優

【宇哥MySQL】索引篇(一)索引揭祕看他是如何讓的查詢效能指數提升的

  場景復現,一個索引提高600倍查詢速度? 首先準備一張books表 create table books( id int not null primary key auto_increment, name varchar(255) not null, author va

【幹貨篇】步步為營輕松掌握jQuery

red submit 所有 onf rec 選中 jquer 分別是 綁定 寫在前面: 經過系統的學習了原生JS之後,會發現其具有以下三個特點: 1、是一種解釋性腳本語言(代碼不進行預編譯)。 2、主要用來向 HTML 頁面添加交互行為。 3、可以直接嵌入 HTML

1分鐘Kafka

Kafka 分布式 消息服務 說起Kafka,許多使用者對它是又愛又恨。Kafka是一種分布式的、基於發布/訂閱的消息系統,其極致體驗讓人欲罷不能,但操心的運維、復雜的安全策略、可靠性易用性的缺失、算不上極致的性能發揮、並不豐富的消息服務功能,仍需要使用者付出諸多的背後工作。即使你是Kafka老手

資深程序員深度學習中的正則化技術(附Python代碼)

c51 進行 ros batch num 簡單的 oat 深度學習 repr 目錄 1. 什麽是正則化? 2. 正則化如何減少過擬合? 3. 深度學習中的各種正則化技術: L2和L1正則化 Dropout 數據增強(Data augmentation) 提前停止(Ear

百曉生linux系統服務搭建系列----DNS服務的搭建一(正向解析)

home 主配置文件 baidu 安裝環境 圖片 搭建 href ace eid DNS正向解析的搭建 實驗環境系統環境:centos6.5 安裝DNS環境軟件包rpm -ivh /mnt/Packages/bind-9.8.2-0.17.rc1.el6_4.6.x86_

百曉生linux系統服務搭建系列----pxe遠程安裝服務器的搭建及無人值守安裝

conf fig ces sys 鏡像文件 mount size set blog 實驗環境系統環境:centos6.5:程安裝服務器WIN7:客戶端一、pxe遠程安裝服務器的搭建 安裝並開啟需要的服務,tftp,ftp,dhcp。1) yum -y install t

百曉生linux系統服務搭建系列----SSH遠程訪問及控制

登入 conf rsa nag 系列 配置 上傳 我們 shel 實驗環境:linux centos 6.5*2實驗目的:用戶登錄控制及密鑰對驗證 sshd服務默認允許root用戶登錄,當在Internet中使用時這是非常不安全的。普遍的做法是先以普通用戶遠程登入,進入安全

百曉生linux系統服務搭建系列----構建虛擬ApacheWeb主機

ESS host mon conf 圖片 common roo echo 端口 虛擬Web主機指的是在同一臺服務器中運行多個Web站點,其中的每一個站點實際上並不獨自占用整個服務器,因此被稱為“虛擬”Web主機。通過Web主機服務可以充分利用服務器的硬件資源,從而大大降低網

架構師分布式鎖

src 效率 獲取鎖 當我 mysql 代碼 red 目錄 在線   大多數互聯網系統都是分布式部署的,分布式部署確實能帶來性能和效率上的提升,但為此,我們就需要多解決一個分布式環境下,數據一致性的問題。   當某個資源在多系統之間,具有共享性的時候,為了保證大家訪問這個資

Logview: MaxCompute Logview參數詳解和問題排查

磁盤 兩種 同時 col mage proc ins NPU 優化 摘要: 對於Logview上的諸多參數信息,究竟應該怎麽“撥開雲霧”,發現問題所在呢?又如何通過Logview了解每個instance、task運行狀態及資源占用情況,如何分析執行計劃,分析query存在問

亞洲誠信[2018國家網絡安全宣傳周]上海地區活動

新的 信息安全 信用卡 對手 禮物 徹底 應用程序 活動 通話 為提升全社會的網絡安全意識和安全防護技能,根據中央網信辦統一部署,2018年國家網絡安全宣傳周於9月17日至23日在全國範圍內舉辦,此次宣傳周主題為“網絡安全為人民,網絡安全靠人民”。上海地區的活動由市委網信

六天mysql資料庫--第四天筆記

回顧: 列屬性:主鍵,自增長,唯一鍵 關係:一對一,一對多,多對多 正規化:規範資料庫的設計,三層正規化 1NF:欄位設計必須符合原子性 2NF:不存在部分依賴(沒有複合主鍵) 3NF:不存在傳遞依賴(實體單獨建表) 逆規範化:效率與磁碟空間的博弈 高階資料操作: 新增資料:主

六天mysql資料庫-- 第三天筆記(下)

資料的高階操作: 資料操作:增刪改查 新增資料: 基本語法: insert into 表名 [(欄位列表)] values(值列表); 在資料插入的時候,假設主鍵對應的值已經存在,插入一定會失敗。 主鍵衝突: 當主鍵存在衝突的時候(Duplicate ke

六天mysql資料庫--第三天筆記(中)

索引: 幾乎所有的索引都是建立在欄位之上。 索引:系統根據某種演算法將已有的資料(未來可能新增的資料),單獨建立一個檔案,檔案能夠實現快速的匹配資料, 並且能夠快速的找到對應表中的記錄。索引的意義在於: 1.提升查詢資料的效率 2.約束資料的有效性(唯一性等) 增加索引有前提條件:索引本