標簽:而且 其他 啓動界面 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