iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 4
0
Software Development

英國研究顯示,連續30天用Kotlin開發Android將有益於身心健康系列 第 4

Android Kotlin 實作 Day 4 : Scalable_ImageView( 使用MotionEvent + 座標系統 )

使用語言

  • Kotlin

使用元件

  • ImageView

Method


OnTouchListener

手指觸控螢幕時觸發

moveImage.setOnTouchListener(mOnTouchListener)

val mOnTouchListener = object : View.OnTouchListener {
    override fun onTouch(view: View?, event: MotionEvent?): Boolean {
        when (event!!.action and MotionEvent.ACTION_MASK) {
            //設置事件
        }
        //通知 ViewGroup 要接收此事件,事件將不往下傳遞
        return true 
    }
}      
  • MotionEvent

    • MotionEvent.action:

      • ACTION_DOWN : 第一根手指按下時觸發

      • ACTION_POINTER_DOWN : 第二、三、四…等等的手指按下時觸發

      • ACTION_MOVE : 螢幕上觸控點滑動時觸發

      • ACTION_POINTER_UP : 在螢幕剩一個觸控點之前,手指離開螢幕時觸發

      • ACTION_UP : 最後一根手指離開螢幕時觸發

        #目前測試發現,三指同時按下時,event.pointerCount 會為 2,
         且無論手指依序或同時起來,ACTION_POINTER_UP 及 ACTION_UP 皆
         不會觸發,這部分仍待了解原因

    • event:

      # Id : 每根手指從按下至離開,會擁有一個固定Id

      # Index : 範圍為 [ 0 , pointerCount-1],且每根手指的Index有可能會變動


View.layout(l, t, r, b)

設置 View 的上下左右邊界

  • l : view.left

  • t : view.top

  • r : view.right = view.left + view.width

  • b : view.bottom = view.top + view.height

# View.x = view.left + view.translateX

# View.y = view.top + view.translateY


座標系統

設計邏輯

定義變數 mode 供 ACTION_MOVE 使用

companion object {
    val MODE_NONE = 0
    val MODE_MOVE = 1
    val MODE_ZOOM = 2
} 

val mOnTouchListener = object : View.OnTouchListener {
    override fun onTouch(view: View?, event: MotionEvent?): Boolean {
        when (event!!.action and MotionEvent.ACTION_MASK) {
        
            ACTION_DOWN -> { mode = MODE_MOVE }

            ACTION_POINTER_DOWN -> { 
                if (event.pointerCount <= 2) {
                //兩指皆在View內才觸發
                    if(判斷觸控點是否在 View 內的條件){ mode = MODE_ZOOM } 
                } 
                else mode = MODE_NONE
            }

            ACTION_POINTER_UP -> { mode = MODE_NONE }          
        }
        return true 
    }
}

拖曳計算

  • 目標:找出新位置的 view.x 及 view.y 並設置

  • 作法:

    ACTION_DOWN 時先將要扣掉的長度存進變數

    ACTION_MOVE 時設定新的 view.x 及 view.y

  • Code:

ACTION_DOWN -> {
    xToSub = event.raxX - view.x
    yToSub = event.raxY - view.y
}

ACTION_MOVE -> {
    view!!.x = event.rawX - xToSub
    view.y = event.rawY - yToSub
}
  • 拖曳邊界

    避免 View 跑出畫面回不來

    1. 自定義期望的拖曳邊界

    2. ACTION_UP 時,用 view 當前的上下左右判斷是否跑出邊界

    3. 若超出邊界,則重新設置 view.x 及 view.y

縮放計算

  1. ACTION_POINTER_DOWN 時取得兩觸控點的距離及中點

    # 不能用 event.rawX,因為無法透過 Index 或 Id 取得兩個點分別的 event.rawX

  2. ACTION_MOVE :

    1. 透過中點座標及初始距離找移動後 left 的位置

      left = midX - (oriX * ratio) + view.translateX

      # 沒加 view.translateX 的話求出來的為 view.x

    2. 仿照上述方式取得 top

    3. right = left + (原 width * ratio)

      bottom = top + (原 height * ratio)

    4. 設置 view.layout(left, top, right, bottom)

    5. 避免縮到太小

      設定 view 的最小長、寬

      若 (原 width * ratio) < 最小值,則將 width 設為自定義的最小值

實作成果


image 圖片來源

查看詳細 Code > GitHub

tags: Android Kotlin onTouch MotionEvent 座標系統 多指觸控 View Layout

上一篇
Android Kotlin 實作 Day 3 : Image picker ( 使用 Permission+ FileProvider + Intent)
下一篇
Android Kotlin 實作 Day 5 : WebView_Search(使用 WebView+Keyboard)
系列文
英國研究顯示,連續30天用Kotlin開發Android將有益於身心健康30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言