本文屬于滑動(dòng)內(nèi)聯(lián)動(dòng)效系列的第二篇。倉(cāng)庫(kù)地址
滑動(dòng)內(nèi)聯(lián)動(dòng)效 指的是 在容器滑動(dòng)的過(guò)程中考传,其子View對(duì)應(yīng)展現(xiàn)出來(lái)的一些效果招拙。本篇主要記錄的是在容器滑動(dòng)過(guò)程中,它的item伴隨進(jìn)行縮放和透明度變化喇勋。
上圖缨该,明了。
圖1中川背,隨著滑動(dòng)贰拿,內(nèi)部item呈現(xiàn)先變大再變小的趨勢(shì),同時(shí)透明度上也是先變亮在變暗的趨勢(shì)渗常。
圖2中壮不,主要是橫向的一些特效,分別有圖片逆差效果皱碘,縮放效果以及透明度變換效果询一。
方案分析
思路基本同滑動(dòng)內(nèi)聯(lián)動(dòng)效的實(shí)現(xiàn)之圖片平行逆差效果,整體還是需要一個(gè)自定義的伴生容器,作為內(nèi)聯(lián)item的父布局健蕊。在實(shí)現(xiàn)方式上還是有些差別菱阵。具體分析步驟如下:
1 獲得外面滑動(dòng)容器的滑動(dòng)事件。
因?yàn)槭亲龌瑒?dòng)內(nèi)聯(lián)效果缩功,那么理應(yīng)得到滑動(dòng)事件才行晴及。還是跟其上篇一樣,使用ViewTreeObserver.OnScrollChangedListener這個(gè)接口嫡锌。2 得到滑動(dòng)容器的位置范圍虑稼。
這個(gè)滑動(dòng)容器可大可小,滑動(dòng)內(nèi)聯(lián)效果肯定是與這個(gè)有關(guān)系的势木。假設(shè)有個(gè)點(diǎn)蛛倦,剛好位于滑動(dòng)容器的最下邊。當(dāng)滑動(dòng)進(jìn)行時(shí)啦桌,這個(gè)點(diǎn)便會(huì)跟著向下移動(dòng)溯壶,當(dāng)其到滑動(dòng)容器最上邊時(shí),這個(gè)點(diǎn)剛好走了滑動(dòng)容器的上下距離甫男。這個(gè)過(guò)程且改,也代表了比較理想的內(nèi)聯(lián)動(dòng)效的起始和最終位置。這個(gè)容器范圍可表示為屏幕上的一個(gè)矩形板驳,這個(gè)矩形可以在滑動(dòng)容器顯示到屏幕上時(shí)動(dòng)態(tài)的設(shè)置給內(nèi)部item又跛。3 確定包裝容器和圖片的內(nèi)聯(lián)滑動(dòng)
滑動(dòng)開始了,也知道什么時(shí)候內(nèi)聯(lián)滑動(dòng)開始了笋庄,那么內(nèi)聯(lián)容器應(yīng)該怎么內(nèi)聯(lián)呢效扫。這個(gè)涉及一些數(shù)學(xué)計(jì)算。與圖片內(nèi)聯(lián)效果有些不同的是直砂,在縮放和透明度變化上菌仁,這里有兩種比較常見(jiàn)的展示。
- 線性計(jì)算:隨著滑動(dòng)静暂,item的屬性線性單調(diào)變化济丘;
- 曲線變化:隨著滑動(dòng),item的屬性先變大再變小洽蛀,使得item位于容器中間時(shí)屬性最明顯摹迷。
這里再聲明一下兩個(gè)概念:
a- 滑動(dòng)容器:即平時(shí)用的具有滑動(dòng)效果的View,比如ListView,RecyclerView郊供;
b- 內(nèi)聯(lián)容器:使其內(nèi)容具有伴生效果的ViewGroup峡碉;
c- 內(nèi)聯(lián)item:在滑動(dòng)容器滑動(dòng)時(shí),具有伴生動(dòng)效的item驮审,其父布局是內(nèi)聯(lián)容器鲫寄,普通item放到內(nèi)聯(lián)容器中吉执,即為內(nèi)聯(lián)item。
代碼實(shí)現(xiàn)
整體實(shí)現(xiàn)思路同滑動(dòng)內(nèi)聯(lián)動(dòng)效的實(shí)現(xiàn)之圖片平行逆差效果地来,效果只是寫幾個(gè)AdStyle戳玫,然后添加到內(nèi)聯(lián)容器中即可。這里以縱向縮放為例未斑,簡(jiǎn)單分析一下咕宿。
public class VerticalScaleStyle extends SimpleStyle implements AdjointStyle {
@Override
public void onAttachedToImageView(AdjointContainer view) {
}
@Override
public void onDetachedFromImageView(AdjointContainer view) {
}
@Override
public void transform(AdjointContainer aContainer, Canvas canvas, int[] viewLocation, Rect parentLocation) {
//獲得內(nèi)聯(lián)容器的y坐標(biāo)
int y = viewLocation[1];
//獲得滑動(dòng)容器的頂部和底部位置
int ptop = parentLocation.top;
int pbottom = parentLocation.bottom;
//獲得內(nèi)聯(lián)容器的內(nèi)部可用寬和高
int vWidth = aContainer.getWidth() - aContainer.getPaddingLeft() - aContainer.getPaddingRight();
int vHeight = aContainer.getHeight() - aContainer.getPaddingTop() - aContainer.getPaddingBottom();
// device's height
int dHeight = ScreenUtil.getScreenHeight(aContainer.getContext());
//取滑動(dòng)低點(diǎn)
dHeight = dHeight < pbottom ? dHeight : pbottom;
// 避免過(guò)度滑動(dòng)
if (y < ptop - vHeight) {
y = ptop - vHeight;
} else if (y > dHeight) {
y = dHeight;
}
y = y - ptop;
int itemMaxMoveScope = pbottom - ptop - vHeight;
float index = y;
if (index <= 0) {
index = 1.0f;
}
if (index >= itemMaxMoveScope) {
index = itemMaxMoveScope;
}
float al = 1.0f;
//是否線性計(jì)算
if (isLinearable()) {
if (index < getLinearPos() * itemMaxMoveScope) {
index = 0;
}
al = (1 - getMinScale()) * (itemMaxMoveScope - index) / itemMaxMoveScope + getMinScale();
} else {//非線性實(shí)現(xiàn)
al = (4 * getMinScale() - 4.0f) * index * index / (itemMaxMoveScope * itemMaxMoveScope)
+ (4.0f - 4 * getMinScale()) * index / itemMaxMoveScope + getMinScale();
}
//設(shè)置最小的縮放比例
if (al < getMinScale()) {
al = getMinScale();
}
al = al * getFactor();
canvas.scale(al, al, vWidth/2, vHeight*getPrivotY());
}
}
使用方式
整體實(shí)現(xiàn)思路同滑動(dòng)內(nèi)聯(lián)動(dòng)效的實(shí)現(xiàn)之圖片平行逆差效果,簡(jiǎn)述為:
- 布局蜡秽,內(nèi)聯(lián)容器作為需要內(nèi)聯(lián)item的容器府阀;
- 設(shè)置區(qū)域,給內(nèi)聯(lián)容器設(shè)置滑動(dòng)容器的矩形區(qū)域芽突;
- 創(chuàng)建一個(gè)或多個(gè)AdjointStyle肌似,添加到內(nèi)聯(lián)容器中。
此時(shí)诉瓦,若是設(shè)置得當(dāng),便會(huì)得到內(nèi)部item隨滑動(dòng)容器滑動(dòng)力细,出現(xiàn)平行逆差/縮放和透明度變化的一種展示效果睬澡。