先來看看翻頁的原理圖:
先了解各個字母表示的含義:
A-把書頁翻起來後看到的背面區域
B-把書頁翻起來後看到的下一頁的一角
C-目前頁的可見部分。
a-手指滑動頁角到達的位置
b-目前頁翻起來後與書本垂直邊的交點
c-目前頁翻起來後與書本水準邊的交點
m-翻頁的起始點
n-書本右上角
t-書本左上角
o-直角坐标系原點
為了能在翻頁的過程中看到下一頁的部分内容,在每次翻頁之前必須準備兩張頁面,一張是目前頁,另一張是下一頁。翻頁的過程就是對這兩張頁面的剪切,組合過程。
看到圖你也應該知道,這是一道什麼幾何題目了,好,那我們再把高中幾何複習一遍吧。通過直線am的中點求它的中垂線bc,直線bc與書本的垂直邊和水準邊分别交于點b,點c,給出a點的動态坐标(x,y),求出b,c坐标。
知道了a,b,c,m四點的坐标,就可以把四邊形abcm用直線連起來,并把四邊形abcm分成A,B 兩部分,A部分表示書頁翻起來後看到的目前頁的背面區域,B部分表示書頁翻起來後看到的下一頁的部分區域。
在java的Graphics2D這個類裡面有clip這樣的方法來達到剪切圖檔的目的,這個方法需要傳入的是一個GeneralPath這樣的對象,他表示的是在一個圖檔上要剪切的一個封閉區域,而這裡,我們要剪切的區域包括:
1.目前頁的可見部分,是一個多邊形ocabnt。
2.目前頁翻起來的背面,這是個三角形acb。
3.下一頁的一角,也是個三角形cmb。
這三個部分剪切完畢,組合到同一個畫布裡面就能形成這樣的翻頁效果了。
當然,在翻頁的過程中,因為要根據手指的觸點坐标來随時重新整理界面的顯示,即重畫界面,需要重新計算b,c兩點的坐标,根據最新的坐标重畫各條直線,剪切直線包圍起來的區域。界面的重新整理頻率根據自身需要調整。
如果你覺得直線圍起來的區域過于生硬,不太像真實的翻頁效果。沒關系,你還可以使用貝塞爾曲線來連接配接交點a,b,c。Android上有畫貝塞爾曲線的方法,Path類裡面的quadTo(x1, y1, x2, y2)。
實際效果就像這樣。
J2SE平台下的翻頁效果示例代碼:http://download.csdn.net/source/2818813
在android中實作手勢翻頁效果,主要用到ViewFlipper和GestureDetector.
ViewFlipper變化目前顯示内容,GestureDetector監聽手勢.
用于多頁的展示非常酷.
以下是簡略說明:
首先建立工程:TestFlip,建立主Activity:TestFlip.
在res/layout/main.xml中添加flipper資訊,如下:
Java代碼
1. < ?xml version="1.0" encoding="utf-8"?>
2. < LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3. android:orientation="vertical"
4. android:layout_width="fill_parent"
5. android:layout_height="fill_parent"
6. >
7. < ViewFlipper android:id="@+id/ViewFlipper01"
8. android:layout_width="fill_parent" android:layout_height="fill_parent">
9. < /ViewFlipper>
10. < /LinearLayout>
< ?xml version="1.0" encoding="utf-8"?>
< LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
< ViewFlipper android:id="@+id/ViewFlipper01"
android:layout_width="fill_parent" android:layout_height="fill_parent">
< /ViewFlipper>
< /LinearLayout>
然後将TestFlip實作OnGestureListener接口,并實作所有抽象方法,然後開始改造這個類.
首先,聲明兩個私有成員.
Java代碼
1. private ViewFlipper flipper;//ViewFlipper執行個體
2. private GestureDetector detector;//觸摸監聽執行個體
private ViewFlipper flipper;//ViewFlipper執行個體
private GestureDetector detector;//觸摸監聽執行個體
然後在onCreate方法中添加成員初始化.
Java代碼
1. detector = new GestureDetector(this);//初始化觸摸探測
2. flipper = (ViewFlipper) this.findViewById(R.id.ViewFlipper01);//獲得ViewFlipper執行個體
3.
4. flipper.addView(addTextView("step 1"));//将View添加到flipper隊列中
5. flipper.addView(addTextView("step 2"));
6. flipper.addView(addTextView("step 3"));
7. flipper.addView(addTextView("step 4"));
8. flipper.addView(addTextView("step 5"));
detector = new GestureDetector(this);//初始化觸摸探測
flipper = (ViewFlipper) this.findViewById(R.id.ViewFlipper01);//獲得ViewFlipper執行個體
flipper.addView(addTextView("step 1"));//将View添加到flipper隊列中
flipper.addView(addTextView("step 2"));
flipper.addView(addTextView("step 3"));
flipper.addView(addTextView("step 4"));
flipper.addView(addTextView("step 5"));
addTextView方法如下:
Java代碼
1. private View addTextView(String text) {
2. TextView tv = new TextView(this);
3. tv.setText(text);
4. tv.setGravity(1);
5. return tv;
6. }
private View addTextView(String text) {
TextView tv = new TextView(this);
tv.setText(text);
tv.setGravity(1);
return tv;
}
flipper将按照你的添加順序排列這些View,并通過flipper.showNext()和flipper.showPrevious()顯示.
還需要多重寫一個方法:onTouchEvent(MotionEvent event),否則detector檢測不到觸摸,這個方法非常簡單.
Java代碼
1. @Override
2. public boolean onTouchEvent(MotionEvent event) {
3. return this.detector.onTouchEvent(event);
4. }
@Override
public boolean onTouchEvent(MotionEvent event) {
return this.detector.onTouchEvent(event);
}
現在開始做動作監聽,在onFling方法中加入以下内容:
Java代碼
1. @Override
2. public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
3. float velocityY) {
4. this.flipper.showNext();//顯示flipper中的下一個view
5. return true;
6. }
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
this.flipper.showNext();//顯示flipper中的下一個view
return true;
}
現在可以運作一下看看效果了.你會發現當滑鼠滑動時畫面隻是很簡單的從Step 1變成Step 2,并沒有那種畫面滑動的效果,而且無論你從左向右滑動還是從右向左滑動都是按照同一個順序,現在我們修改一些,讓效果更炫一點.
先在res目錄下建立anim目錄,并建立4個基于Animation的xml檔案,分别命名為:left_in.xml,left_out.xml,right_in.xml,right_left.xml
内容分别為:
left_in.xml:
Java代碼
1. < ?xml version="1.0" encoding="utf-8"?>
2. < set xmlns:android="http://schemas.android.com/apk/res/android">
3. < translate android:fromXDelta="100%p" android:toXDelta="0"
4. android:duration="500" />
5. < /set>
< ?xml version="1.0" encoding="utf-8"?>
< set xmlns:android="http://schemas.android.com/apk/res/android">
< translate android:fromXDelta="100%p" android:toXDelta="0"
android:duration="500" />
< /set>
left_out.xml:
Java代碼
1. < ?xml version="1.0" encoding="utf-8"?>
2. < set xmlns:android="http://schemas.android.com/apk/res/android">
3. < translate android:fromXDelta="0" android:toXDelta="-100%p"
4. android:duration="500" />
5. < /set>
< ?xml version="1.0" encoding="utf-8"?>
< set xmlns:android="http://schemas.android.com/apk/res/android">
< translate android:fromXDelta="0" android:toXDelta="-100%p"
android:duration="500" />
< /set>
right_in.xml:
Java代碼
1. < ?xml version="1.0" encoding="utf-8"?>
2. < set xmlns:android="http://schemas.android.com/apk/res/android">
3. < translate android:fromXDelta="-100%p" android:toXDelta="0"
4. android:duration="500" />
5. < /set>
< ?xml version="1.0" encoding="utf-8"?>
< set xmlns:android="http://schemas.android.com/apk/res/android">
< translate android:fromXDelta="-100%p" android:toXDelta="0"
android:duration="500" />
< /set>
right_out.xml:
Java代碼
1. < ?xml version="1.0" encoding="utf-8"?>
2. < set xmlns:android="http://schemas.android.com/apk/res/android">
3. < translate android:fromXDelta="0" android:toXDelta="100%p"
4. android:duration="500" />
5. < /set>
< ?xml version="1.0" encoding="utf-8"?>
< set xmlns:android="http://schemas.android.com/apk/res/android">
< translate android:fromXDelta="0" android:toXDelta="100%p"
android:duration="500" />
< /set>
主要是做一個translation動畫,fromXDelta:動畫的開始X位置,toXDelta:動畫的結束X位置,duration:持續時間.
然後将onFling方法修改為如下:
Java代碼
1. @Override
2. public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
3. float velocityY) {
4. if (e1.getX() - e2.getX() > 120) {//如果是從右向左滑動
5. //注冊flipper的進出效果
6. this.flipper.setInAnimation(AnimationUtils.loadAnimation(this, R.anim.left_in));
7. this.flipper.setOutAnimation(AnimationUtils.loadAnimation(this, R.anim.left_out));
8. this.flipper.showNext();
9. return true;
10. } else if (e1.getX() - e2.getX() < -120) {//如果是從左向右滑動
11. this.flipper.setInAnimation(AnimationUtils.loadAnimation(this, R.anim.right_in));
12. this.flipper.setOutAnimation(AnimationUtils.loadAnimation(this, R.anim.right_out));
13. this.flipper.showPrevious();
14. return true;
15. }
16. return false;
17. }
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
if (e1.getX() - e2.getX() > 120) {//如果是從右向左滑動
//注冊flipper的進出效果
this.flipper.setInAnimation(AnimationUtils.loadAnimation(this, R.anim.left_in));
this.flipper.setOutAnimation(AnimationUtils.loadAnimation(this, R.anim.left_out));
this.flipper.showNext();
return true;
} else if (e1.getX() - e2.getX() < -120) {//如果是從左向右滑動
this.flipper.setInAnimation(AnimationUtils.loadAnimation(this, R.anim.right_in));
this.flipper.setOutAnimation(AnimationUtils.loadAnimation(this, R.anim.right_out));
this.flipper.showPrevious();
return true;
}
return false;
}
然後重新運作看看效果,如果圖檔之類的多,還可以在animation裡加入alpha的效果,如下
Java代碼
1. < alpha android:fromAlpha="0.1" android:toAlpha="1.0"
2. android:duration="500" />
< alpha android:fromAlpha="0.1" android:toAlpha="1.0"
android:duration="500" />
一個手勢翻頁效果就搞定了,用在多内容的展示效果上會非常棒.
源代碼下載下傳:http://u.115.com/file/f5fb0acb23(壓縮包7Z的,javaeye不讓傳???)