2025-06-14

第一次看到翻頁效果的時候,覺得真是厲害,真是想不出是怎麼做的呢(唉,牛人的智商真是隻能仰望!)。

直到看瞭Android 實現書籍翻頁效果—-原理篇 一文,看瞭何明桂對翻頁效果的一張圖解,看到貝塞爾曲線,才恍然大悟,隻能內心贊嘆瞭。

下面先看看圖(這張圖是直接拿何明桂大牛的,請多多包涵):

vcfOqsbwtePAtLet0rO1xKOstavG5Mq11rvSqr2r09LPwr3HtcQgZiC148nos8nSu7j2seTBv6Ooy/y/ydLUysfIzrrO0ru49r3Ho6m+zb/J0tTKtc/Wy8S49r3HtcS3rdKz0Ke5+8HLoaM8L3A+CjxwPtXiuPa3rcPm0Ke5+8bkyrXKx9PJyP2yv7fW1+mzybXEo7q1scew0rOhorWxx7DSs9KzsbMgus0gz8LSu9KzPC9wPgo8cD66zrTzxaO1xMu8wrfKxzGjqc/Ix/Oz9tKzsbO4+s/C0rvSs8f40/KjrNf3zqpwYXRoMCwgyLu688D708NjbGlwcGF0aCC1xCBSZWdpb24uT3AuWE9SIMC0x/Oz9rWxx7DSs6GjPC9wPgo8cD4gICAgICAgICAgMqOpx/Oz9s/C0rvSs7XEcGF0aDGjrNTZuPm+3WNsaXBwYXRotcRSZWdpb24uT3AuRGlmZmVyZW5jZSDAtLTTcGF0aDDW0Lz0s/bSs7GztcTH+NPyoaM8L3A+CjxwPrb4cGF0aDCjrMbkyrW+zcrH08lqaWujqLG0yPu2+8f6z9+jrGjOqr/Y1sa146Opo6xrYaOo1rHP36Opo6xhYqOo1rHP36Opo6xiZGOjqLG0yPu2+8f6z9+jrNLUZc6qv9jWxrXjo6mjrGNmo6jWsc/fo6mjrGZqo6jWsc/fo6nX6bPJtcShozwvcD4KPHA+tvhwYXRoMaOs1PLKx9PJY2SjqLG0yPu2+8f6z9+jrGTOqr/Y1sa146OpLGRpo6jWsc/fo6mjrGlqo6ixtMj7tvvH+s/fo6zS1GTOqr/Y1sa146OpLGpmo6jWsc/fo6mhozwvcD4KPHA+y7zCt7zIyLvH5bP+wcujrMTHw7S1sci7ytfPyMrH0qrAtLzGy+O147XEzrvWw8HLo6y6zrTzxaPSstLRvq2w0bj3uPa149T1w7TL47XEwt+8rdTayc/OxNbQuPiz9sHLo6yyu7n9ztK+9bXDttTT2sbk1tC1xGIsayDBvbXjo6y6zrTzxaPKx8/rtuDBy6GjPC9wPgo8cD66zrTzxaPKx8D708PBvdaxz9/P4L27wLTL47P2xuS9u7XjzrvWw7XEo6y6zrTzxaPUrc7EyOfPwqO6PC9wPgo8cD48L3A+CjxwPjxzdHJvbmc+19vJz6OsNLXjz+C9u7XE1rHP37XEvbu1486qo7o8L3N0cm9uZz48L3A+CjxwPjxzdHJvbmc+ICAgICB4PSggKHg0KnkzLXk0KngzKS8oeDQteDMpLSh4Mip5MS15Mip4MSkvKHgyLXgxKSkgLzwvc3Ryb25nPjwvcD4KPHA+PHN0cm9uZz4gKCh5Mi15MSkvKHgyLXgxKS0gKHk0LXkzKS8oeDQteDMpICk8L3N0cm9uZz48L3A+CjxwPjxzdHJvbmc+ICAgICA8L3N0cm9uZz48L3A+CjxwPjxzdHJvbmc+ID0gKCAoeDQqeTMteTQqeDMpICh4Mi14MSktICh4Mip5MS15Mip4MSkgKHg0LXgzKSApIC88L3N0cm9uZz48L3A+CjxwPjxzdHJvbmc+ICAgICggKHkyLXkxKSAoeDQteDMpLSAoeTQteTMpICh4Mi14MSkgKTwvc3Ryb25nPjwvcD4KPHA+PHN0cm9uZz69q9aux7DH87XDtcQgYSxlLGMsasvEuPa147T4yOvJz8q91PK/ydLUx/Oz9iBiLiDNrMDtv8nH82u146GjPC9zdHJvbmc+PC9wPgo8cD61q8bkyrXU2tStz8i1xMPoyvbW0KOsY2og1eLM9daxz9/Kx7S51rHGvbfWYWe1xKOs0rK+zcrHy7XG5Ma90NDT2sj9vcfQzrXEtdeyosa9t9bG5LXXsd/Jz7XEtLnP37XEo6zEx8O0uPm+3c/gJiMyMDI4NDvI/b3H0M61xLaowO2/ydLU1qq1wKOsYrXjus1rtePSstOmuMPKx8bksd9hZbrNYWi1xNbQteOho8v50tSjrNXiwb2147XE1/ix6r/J0tTWsb3TuPm+3WFlteO6zWFotePL47P2wLS1xKGjPC9wPgo8cD6497j2teO1xLzGy+PC37ytyOfPwqO6PC9wPgo8cD48L3A+CjxwcmUgY2xhc3M9″brush:java;”> private void calculatePoints(){
fx = cornerX;//這是界面的四個頂點之一,可以根據手指落下時來判斷是從哪個頂點來翻
fy = cornerY;

gx = (ax + fx) / 2;//g點是af的中點
gy = (ay + fy) / 2;

float gm = fy – gy;
float mf = fx – gx;
float em = gm * gm / mf;//根據相似三角形算出em的長度

ex = gx – em;//算出e點
ey = fy;

float hm = mf * mf / gm;

hx = fx;
hy = gy – hm;//同理,算出h點

cx = ex – (fx – ex)/2;//再同理,三角形ehf跟三角形cjf是相似的,且根據cj是平分ag的,所以在邊上的比例是2/3的關系
cy = fy;

jx = fx;
jy = hy – (fy – hy)/2;//同上

bx = (ax + ex) / 2;
by = (ay + ey) / 2;//b點其實就是ae的中點

kx = (ax + hx) / 2;
ky = (ay + hy) / 2;//k點就是ah的中點

//p middle point of the bc;
float px = (bx + cx) / 2; //這裡求p點,其實是為瞭求d點,因為這一段貝塞爾曲線是對稱的,
float py = (by + cy) / 2; //所以求出bc的中點p,跟控制點e連起來,穿過的點d剛好就是在曲線的中點

dx = (px + ex) / 2;
dy = (py + ey) / 2;

px = (kx + jx) / 2; //同上
py = (ky + jy) / 2;

ix = (px + hx) / 2;
iy = (py + hy) / 2;
}
既然點出來瞭,那麼就利用path的quadTo和lineTo,還有close來畫出封閉的貝塞爾曲線,就是要畫出來的區域瞭。

		canvas.save();			
		path.reset();
		path.moveTo(jx, jy);
		path.quadTo(hx, hy, kx, ky);
		path.lineTo(ax, ay);
		path.lineTo(bx, by);
		path.quadTo(ex, ey, cx, cy);
		path.lineTo(fx, fy);
		path.close();						
		paint.setColor(Color.GREEN);		//畫綠色
		canvas.drawPath(path, paint);
		canvas.restore();

畫出 path0,從j點到f點,然後利用close把曲線給封閉起來。

		canvas.save();
		canvas.clipRect(canvas.getClipBounds());//clip出整個界面
		canvas.clipPath(path,Op.XOR);		//clip出path0的區域,然後根據XOR,取出path0沒有圈住的區域
		canvas.drawColor(Color.RED);		//畫紅色
		canvas.restore();

利用異或的操作(異或其實就是我們倆都占瞭的地方,就不能給你瞭),截出當前頁。

最後再利用difference操作,截取出頁背部分,

                canvas.clipPath(path);
		pathNext.reset();
		pathNext.moveTo(cx, cy);
		pathNext.quadTo(dx, dy, dx, dy);
		pathNext.lineTo(ix, iy);
		pathNext.quadTo(jx, jy, jx, jy);
		pathNext.lineTo(fx, fy);
		pathNext.close();
		canvas.clipPath(pathNext, Op.DIFFERENCE);//difference最取出兩段path中不同的地方
		canvas.drawColor(Color.YELLOW);
		canvas.restore();

這樣,就把這幾個區域都給取出來瞭,當我們Touch的時候,根據手指移動的坐標,進行重復的計算,從而拉出翻頁的效果,當我們手指抬起的時候,就利用一個動畫效果,把頁面直接給翻過去。

下面是一個小Demo,我們來看看效果圖:

隻是完成瞭一個比較簡單的效果,後面還需要添加圖片,文字之類的,才能真正形成一個書籍翻頁的效果。

源代碼請點擊

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *