天天看點

在Android手機上實作閱讀器的翻頁效果

先來看看翻頁的原理圖:

在Android手機上實作閱讀器的翻頁效果

先了解各個字母表示的含義:

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)。

實際效果就像這樣。

在Android手機上實作閱讀器的翻頁效果

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不讓傳???)