我們來看一下效果圖:
背景
在開發(fā)項(xiàng)目時(shí),需要對 App的某個(gè)資源模塊進(jìn)行界面重構(gòu),其中在資源展示部分中新的交互以卡片疊加的效果替代了原來的資源組織樹門禁展示方式疾捍。在新的資源展示方式中羡洛,每一個(gè)新的卡片都是在最上面的,其順序以棧的形式存儲在內(nèi)存迫肖。卡片支持疊加效果攒驰,左右滑動切換到下一頁或上一頁蟆湖,且卡片中的資源是以列表的形式展示,支持上下滑動玻粪,上拉刷新隅津,下拉加載更多。目前網(wǎng)上存在的卡片布局第三方庫劲室,并不能滿足我們的項(xiàng)目需求伦仍,有的是無法達(dá)到疊加效果,有的會是卡片中不能有列表很洋,否則會產(chǎn)生View滑動事件沖突充蓝,導(dǎo)致列表無法滑動,因此考慮使用已有的知識,自己實(shí)現(xiàn)這樣的功能谓苟。
實(shí)現(xiàn)? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
在Android系統(tǒng)中官脓,沒有能直接能實(shí)現(xiàn)該效果的控件,可以實(shí)現(xiàn)左右滑動切換頁面的控件首先想到ViewPager娜谊,但ViewPager并不能直接實(shí)現(xiàn)頁面疊加效果确买,通過查閱資料,發(fā)現(xiàn)可以自定義ViewPager.PageTransformer接口去控制ViewPager中各個(gè)頁面的偏移顯示效果纱皆。
編碼嘗試:
1湾趾、創(chuàng)建基本界面結(jié)構(gòu):
首先我們先創(chuàng)建一個(gè)Activity,配置好頁面派草,就像以下效果搀缠。一個(gè)ViewPager,里面放View。還需要給ViewPager的setOffscreenPageLimit一個(gè)大一點(diǎn)的值近迁,這樣可以使Viewpager預(yù)加載多個(gè)頁面艺普。
正常情況下,ViewPager里面的內(nèi)容是水平排列的鉴竭,如下圖:
現(xiàn)在要做的第一步歧譬,就是將ViewPager里面所有的view都顯示在同一個(gè)位置,那么就需要自定義PageTransformer去實(shí)現(xiàn)了搏存。
自定義PageTransformer:
PageTransformer介紹瑰步,當(dāng)ViewPager中頁面滑動切換時(shí),將會回調(diào)方法transformPage(View page, float position)璧眠;該方法有兩個(gè)參數(shù)缩焦,第一個(gè)view當(dāng)然就是當(dāng)前正在滑動的頁面,第二個(gè)是一個(gè)float類型的值责静,不是我們平常見到的position位置袁滥,而是當(dāng)前滑動狀態(tài)的表示,相對于當(dāng)前position的position灾螃。它有三個(gè)臨界值-1 0 1题翻,0代表當(dāng)前屏幕顯示的view的position,1代表當(dāng)前view的下一個(gè)view所在的position腰鬼,-1代表當(dāng)前view的前一個(gè)view所在的position
當(dāng)前view左滑藐握、右滑時(shí)各個(gè)view positon的變化情況:
既然ViewPager里面的View默認(rèn)是水平排列的,那么只要將每個(gè)view的x軸坐標(biāo)更改為:view的寬度乘以下標(biāo)的負(fù)數(shù)垃喊,這樣就排列在一起了,為了方便起見袜炕,還給view增加了一個(gè)透明度本谜。代碼如下:
public void transformPage(View page, float position) {
??????? //設(shè)置透明度
??????? page.setAlpha(0.5f);
??????? //設(shè)置每個(gè)View在中間,即設(shè)置相對原位置偏移量
??????? page.setTranslationX((-page.getWidth() * position));?
}
具體效果如下:
卡片都疊加在了一起偎窘,說明X方向水平偏移達(dá)到了預(yù)期效果乌助,然后還需要實(shí)現(xiàn)卡片在Y方向垂直偏移溜在,和卡片大小的縮放操作,就可以實(shí)現(xiàn)疊加效果了他托,定義了一個(gè)變量mOffset表示偏移量掖肋,賦值為40px。
@Override
public?void?transformPage(View?page,?float?position)?{
if?(position?>?0){
//移動X軸坐標(biāo)赏参,使得卡片在同一坐標(biāo)
page.setTranslationX(-position?*?page.getWidth());
//縮放卡片并調(diào)整位置
float?scale?=?(page.getWidth()?-?mOffset?*?position)?/?page.getWidth();
page.setScaleX(scale);
page.setScaleY(scale);
//移動Y軸坐標(biāo)
page.setTranslationY(position?*?mOffset);
}
}
為啥這里只處理position>0的情況呢志笼,因?yàn)閿?shù)據(jù)源中最新的那個(gè)數(shù)據(jù)放在list中的第0個(gè),所以
要滑動下一個(gè)把篓,是用手指往右往左滑動的纫溃,那么我們只要把position>0的那些view都設(shè)置
translationX坐標(biāo)讓他們疊到第一個(gè)view的下面就行了,然后就設(shè)置他們的translationY
那我們怎么實(shí)現(xiàn)拿手勢從左往右滑看歷史呢韧掩,我們就要把數(shù)據(jù)源中最新的那條數(shù)據(jù)放到list的最后一個(gè)紊浩,
然后進(jìn)去后讓viewpager定位到最后一頁,然后我們要處理position<0的那些view就行了
public?class?CardTransformer?implements?ViewPager.PageTransformer?{
private?int?mOffset?=?40;
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public?void?transformPage(View?page,?float?position)?{
if?(position?<=0)?{
page.setTranslationX(-position?*?page.getWidth());
//縮放卡片并調(diào)整位置
float?scale?=?(page.getWidth()?+?mOffset?*?position)?/?page.getWidth();
page.setScaleX(scale);
page.setScaleY(scale);
//移動Y軸坐標(biāo)
page.setTranslationY(-position?*?mOffset);
page.setTranslationZ(position);
}
}
}
這個(gè)translationZ是什么作用呢疗锐,其實(shí)是設(shè)置view的層級坊谁,translationZ越大,說明他的層級越高
所以position = -1的view的層級就比position=0的view的層級低滑臊,那么position=0的view就會疊在
position=-1的view的上面口芍,這樣就實(shí)現(xiàn)了效果
項(xiàng)目的代碼在https://github.com/nickgao1986/ViewPaperSwitch
如果喜歡這個(gè)效果,請幫忙點(diǎn)個(gè)贊简珠,謝謝