將自訂檢視畫面設為互動式

試用 Compose
Jetpack Compose 是 Android 推薦的 UI 工具包。瞭解如何在 Compose 中使用版面配置。

繪製 UI 只是建立自訂檢視區塊的一部分。您也需要 您的檢視畫面會回應使用者輸入內容,且與 您要模擬的實際動作

讓應用程式中的物件就像實際物件一樣。例如,別讓 應用程式中 實際上不會這麼做只要將圖片從某個位置移到 另一個例子。

使用者若能察覺介面上的細微行為或感覺,就能做出最好的回應 模仿現實世界的小工具舉例來說,當使用者快速滑過 UI 物件時 讓他們有意識到,早就延遲運動。結尾 讓他們產生動力,使物體除了在流動外 快速滑過

本頁面說明如何使用 Android 架構的功能來新增 並調整您的自訂檢視區塊。

如需更多相關資訊,請前往 輸入事件總覽屬性動畫 總覽頁面

處理輸入手勢

如同許多其他 UI 架構,Android 也支援輸入事件模型。使用者 動作會變成觸發回呼的事件,您也可以覆寫 回呼,藉此自訂應用程式回應使用者的方式。最常見的輸入內容 Android 系統中的事件是 touch,就會觸發 onTouchEvent(android.view.MotionEvent)。 覆寫這個方法以處理事件,如下所示:

Kotlin

override fun onTouchEvent(event: MotionEvent): Boolean {
    return super.onTouchEvent(event)
}

Java

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

觸控事件沒有特別實用。現代化觸控 UI 定義輕觸、提取、推送、 快速滑過或縮放如要將原始觸控事件轉換為手勢,Android 提供 GestureDetector

傳入類別的執行個體以建構 GestureDetector 會導入 GestureDetector.OnGestureListener。 如果只想處理一些手勢, GestureDetector.SimpleOnGestureListener 而不是實作 GestureDetector.OnGestureListener 存取 API舉例來說,以下程式碼會建立 GestureDetector.SimpleOnGestureListener 和覆寫設定 onDown(MotionEvent)

Kotlin

private val myListener =  object : GestureDetector.SimpleOnGestureListener() {
    override fun onDown(e: MotionEvent): Boolean {
        return true
    }
}

private val detector: GestureDetector = GestureDetector(context, myListener)

Java

class MyListener extends GestureDetector.SimpleOnGestureListener {
   @Override
   public boolean onDown(MotionEvent e) {
       return true;
   }
}
detector = new GestureDetector(getContext(), new MyListener());

無論是否使用 GestureDetector.SimpleOnGestureListener, 一律執行 onDown() 傳回 true 的方法。這項功能是必要動作,因為所有手勢 開頭為 onDown() 訊息。如果您退回 false 起價:onDown(),如 GestureDetector.SimpleOnGestureListener 會假設 系統會忽略另一個手勢和 GestureDetector.OnGestureListener 並未呼叫。僅退貨 如要忽略整個端點,請前往 onDown()false 手勢。

實作 GestureDetector.OnGestureListenerGestureDetector 的執行個體,您可以使用 GestureDetector 來解讀您收到的觸控事件 onTouchEvent()

Kotlin

override fun onTouchEvent(event: MotionEvent): Boolean {
    return detector.onTouchEvent(event).let { result ->
        if (!result) {
            if (event.action == MotionEvent.ACTION_UP) {
                stopScrolling()
                true
            } else false
        } else true
    }
}

Java

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

如果將 onTouchEvent() 傳遞到沒有該事件的觸控事件 視為手勢的一部分,就會傳回 false。接著您就能執行 您自己的自訂手勢偵測程式碼。

製作實際可行的動態效果

手勢雖然是用來控制觸控螢幕裝置,但功能 不符合直覺且難以記住,除非它們實際生產 並將結果視為合理的結果

舉例來說,假設您想實作水平快速滑過手勢, 設定在視圖中繪製的項目沿著垂直軸旋轉。這個手勢 如果 UI 以快速滑過方向快速回應,就會很合理 放慢速度,就像使用者推著飛輪而放慢速度一樣。

以下說明文件 將捲動動畫製作成動畫 手勢:詳細說明如何實作自己的骨架 行為但模擬飛輪的氛圍並非易事。涉及大量物理 而且需要數學運算,飛輪模型才能正確運作幸運的是 Android 提供了輔助類別,可模擬此情況和其他行為。 Scroller 類別是處理飛輪樣式快速滑過手勢的基礎。

如要開始快速滑過,請呼叫 fling() 將起始速度和最小值和最大值 xy 快速滑過輸入的值針對速率值,您可以使用 GestureDetector

Kotlin

fun onFling(e1: MotionEvent, e2: MotionEvent, velocityX: Float, velocityY: Float): Boolean {
    scroller.fling(
            currentX,
            currentY,
            (velocityX / SCALE).toInt(),
            (velocityY / SCALE).toInt(),
            minX,
            minY,
            maxX,
            maxY
    )
    postInvalidate()
    return true
}

Java

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

呼叫 fling() 會設定快速滑過的物理模型 手勢。然後,呼叫以更新 Scroller Scroller.computeScrollOffset() 定期間隔computeScrollOffset() 會更新 透過讀取目前時間及讀取 Scroller 物件的內部狀態 使用物理模型來計算該位置的 xy 位置 讓應用程式從可以最快做出回應的位置 回應使用者要求致電 getCurrX()getCurrY() 擷取這些值。

大部分的檢視畫面都會傳遞 Scroller 物件的 xy。 直接放置於 scrollTo()。 這個範例有些許不同之處,那就是使用目前捲動的 x 位置 設定檢視的旋轉角度。

Kotlin

scroller.apply {
    if (!isFinished) {
        computeScrollOffset()
        setItemRotation(currX)
    }
}

Java

if (!scroller.isFinished()) {
    scroller.computeScrollOffset();
    setItemRotation(scroller.getCurrX());
}

Scroller 類別會為您計算捲動位置,但會為您計算捲動位置 系統不會自動將這些位置套用至您的檢視畫面。套用新座標 ,讓捲動動畫看起來流暢。有兩種方法 :

  • 呼叫 以強制重新繪製 postInvalidate() 呼叫 fling() 後。要使用這個技巧, 運算捲動偏移 onDraw() 並在每次捲動偏移時呼叫 postInvalidate() 並輸入變更內容
  • 設定 ValueAnimator 為快速滑過效果加上動畫效果 並新增事件監聽器 呼叫 addUpdateListener()。 這項技術能夠為 View

順暢轉換

使用者會期望現代 UI 在狀態之間流暢轉換:UI 元素 淡入和淡出,而不是出現或消失,而且動畫開始 並順利結束,而不是突然開始和停止。Android 屬性動畫 架構,有助於您更輕鬆地進行轉換。

如要使用動畫系統,每當屬性變更會影響 請勿直接變更屬性而是改用 ValueAnimator即可進行變更。在以下範例中 修改檢視畫面中所選的子元件,就會讓整個畫面顯示 檢視旋轉,讓選取指標置中。 ValueAnimator 會在週期內變更數百個 毫秒,而不是立即設定新的輪播值。

Kotlin

autoCenterAnimator = ObjectAnimator.ofInt(this, "Rotation", 0).apply {
    setIntValues(targetAngle)
    duration = AUTOCENTER_ANIM_DURATION
    start()
}

Java

autoCenterAnimator = ObjectAnimator.ofInt(this, "Rotation", 0);
autoCenterAnimator.setIntValues(targetAngle);
autoCenterAnimator.setDuration(AUTOCENTER_ANIM_DURATION);
autoCenterAnimator.start();

如果您要變更的值是底數 View 的其中一個 屬性,由於檢視畫面內建 ViewPropertyAnimator 是針對多個屬性同時播放的動畫進行最佳化,如 範例:

Kotlin

animate()
    .rotation(targetAngle)
    .duration = ANIM_DURATION
    .start()

Java

animate().rotation(targetAngle).setDuration(ANIM_DURATION).start();