Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android官方開發文檔Training系列課程中文版:創建自定義View之View的交互

Android官方開發文檔Training系列課程中文版:創建自定義View之View的交互

編輯:關於Android編程

寫在前面的話:這一章很有價值,想要提升安卓知識的一定要讀一讀。不做安卓的也可以得到其它方面的提升。

原文地址:http://android.xsoftlab.net/training/custom-views/making-interactive.html

UI的繪制只是自定義View的一部分。你還需要使View可以以一種接近真實世界的反饋方式來響應用戶的輸入事件。虛擬世界中的對象應該總是以真實世界中對象的行為方式來行動。比如說,圖像不應該從某處突然出現或消失,因為真實世界中的圖像總是從一個地方移動到另一個地方的。

用戶還應該在UI界面上感知到一些細微的感覺。最好的反饋就是模仿真實世界的微妙行為。舉個栗子,用戶在快速滑動UI對象時,應該在開始時感覺到延遲的摩擦力,在滑出去後還應當繼續保持慣性滑動。

這節課將會演示如何使用Android的框架特性為自定義View添加這些真實世界的行為。

處理輸入手勢

與其它UI框架很接近,Android同樣支持輸入事件模型。用戶的行為會被轉換為一種會觸發回調的事件,你可以通過重寫這些回調方法來決定如何對這些事件做出響應。Android中最為常見的輸入事件是touch,它會觸發onTouchEvent(android.view.MotionEvent)。通過重寫這個方法來處理一些事件:

   @Override
   public boolean onTouchEvent(MotionEvent event) {
    return super.onTouchEvent(event);
   }

觸摸事件本身並不是特別有用處。觸摸UI定義了一些交互手勢,比如雙擊、下拉、上推、快速滑動以及縮放等等。為了將原始觸摸事件轉換為手勢,Android提供了GestureDetector。

構造GestureDetector需要傳遞一個GestureDetector.OnGestureListener的實現類作為參數。如果你只是需要處理幾個手勢,你可以繼承GestureDetector.SimpleOnGestureListener。下面的代碼繼承了這個接口,並重寫了它的onDown(MotionEvent)方法。

class mListener extends GestureDetector.SimpleOnGestureListener {
   @Override
   public boolean onDown(MotionEvent e) {
       return true;
   }
}
mDetector = new GestureDetector(PieChart.this.getContext(), new mListener());

無論你是否使用GestureDetector.SimpleOnGestureListener接口,你都需要實現一個返回true的onDown()方法。這一步是必須的,因為所有的手勢都是從onDown()方法開始的。如果你在onDown()方法中返回了false,那麼系統會認為你想忽略這次事件,並且其它的相關方法都不會被調用。如果你真的想要忽略整個手勢事件,那麼在onDown()方法中返回false是唯一的一種方式。一旦實現了GestureDetector.OnGestureListener接口,並創建了GestureDetector的實例,則可以使用GestureDetector對象來與在onTouchEvent()中接收到的觸摸事件進行交互。

@Override
public boolean onTouchEvent(MotionEvent event) {
   boolean result = mDetector.onTouchEvent(event);
   if (!result) {
       if (event.getAction() == MotionEvent.ACTION_UP) {
           stopScrolling();
           result = true;
       }
   }
   return result;
}

當傳給onTouchEvent()方法一個不能識別的手勢時,它會返回false,這樣你就可以運行自定義的手勢識別代碼了。

創建物理模擬手勢

手勢是用來控制觸摸屏設備的一種強大方式,除非它們提供了物理模擬效果,否則它們可能是違反直覺的、難以記住的。一個好的示例就是飛速滑動手勢:當用戶快速的在屏幕上滑動手指時,手指突然離開了屏幕,就會觸發這種手勢。如果UI在同一方向上繼續滑動然後慢慢的減速,這時就會給用戶造成一種感覺:仿佛在操作一個飛輪一樣。

不管怎樣,模擬飛輪這種感覺並不是沒有價值的。為了正確模擬這種感覺,需要很多的物理及數學運算。幸運的是,Android為此提供了輔助類。Scroller是一個專門用來處理這種飛輪感覺手勢的輔助類。

為了啟動滑動,需要以一個初始速度值及其它相關速度參數調用fling()。有關速度值,你可以通過GestureDetector計算得到。

@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
   mScroller.fling(currentX, currentY, velocityX / SCALE, velocityY / SCALE, minX, minY, maxX, maxY);
   postInvalidate();
}

Note: 盡管GestureDetector計算到的這個速度值在物理上很精確,但是很多開發者感覺使用這個值來啟動滑動還是太快了。通常會在4到8之間取一個系數來減小x和y。

先調用fling()為滑動手勢設置物理模型。然後你需要定期調用Scroller.computeScrollOffset()來更新Scroller。computeScrollOffset()通過讀取當前的時間以及使用物理模型來計算x及y的位置來更新Scroller對象的內部狀態。通過調用getCurrX()和getCurrY()來接收這些值。

很多View將Scroller對象的x,y的位置值直接傳遞給scrollTo()。餅圖示例在這裡有些小小的不同:它使用當前滑動的y的位置來設置餅圖的旋轉角度:

if (!mScroller.isFinished()) {
    mScroller.computeScrollOffset();
    setPieRotation(mScroller.getCurrY());
}

Scroller會為你計算滑動的位置,但是它不會自動的將這些值應用到你的View中。為了使View的滑動效果更佳平滑,獲得並應用這些值是需要你去做的。有兩種方式可以實現:

在fling()之後調用postInvalidate(),這樣可以重新繪制界面。這個方法需要每次滑動的偏移量發生變化之後在onDraw()方法中調用。 為滑動動畫設置ValueAnimator,調用addUpdateListener()添加監聽器,以便處理動畫的更新。

在餅圖示例中使用了第二種方案。這項技術在設置上稍微的有些復雜,但是它的工作過程與動畫系統更為接近,並且不會請求不必要的更新。它的缺點是在API 11之前ValueAnimator並不適用,所以這項技術在Android 3.0之前不可以使用。

Note: ValueAnimator在API 11之前並不可用,但是你仍然還可以在API 11之前使用。你只需要確保在運行時檢查當前的API等級,並且在等級低於11時不調用View動畫就可以。

       mScroller = new Scroller(getContext(), null, true);
       mScrollAnimator = ValueAnimator.ofFloat(0,1);
       mScrollAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
           @Override
           public void onAnimationUpdate(ValueAnimator valueAnimator) {
               if (!mScroller.isFinished()) {
                   mScroller.computeScrollOffset();
                   setPieRotation(mScroller.getCurrY());
               } else {
                   mScrollAnimator.cancel();
                   onScrollFinished();
               }
           }
       });

使滑動過程更流暢

用戶不希望狀態之間的過渡發生卡頓。所以UI元素的淡入淡出取代了閃現與消失。動作的平滑過渡取代了突然的啟動與停止。Android 3.0中出現的property animation framework使平滑轉場更加簡便。

每次屬性的變更都會影響View的外觀,所以不要直接更改它們的屬性。相反,可以使用ValueAnimator來做出變更。在下面的示例中,修改當前所選擇的扇形圖會使整個餅圖發生旋轉,所以選擇的這個點在餅圖中看起來是居正中的。ValueAnimator更改旋轉用了數百毫秒的時間。

mAutoCenterAnimator = ObjectAnimator.ofInt(PieChart.this, "PieRotation", 0);
mAutoCenterAnimator.setIntValues(targetAngle);
mAutoCenterAnimator.setDuration(AUTOCENTER_ANIM_DURATION);
mAutoCenterAnimator.start();

如果你想更改View的基礎屬性,那麼這項事情就更容易了,因為View有一個內置的View屬性動畫框架ViewPropertyAnimator,它專門用來同時作用多個屬性,比如:

animate().rotation(targetAngle).setDuration(ANIM_DURATION).start();
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved