標簽:而且 其他 啟動界面 click 將不 右上角 系統 簡單 google
在上篇文章中已經了解到界面Activity
的繪制完全依賴其加載的視圖組件View
,不僅如此,用戶的每次觸摸操作都可以在界面Activity
內接收并響應,也可以直接傳遞給其中的某個視圖View
響應。本文將針對這兩種用戶交互方式分別展開介紹。
說到界面交互,很容易想到用戶在設備屏幕上的觸摸操作??墒瞧聊荒敲创笠趺创_定用戶觸摸的位置呢?Android系統定義了一套屏幕坐標規則,該規則不僅適用于當前的屏幕交互,在后文提及的動畫繪制及其他屏幕相關操作等都同樣適用。該規則將屏幕的左上角作為屏幕坐標的原點,從左上角往右上角延伸的方向作為屏幕坐標的x軸,從左上角往左下角延伸的方向作為屏幕坐標的y軸。
比如針對一款 1024x512 尺寸的TV設備,其左下角的屏幕坐標值為 (0, 512),右下角的屏幕坐標值為 (1024, 512),右上角的屏幕坐標值為 (1024, 0),左上角的屏幕坐標值為 (0, 0)。
對屏幕的觸摸位置有了衡量標準,是不是就可以根據不同的位置做觸摸操作了呢?說到觸摸操作,也需要細化之后單獨處理。Android系統將用戶操作行為,大致分為三種:按下行為,滑動行為,抬起釋放行為。這樣系統就可以根據每一個操作行為做單獨的響應處理了。
另外,用戶的操作對象,除了上文提到的硬件設備屏幕以外,還有硬件設備的按鍵(包括硬件按鍵和虛擬按鍵)。只不過對按鍵的操作行為只有按下行為和抬起釋放行為兩種,而且按鍵的操作不需要用到屏幕坐標相關內容。
基于上文的介紹,可以在界面Activity
中可以分別重寫下邊三個方法對用戶的界面操作交互做出響應。
boolean onTouchEvent(MotionEvent event)
在子視圖沒有處理的情況下,用戶對硬件設備屏幕的每一個操作,都會回調一次該方法。
其參數android.view.MotionEvent事件類的實例化對象event。
event.getAction()
方法可以獲取當前事件行為,包括MotionEvent.ACTION_DOWN
按下行為、MotionEvent.ACTION_MOVE
滑動行為、MotionEvent.ACTION_UP
抬起釋放行為等。
event.getX()
方法獲取當前操作的屏幕坐標x軸值。
同理event.getY()
方法獲取當前操作的屏幕坐標y軸值。
boolean onKeyDown(int keyCode, KeyEvent event)
在子視圖沒有處理的情況下,用戶對硬件設備按鍵的每一次按下行為,都會回調一次該方法。
參數一int類型的keyCode指定按鍵類型,一般其值與參數二event.getKeyCode()
相等。
參數二android.view.KeyEvent類的實例化對象event。
event.getAction()
方法同樣可以獲取當前事件行為,只有KeyEvent.ACTION_DOWN
按下行為和KeyEvent.ACTION_UP
抬起釋放行為兩個行為值。
event.getKeyCode()
方法可以獲取觸發當前事件的按鍵類型,其值包括KeyEvent.KEYCODE_HOME
HOME鍵,KeyEvent.KEYCODE_POWER
電源鍵,KEYCODE_VOLUME_UP
音量增加鍵等。
boolean onKeyUp(int keyCode, KeyEvent event)
在子視圖沒有處理的情況下,用戶對硬件設備按鍵的每一次抬起釋放行為,都會回調一次該方法。其兩個參數與上述onKeyDown()
中的兩個參數類似。
相對來說,界面內的視圖響應要繁瑣一些,而能實現的效果也更多樣化。當把視圖View
作為用戶的操作對象時,仍然可以重寫上述界面響應的三個方法,但是系統視圖往往也封裝了一層更加簡單粗暴的響應方法。
在視圖中重寫界面響應的三個方法后,如果返回的結果為true,則上文界面響應中的三個方法將不會被回調。
為什么需要封裝一層響應方法呢?用戶對視圖的操作,往往就是點擊(短時間內執行按下行為和抬起釋放行為),長按(在執行按下行為后等待一段時間再執行抬起釋放行為),拖拽(在執行按下行為后執行一段滑動行為之后再執行抬起釋放行為)這些固定操作類型。如果每個視圖都要細分用戶的操作行為,就會有大量冗余的操作類型判斷代碼,所以AndroidSDK定義了一系列接口分別對應用戶的操作類型。視圖如果需要響應某個操作,只需要設置其操作類型接口的實例化對象,并在該對象中實現相關方法即可。而這些接口主要有以下三個。
onClick(View view)
方法,在該方法內響應響應視圖View
被用戶點擊后的代碼邏輯。onLongClick(View view)
方法,在該方法內響應響應視圖View
被用戶長按后的代碼邏輯。onDrag(View v, DragEvent event)
方法,在該方法內響應視圖View
被用戶拖拽后的代碼邏輯。另外,不同的系統視圖也可能有單獨設置的響應方法,或者自定義視圖也會提供單獨的響應方法,例如列表視圖中的某一行數據被單獨點擊后如何響應,這些都要根據具體的視圖類查找并使用對應的響應方法,這里不再贅述。
在上文界面響應的三個方法中,關于他們被回調的時機,有個前提是子視圖沒有處理,即子視圖的界面響應方法返回結果為false。這就涉及到Android系統的事件傳遞機制了。
我們知道界面Activity
在創建之后會調用setContentView(int layoutId)
加載根視圖View
,而根視圖里邊則可以內嵌一層層的子視圖。那么,如果用戶將手指觸摸到屏幕上,會觸發按下行為,該行為作為事件首先傳遞到根視圖中,之后根視圖再將該事件傳遞給子視圖,子視圖再將該事件傳遞給子視圖的子視圖,這樣按照加載時的嵌套順序一層層傳遞事件,稱之為事件分發。
直到該事件傳遞到最后一層子視圖,或者某一層視圖不再繼續傳遞該事件,那么該事件將在最后傳遞到的這層視圖中被首先處理。而每層視圖在收到傳遞進來的事件后,都有兩條路可以選擇,要么將該事件繼續傳遞給子視圖,要么自己處理該事件,如果選擇第二條路不再繼續傳遞子視圖而是自己處理該事件,稱之為事件攔截。
一旦某層視圖處理了該事件,那么其父層視圖將繼續處理該事件,之后是父層的父層視圖處理該事件,事件被這樣一層層處理,直到根視圖處理該事件結束,稱之為事件處理。
在經歷了事件分發和事件處理之后,這樣的一個事件傳遞機制就算完成了。而上文提到的每一個事件,都是如此。
上述過程在代碼中的實現,只需要針對事件分發、事件攔截和事件處理分別定義一個可重寫的方法即可。能夠重寫該方法的位置主要是android.app.Acitivty
和android.view.View
中,由于事件攔截只會發生在子視圖的傳遞過程中,在界面中并不需要,所以事件攔截對應的方法只在android.view.GroupView
中重寫。
boolean dispatchTouchEvent (MotionEvent event)
boolean onInterceptTouchEvent(MotionEvent event)
dispatchTouchEvent()
。返回結果為true時,表示攔截該事件,將會回調當前視圖的onTouchEvent()
.boolean onTouchEvent (MotionEvent event)
上文介紹了針對一個界面Activity
的交互響應,那么兩個界面Activity
之間如何交互呢?這就用到在加載界面一文中啟動Activity
所使用的android.content.Intent
意圖類了。不同于用戶與界面的交互,界面間交互主要是變量數據的共享,所以通過Intent
支持的交互數據類型是有限的。
在啟動一個界面Activity
之前要先創建意圖對象,在該意圖對象調用putExtras(Bundle bundle)
方法,可以將要發送的數據打包成android.os.Bundle類型的實例存入。
而該Bundle
對象可以存儲的數據類型支持包括boolean
、char
、byte
、short
、int
、float
、double
、long
八種基本數據類型,String
類型和實現Parcelable
接口的任意類型,及其[]
數組或ArrayList
數組,和其他一些不常用類型。這些數據都是以key-value鍵值對的形式保存在Bundle
對象中。對于要保存的不同數據類型,分別調用對應的putT(String key, T value)
系列方法即可以參數一key和參數二value的形式存入,同樣可以調用對應的getT(String key)
系列方法取出指定參數一key對應的value數據,這里的T泛指支持的不同數據類型。
另外也可以在創建的意圖對象中直接調用putExtra(String key, T value)
系列方法,將要發送的數據直接以key-value鍵值對的形式存入,同樣也可以使用getTExtra(String key)
系列方法取出指定參數一key對應的value數據,這里的T同樣泛指Bundle
可支持的不同數據類型。
在打包所有的數據后,就可以在當前界面Activity
中繼續調用startActivity(Intent intent)
系列方法啟動Intent
意圖參數中指定的另一界面Activity
了。
這里的startActivity(Intent)
方法是最簡單的啟動方法,另外還有startActivity(Intent, Bundle)
在啟動時將要發送的數據打包作為參數二傳入。
或者startActivityForResult(Intent intent, int requestCode)
在啟動時傳入一個唯一值作為參數二,以區分啟動不同界面的意圖,在啟動的界面Activity
返回后,系統會調用當前界面Activity
中的onActivityResult(int requestCode, int resultCode, Intent data)
方法,因此可以重寫該方法。并根據參數一的唯一性對之前啟動的不同界面意圖做區分處理。參數二是根據啟動界面不同關閉狀態所返回的結果值,默認為android.app.Activity.RESULT_CANCELED
,另外也可以為android.app.Activity.RESULT_FIRST_USER
和android.app.Activity.RESULT_OK
,其值需要在啟動界面返回時設置。參數三是從啟動界面返回的Intent
類型,主要使用其中的Bundle
打包數據類型對象,同樣其值可以在啟動界面返回時設置。
作為接收數據的啟動界面Activity
,在其綁定上下文環境之后,一般是在onCreate(Bundle savedInstanceState)
方法中,可以使用getIntent()
方法獲取傳遞進來的Intent
意圖對象,獲取該對象之后自然就可以通過getBExtras()
或一系列getTExtra(String key)
獲取到打包的數據,這樣在啟動界面中就可以使用在啟動之前上一個界面Activtiy
中的變量數據了。
而當啟動界面Activity
在被用戶操作返回時,系統將回調該啟動界面的onBackPressed()
方法,之后將該Activity
從棧中移出并銷毀。所以可以重寫onBackPressed()
方法,在該方法中調用setResult(int resultCode, Intent data)
設置上文提到的返回時參數。
或者在啟動界面Activity
代碼中也可以主動調用finish()
方法,以關閉當前界面。因此在調用finish()
方法之前先調用setResult(int resultCode, Intent data)
設置返回參數即可。
Android系統編程入門系列之界面Activity交互響應
標簽:而且 其他 啟動界面 click 將不 右上角 系統 簡單 google
原文地址:https://www.cnblogs.com/BobGo/p/15004013.html