Android翻頁效果原理實(shí)現(xiàn)之曲線的實(shí)現(xiàn)
來源:程序員人生 發(fā)布時(shí)間:2015-01-21 08:29:31 閱讀次數(shù):7203次
尊重原創(chuàng)轉(zhuǎn)載請注明:From AigeStudio(http://blog.csdn.net/aigestudio)Power by Aige 侵權(quán)必究!
炮兵
鎮(zhèn)樓
上1節(jié)我們通過引入折線實(shí)現(xiàn)了頁面的折疊翻轉(zhuǎn)效果,有了前面兩節(jié)的基礎(chǔ)呢其實(shí)曲線的實(shí)現(xiàn)可以變得非常簡單,為何這么說呢?由于曲線不過就是在折線的基礎(chǔ)上對Path加入了曲線的實(shí)現(xiàn),進(jìn)而只是影響了我們的Region區(qū)域,而其他的甚么事件啊、滑動(dòng)計(jì)算啊之類的幾近都是不變的對吧,說白了就是對現(xiàn)有的折線View進(jìn)行update改造,雖然是改造,但是我們該如何下手呢?首先我們來看看現(xiàn)實(shí)中翻頁的效果應(yīng)當(dāng)是怎樣的呢?如果大家身旁有書或本子乃至1張紙也行,嘗試以不同的方式去翻動(dòng)它,你會(huì)發(fā)現(xiàn)除我們前面兩節(jié)曾提到過的1些限制外,還有1些special的現(xiàn)象:
1、翻起來的區(qū)域從側(cè)面來看是1個(gè)有弧度的區(qū)域,如圖所示側(cè)面圖:

而我們將依照第1節(jié)中的約定疏忽這部份弧度的表現(xiàn),由于從正俯視的角度我們壓根看不到弧度的效果,So~我們強(qiáng)迫讓其與頁面平行:

2、根據(jù)拖拽點(diǎn)距離頁面高度的不同,我們可以得到不同的卷曲度:

而其在我們正俯視點(diǎn)的表現(xiàn)則是曲線的弧度不同:

一樣的,我們依照第1節(jié)的約定,為了簡化問題,我們將拖拽點(diǎn)距離頁面的高度視為1個(gè)定值使在我們正俯視點(diǎn)表現(xiàn)的曲線出發(fā)點(diǎn)從距離控件交點(diǎn)1/4處開始:

3、如上1節(jié)末所說,在曲折的區(qū)域圖象也會(huì)有相似的扭曲效果
OK,大致的1個(gè)分析就是這樣,我們根據(jù)分析結(jié)果可以得出下面的1個(gè)分析圖:

由上圖配合我們上面的分析我們可知:DB = 1/4OB,F(xiàn)A = 1/4OA,而點(diǎn)F和點(diǎn)D分別為兩條曲線(如無特殊聲明,我們所說的曲線均為貝賽爾曲線,下同)的出發(fā)點(diǎn)(固然你也能夠說是終點(diǎn)無所謂),這時(shí)候,我們以點(diǎn)A、B為曲線的控制點(diǎn)并以其為端點(diǎn)分別沿著x軸和y軸方向作線段AG、BC,另AG = AF、BC = BD,并令點(diǎn)G、C分別為曲線的終點(diǎn),這樣,我們的這兩條2階貝塞爾曲線就非常非常的特殊,例如上圖中的曲線DC,它是由起始點(diǎn)D、C和控制點(diǎn)B構(gòu)成,而BD = BC,也就是說3角形BDC是的等腰3角形,進(jìn)1步地說就是曲線DC的兩條控制桿力臂相等,進(jìn)1步地我們可以推斷出曲線DC的頂點(diǎn)J一定在直線DC的中垂線上,更進(jìn)1步地我們可以根據(jù)《自定義控件其實(shí)很簡單5/12》所說的2階貝塞爾曲線公式得出當(dāng)且僅當(dāng)t
= 0.5時(shí)曲線的端點(diǎn)恰好會(huì)在頂點(diǎn)J上,由此我們可以非常非常簡單地得到曲線的頂點(diǎn)坐標(biāo)。好了,YY歸YY我們還是要回歸到具體的操作中來,首先,我們要計(jì)算出點(diǎn)G、F、D、C的坐標(biāo)值,這4點(diǎn)坐標(biāo)也相當(dāng)easy,就拿F點(diǎn)坐標(biāo)來講,我們過點(diǎn)F分別作OM、AM的垂線:

由于FA = 1/4OA,那末我們可以得到F點(diǎn)的x坐標(biāo)Fx = a + 3/4MA,y坐標(biāo)Fy = b + 3/4OM,而G點(diǎn)的x坐標(biāo)Gx = a + MA - 1/4x;其他兩點(diǎn)D、C就不多扯了,那末在代碼中如何體現(xiàn)呢?首先,為了便于視察效果,我們先注釋掉圖片的繪制:
/*
* 如果坐標(biāo)點(diǎn)在原點(diǎn)(即還沒產(chǎn)生觸碰時(shí))則繪制第1頁
*/
if (mPointX == 0 && mPointY == 0) {
// canvas.drawBitmap(mBitmaps.get(mBitmaps.size() - 1), 0, 0, null);
return;
}
// 省略大量代碼
//drawBitmaps(canvas);
并繪制線條:
canvas.drawPath(mPath, mPaint);
在上1節(jié)中我們在生成Path時(shí)將情況分為了兩種:
if (sizeLong > mViewHeight) {
//…………………………
} else {
//…………………………
}
一樣,我們也分開處理兩種情況,那末針對sizeLong > mViewHeight的時(shí)候此時(shí)控件頂部的曲線效果已是看不到了,我們只需斟酌底部的曲線效果:
// 計(jì)算曲線出發(fā)點(diǎn)
float startXBtm = btmX2 - CURVATURE * sizeShort;
float startYBtm = mViewHeight;
// 計(jì)算曲線終點(diǎn)
float endXBtm = mPointX + (1 - CURVATURE) * (tempAM);
float endYBtm = mPointY + (1 - CURVATURE) * mL;
// 計(jì)算曲線控制點(diǎn)
float controlXBtm = btmX2;
float controlYBtm = mViewHeight;
// 計(jì)算曲線頂點(diǎn)
float bezierPeakXBtm = 0.25F * startXBtm + 0.5F * controlXBtm + 0.25F * endXBtm;
float bezierPeakYBtm = 0.25F * startYBtm + 0.5F * controlYBtm + 0.25F * endYBtm;
/*
* 生成帶曲線的4邊形路徑
*/
mPath.moveTo(startXBtm, startYBtm);
mPath.quadTo(controlXBtm, controlYBtm, endXBtm, endYBtm);
mPath.lineTo(mPointX, mPointY);
mPath.lineTo(topX1, 0);
mPath.lineTo(topX2, 0);
mPath.lineTo(bezierPeakXBtm, bezierPeakYBtm);
該部份的實(shí)際效果以下:

PS:為了便于大家對參數(shù)的理解,我對每個(gè)點(diǎn)的坐標(biāo)都重新給予了1個(gè)援用其命名也淺顯易懂,實(shí)際進(jìn)程可以省略這1步簡化代碼
而當(dāng)sizeLong <= mViewHeight時(shí)這時(shí)候候不但底部有曲線效果,右邊也有:
/*
* 計(jì)算參數(shù)
*/
float leftY = mViewHeight - sizeLong;
float btmX = mViewWidth - sizeShort;
// 計(jì)算曲線出發(fā)點(diǎn)
float startXBtm = btmX - CURVATURE * sizeShort;
float startYBtm = mViewHeight;
float startXLeft = mViewWidth;
float startYLeft = leftY - CURVATURE * sizeLong;
/*
* 限制左邊曲線出發(fā)點(diǎn)
*/
if (startYLeft <= 0) {
startYLeft = 0;
}
/*
* 限制右邊曲線出發(fā)點(diǎn)
*/
if (startXBtm <= 0) {
startXBtm = 0;
}
// 計(jì)算曲線終點(diǎn)
float endXBtm = mPointX + (1 - CURVATURE) * (tempAM);
float endYBtm = mPointY + (1 - CURVATURE) * mL;
float endXLeft = mPointX + (1 - CURVATURE) * mK;
float endYLeft = mPointY - (1 - CURVATURE) * (sizeLong - mL);
// 計(jì)算曲線控制點(diǎn)
float controlXBtm = btmX;
float controlYBtm = mViewHeight;
float controlXLeft = mViewWidth;
float controlYLeft = leftY;
// 計(jì)算曲線頂點(diǎn)
float bezierPeakXBtm = 0.25F * startXBtm + 0.5F * controlXBtm + 0.25F * endXBtm;
float bezierPeakYBtm = 0.25F * startYBtm + 0.5F * controlYBtm + 0.25F * endYBtm;
float bezierPeakXLeft = 0.25F * startXLeft + 0.5F * controlXLeft + 0.25F * endXLeft;
float bezierPeakYLeft = 0.25F * startYLeft + 0.5F * controlYLeft + 0.25F * endYLeft;
/*
* 生成帶曲線的3角形路徑
*/
mPath.moveTo(startXBtm, startYBtm);
mPath.quadTo(controlXBtm, controlYBtm, endXBtm, endYBtm);
mPath.lineTo(mPointX, mPointY);
mPath.lineTo(endXLeft, endYLeft);
mPath.quadTo(controlXLeft, controlYLeft, startXLeft, startYLeft);
效果以下:

Path有了,我們就該斟酌如何將其轉(zhuǎn)換為Region,在這個(gè)進(jìn)程中呢又1個(gè)問題,曲線路徑不像上1節(jié)的直線路徑我們可以輕易取得其范圍區(qū)域,由于我們的折疊區(qū)域其實(shí)應(yīng)當(dāng)是這樣的:

如圖所示紅色路徑區(qū)域,這部份區(qū)域則是我們折疊的區(qū)域,而事實(shí)上我們?yōu)榱擞?jì)算方便將整條2階貝賽爾曲線都繪制了出來,也就是說我們的Path除紅色線條部份還包括了藍(lán)色線條部份對吧,那末問題來了,如何將這兩部份“做掉”呢?其實(shí)方法很多,我們可以在計(jì)算的時(shí)候就只生成半條曲線,這是方法1我們利用純計(jì)算的方式,記得我在該系列文章開頭曾說過翻頁效果的實(shí)現(xiàn)可以有兩種方式,1種是純計(jì)算而另外一種則是利用圖形的組合思想,如何組合呢?這里對區(qū)域的計(jì)算我們就不用純計(jì)算的方式了,我們嘗試用圖形組合來試試。首先我們將Path轉(zhuǎn)為Region看看是甚么樣的:
Region region = computeRegion(mPath);
canvas.clipRegion(region);
canvas.drawColor(Color.RED);
// canvas.drawPath(mPath, mPaint);
效果以下:

可以看到我們沒有封閉的Path構(gòu)成的Region效果,事實(shí)呢跟我們需要的區(qū)域差距有點(diǎn)大,首先上下兩個(gè)月半圓是過剩的,其次目測少了1塊對吧:

如上圖藍(lán)色的那塊,那末我們該如何把這塊“補(bǔ)”回來呢?利用圖形組合的思想,我們想法為該Region補(bǔ)1塊矩形:

然后差集掉兩個(gè)月半圓不就成了?這部份代碼改動(dòng)較大,我先貼代碼再說吧:
if (sizeLong > mViewHeight) {
// 計(jì)算……額……按圖來AN邊~
float an = sizeLong - mViewHeight;
// 3角形AMN的MN邊
float largerTrianShortSize = an / (sizeLong - (mViewHeight - mPointY)) * (mViewWidth - mPointX);
// 3角形AQN的QN邊
float smallTrianShortSize = an / sizeLong * sizeShort;
/*
* 計(jì)算參數(shù)
*/
float topX1 = mViewWidth - largerTrianShortSize;
float topX2 = mViewWidth - smallTrianShortSize;
float btmX2 = mViewWidth - sizeShort;
// 計(jì)算曲線出發(fā)點(diǎn)
float startXBtm = btmX2 - CURVATURE * sizeShort;
float startYBtm = mViewHeight;
// 計(jì)算曲線終點(diǎn)
float endXBtm = mPointX + (1 - CURVATURE) * (tempAM);
float endYBtm = mPointY + (1 - CURVATURE) * mL;
// 計(jì)算曲線控制點(diǎn)
float controlXBtm = btmX2;
float controlYBtm = mViewHeight;
// 計(jì)算曲線頂點(diǎn)
float bezierPeakXBtm = 0.25F * startXBtm + 0.5F * controlXBtm + 0.25F * endXBtm;
float bezierPeakYBtm = 0.25F * startYBtm + 0.5F * controlYBtm + 0.25F * endYBtm;
/*
* 生成帶曲線的4邊形路徑
*/
mPath.moveTo(startXBtm, startYBtm);
mPath.quadTo(controlXBtm, controlYBtm, endXBtm, endYBtm);
mPath.lineTo(mPointX, mPointY);
mPath.lineTo(topX1, 0);
mPath.lineTo(topX2, 0);
/*
* 替補(bǔ)區(qū)域Path
*/
mPathTrap.moveTo(startXBtm, startYBtm);
mPathTrap.lineTo(topX2, 0);
mPathTrap.lineTo(bezierPeakXBtm, bezierPeakYBtm);
mPathTrap.close();
/*
* 底部月半圓Path
*/
mPathSemicircleBtm.moveTo(startXBtm, startYBtm);
mPathSemicircleBtm.quadTo(controlXBtm, controlYBtm, endXBtm, endYBtm);
mPathSemicircleBtm.close();
/*
* 生成包括折疊和下1頁的路徑
*/
//暫時(shí)沒用省略掉
// 計(jì)算月半圓區(qū)域
mRegionSemicircle = computeRegion(mPathSemicircleBtm);
} else {
/*
* 計(jì)算參數(shù)
*/
float leftY = mViewHeight - sizeLong;
float btmX = mViewWidth - sizeShort;
// 計(jì)算曲線出發(fā)點(diǎn)
float startXBtm = btmX - CURVATURE * sizeShort;
float startYBtm = mViewHeight;
float startXLeft = mViewWidth;
float startYLeft = leftY - CURVATURE * sizeLong;
// 計(jì)算曲線終點(diǎn)
float endXBtm = mPointX + (1 - CURVATURE) * (tempAM);
float endYBtm = mPointY + (1 - CURVATURE) * mL;
float endXLeft = mPointX + (1 - CURVATURE) * mK;
float endYLeft = mPointY - (1 - CURVATURE) * (sizeLong - mL);
// 計(jì)算曲線控制點(diǎn)
float controlXBtm = btmX;
float controlYBtm = mViewHeight;
float controlXLeft = mViewWidth;
float controlYLeft = leftY;
// 計(jì)算曲線頂點(diǎn)
float bezierPeakXBtm = 0.25F * startXBtm + 0.5F * controlXBtm + 0.25F * endXBtm;
float bezierPeakYBtm = 0.25F * startYBtm + 0.5F * controlYBtm + 0.25F * endYBtm;
float bezierPeakXLeft = 0.25F * startXLeft + 0.5F * controlXLeft + 0.25F * endXLeft;
float bezierPeakYLeft = 0.25F * startYLeft + 0.5F * controlYLeft + 0.25F * endYLeft;
/*
* 限制右邊曲線出發(fā)點(diǎn)
*/
if (startYLeft <= 0) {
startYLeft = 0;
}
/*
* 限制底部左邊曲線出發(fā)點(diǎn)
*/
if (startXBtm <= 0) {
startXBtm = 0;
}
/*
* 根據(jù)底部左邊限制點(diǎn)重新計(jì)算貝塞爾曲線頂點(diǎn)坐標(biāo)
*/
float partOfShortLength = CURVATURE * sizeShort;
if (btmX >= -mValueAdded && btmX <= partOfShortLength - mValueAdded) {
float f = btmX / partOfShortLength;
float t = 0.5F * f;
float bezierPeakTemp = 1 - t;
float bezierPeakTemp1 = bezierPeakTemp * bezierPeakTemp;
float bezierPeakTemp2 = 2 * t * bezierPeakTemp;
float bezierPeakTemp3 = t * t;
bezierPeakXBtm = bezierPeakTemp1 * startXBtm + bezierPeakTemp2 * controlXBtm + bezierPeakTemp3 * endXBtm;
bezierPeakYBtm = bezierPeakTemp1 * startYBtm + bezierPeakTemp2 * controlYBtm + bezierPeakTemp3 * endYBtm;
}
/*
* 根據(jù)右邊限制點(diǎn)重新計(jì)算貝塞爾曲線頂點(diǎn)坐標(biāo)
*/
float partOfLongLength = CURVATURE * sizeLong;
if (leftY >= -mValueAdded && leftY <= partOfLongLength - mValueAdded) {
float f = leftY / partOfLongLength;
float t = 0.5F * f;
float bezierPeakTemp = 1 - t;
float bezierPeakTemp1 = bezierPeakTemp * bezierPeakTemp;
float bezierPeakTemp2 = 2 * t * bezierPeakTemp;
float bezierPeakTemp3 = t * t;
bezierPeakXLeft = bezierPeakTemp1 * startXLeft + bezierPeakTemp2 * controlXLeft + bezierPeakTemp3 * endXLeft;
bezierPeakYLeft = bezierPeakTemp1 * startYLeft + bezierPeakTemp2 * controlYLeft + bezierPeakTemp3 * endYLeft;
}
/*
* 替補(bǔ)區(qū)域Path
*/
mPathTrap.moveTo(startXBtm, startYBtm);
mPathTrap.lineTo(startXLeft, startYLeft);
mPathTrap.lineTo(bezierPeakXLeft, bezierPeakYLeft);
mPathTrap.lineTo(bezierPeakXBtm, bezierPeakYBtm);
mPathTrap.close();
/*
* 生成帶曲線的3角形路徑
*/
mPath.moveTo(startXBtm, startYBtm);
mPath.quadTo(controlXBtm, controlYBtm, endXBtm, endYBtm);
mPath.lineTo(mPointX, mPointY);
mPath.lineTo(endXLeft, endYLeft);
mPath.quadTo(controlXLeft, controlYLeft, startXLeft, startYLeft);
/*
* 生成底部月半圓的Path
*/
mPathSemicircleBtm.moveTo(startXBtm, startYBtm);
mPathSemicircleBtm.quadTo(controlXBtm, controlYBtm, endXBtm, endYBtm);
mPathSemicircleBtm.close();
/*
* 生成右邊月半圓的Path
*/
mPathSemicircleLeft.moveTo(endXLeft, endYLeft);
mPathSemicircleLeft.quadTo(controlXLeft, controlYLeft, startXLeft, startYLeft);
mPathSemicircleLeft.close();
/*
* 生成包括折疊和下1頁的路徑
*/
//暫時(shí)沒用省略掉
/*
* 計(jì)算底部和右邊兩月半圓區(qū)域
*/
Region regionSemicircleBtm = computeRegion(mPathSemicircleBtm);
Region regionSemicircleLeft = computeRegion(mPathSemicircleLeft);
// 合并兩月半圓區(qū)域
mRegionSemicircle.op(regionSemicircleBtm, regionSemicircleLeft, Region.Op.UNION);
}
// 根據(jù)Path生成的折疊區(qū)域
Region regioFlod = computeRegion(mPath);
// 替補(bǔ)區(qū)域
Region regionTrap = computeRegion(mPathTrap);
// 令折疊區(qū)域與替補(bǔ)區(qū)域相加
regioFlod.op(regionTrap, Region.Op.UNION);
// 從相加后的區(qū)域中剔除掉月半圓的區(qū)域取得終究折疊區(qū)域
regioFlod.op(mRegionSemicircle, Region.Op.DIFFERENCE);
/*
* 根據(jù)裁剪區(qū)域填充畫布
*/
canvas.clipRegion(regioFlod);
canvas.drawColor(Color.RED);
200行的代碼我們就做了1件事就是正確計(jì)算Path,一樣我們還是依照之前的分了兩種情況來計(jì)算,第1種情況sizeLong > mViewHeight時(shí),我們先計(jì)算替補(bǔ)的這塊區(qū)域:

如上代碼46⑷9行
/*
* 替補(bǔ)區(qū)域Path
*/
mPathTrap.moveTo(startXBtm, startYBtm);
mPathTrap.lineTo(topX2, 0);
mPathTrap.lineTo(bezierPeakXBtm, bezierPeakYBtm);
mPathTrap.close();
然后計(jì)算底部的月半圓Path:

對應(yīng)代碼54⑸6行
/*
* 底部月半圓Path
*/
mPathSemicircleBtm.moveTo(startXBtm, startYBtm);
mPathSemicircleBtm.quadTo(controlXBtm, controlYBtm, endXBtm, endYBtm);
mPathSemicircleBtm.close();
將當(dāng)前折疊區(qū)域和替補(bǔ)區(qū)域相加再減去月半圓Path區(qū)域我們就能夠得到正確的折疊區(qū)域,對應(yīng)代碼64行和192⑵01行:
// 計(jì)算月半圓區(qū)域
mRegionSemicircle = computeRegion(mPathSemicircleBtm);
// ………………中間省略巨量代碼………………
// 根據(jù)Path生成的折疊區(qū)域
Region regioFlod = computeRegion(mPath);
// 替補(bǔ)區(qū)域
Region regionTrap = computeRegion(mPathTrap);
// 令折疊區(qū)域與替補(bǔ)區(qū)域相加
regioFlod.op(regionTrap, Region.Op.UNION);
// 從相加后的區(qū)域中剔除掉月半圓的區(qū)域取得終究折疊區(qū)域
regioFlod.op(mRegionSemicircle, Region.Op.DIFFERENCE);
該情況下我們的折疊區(qū)域是醬紫的:

兩1種情況則略微復(fù)雜些,除要計(jì)算底部,我們還要計(jì)算右邊的月半圓Path區(qū)域,代碼165⑴74:
/*
* 生成底部月半圓的Path
*/
mPathSemicircleBtm.moveTo(startXBtm, startYBtm);
mPathSemicircleBtm.quadTo(controlXBtm, controlYBtm, endXBtm, endYBtm);
mPathSemicircleBtm.close();
/*
* 生成右邊月半圓的Path
*/
mPathSemicircleLeft.moveTo(endXLeft, endYLeft);
mPathSemicircleLeft.quadTo(controlXLeft, controlYLeft, startXLeft, startYLeft);
mPathSemicircleLeft.close();
替補(bǔ)區(qū)域的計(jì)算,147⑴51:
/*
* 替補(bǔ)區(qū)域Path
*/
mPathTrap.moveTo(startXBtm, startYBtm);
mPathTrap.lineTo(startXLeft, startYLeft);
mPathTrap.lineTo(bezierPeakXLeft, bezierPeakYLeft);
mPathTrap.lineTo(bezierPeakXBtm, bezierPeakYBtm);
mPathTrap.close();
區(qū)域的轉(zhuǎn)換,184⑴88:
/*
* 計(jì)算底部和右邊兩月半圓區(qū)域
*/
Region regionSemicircleBtm = computeRegion(mPathSemicircleBtm);
Region regionSemicircleLeft = computeRegion(mPathSemicircleLeft);
// 合并兩月半圓區(qū)域
mRegionSemicircle.op(regionSemicircleBtm, regionSemicircleLeft, Region.Op.UNION);
終究的計(jì)算跟上面第1種情況1樣,效果以下:

結(jié)合兩種情況,我們可以得到下面的效果:

然后,我們需要計(jì)算“下1頁”的區(qū)域,一樣,根據(jù)上1節(jié)我們的講授,我們先獲得折疊區(qū)域和下1頁區(qū)域之和再減去折疊區(qū)域就能夠得到下1頁的區(qū)域:
mRegionNext = computeRegion(mPathFoldAndNext);
mRegionNext.op(mRegionFold, Region.Op.DIFFERENCE);
繪制效果以下:

最后,我們結(jié)合上兩節(jié),注入數(shù)據(jù):
/**
* 繪制位圖數(shù)據(jù)
*
* @param canvas
* 畫布對象
*/
private void drawBitmaps(Canvas canvas) {
// 繪制位圖前重置isLastPage為false
isLastPage = false;
// 限制pageIndex的值范圍
mPageIndex = mPageIndex < 0 ? 0 : mPageIndex;
mPageIndex = mPageIndex > mBitmaps.size() ? mBitmaps.size() : mPageIndex;
// 計(jì)算數(shù)據(jù)起始位置
int start = mBitmaps.size() - 2 - mPageIndex;
int end = mBitmaps.size() - mPageIndex;
/*
* 如果數(shù)據(jù)出發(fā)點(diǎn)位置小于0則表示當(dāng)前已到了最后1張圖片
*/
if (start < 0) {
// 此時(shí)設(shè)置isLastPage為true
isLastPage = true;
// 并顯示提示信息
showToast("This is fucking lastest page");
// 強(qiáng)迫重置起始位置
start = 0;
end = 1;
}
/*
* 計(jì)算當(dāng)前頁的區(qū)域
*/
canvas.save();
canvas.clipRegion(mRegionCurrent);
canvas.drawBitmap(mBitmaps.get(end - 1), 0, 0, null);
canvas.restore();
/*
* 計(jì)算折疊頁的區(qū)域
*/
canvas.save();
canvas.clipRegion(mRegionFold);
canvas.translate(mPointX, mPointY);
/*
* 根據(jù)長短邊標(biāo)識(shí)計(jì)算折疊區(qū)域圖象
*/
if (mRatio == Ratio.SHORT) {
canvas.rotate(90 - mDegrees);
canvas.translate(0, -mViewHeight);
canvas.scale(⑴, 1);
canvas.translate(-mViewWidth, 0);
} else {
canvas.rotate(-(90 - mDegrees));
canvas.translate(-mViewWidth, 0);
canvas.scale(1, ⑴);
canvas.translate(0, -mViewHeight);
}
canvas.drawBitmap(mBitmaps.get(end - 1), 0, 0, null);
canvas.restore();
/*
* 計(jì)算下1頁的區(qū)域
*/
canvas.save();
canvas.clipRegion(mRegionNext);
canvas.drawBitmap(mBitmaps.get(start), 0, 0, null);
canvas.restore();
}
終究效果以下:

該部份的代碼就不貼出了,大部份跟上1節(jié)相同,由于過兩天要去旅游時(shí)間略緊這節(jié)略講得粗糙,不過也沒甚么太大的改動(dòng),如果大家有不懂的地方可以留言或群里@哥,下1節(jié)我們將嘗試實(shí)現(xiàn)翻頁時(shí)圖象扭曲的效果。
源碼地址:傳送門
生活不易,碼農(nóng)辛苦
如果您覺得本網(wǎng)站對您的學(xué)習(xí)有所幫助,可以手機(jī)掃描二維碼進(jìn)行捐贈(zèng)