> 在用戶的交互中,有不止一種的方法來(lái)截獲事件??紤]到在用戶界面中的事件時(shí),從特殊的與用戶交互的view對(duì)象中捕獲事件,View類提供了一些特殊的方法。 再各種的視圖類中,你要編寫自己的布局,你可以聲明一些公共的回調(diào)方法來(lái)響應(yīng)UI事件。當(dāng)相應(yīng)的動(dòng)作發(fā)生時(shí),這些方法會(huì)被android框架自動(dòng)調(diào)用。例如,當(dāng)一個(gè)view被觸摸時(shí),onTouchEvent()方法被調(diào)用。然而,為了截獲這些方法,我們需要重寫這些方法。當(dāng)然了,重寫每一個(gè)這樣的方法顯然時(shí)不實(shí)際的,這就是為什么為何view類會(huì)有一些必須的接口這樣你可以更加容易的使用。這些接口,被稱作事件監(jiān)聽(tīng)器 event listeners,這就是捕捉到界面上用戶操作的關(guān)鍵。 當(dāng)你經(jīng)常在用戶交互上使用事件監(jiān)聽(tīng)器時(shí),有時(shí)需要自己寫一個(gè)繼承自view的類,來(lái)自定義一個(gè)部件。如果你想繼承一個(gè)Button類來(lái)實(shí)現(xiàn)更多的功能,這種情況下,你可以借助event handlers 類來(lái)定義默認(rèn)的事件處理類。 事件監(jiān)聽(tīng)器是包含簡(jiǎn)單回調(diào)方法的view類的一個(gè)接口,當(dāng)用戶觸發(fā)了一些注冊(cè)過(guò)的事件時(shí),android系統(tǒng)框架會(huì)自動(dòng)調(diào)用相應(yīng)的方法。 事件監(jiān)聽(tīng)器包含以下幾個(gè)方法: onCLick() 來(lái)自View.onClickListener。 當(dāng)view被觸摸,或者焦點(diǎn)在view上時(shí),用戶按了確認(rèn)鍵或?qū)Ш芥I。 onLongClick() 來(lái)自 View.onLongClickListener。當(dāng)view被觸摸超過(guò)1秒,或者焦點(diǎn)在view上,用戶按了確認(rèn)或?qū)Ш芥I超過(guò)1秒時(shí),方法被調(diào)用。 onFocysChange() 來(lái)自 View.onFocusChangeListener。當(dāng)焦點(diǎn)離開(kāi)view時(shí)被調(diào)用。 onKey() 來(lái)自 View.onKeylistener。按下或者彈起某個(gè)鍵時(shí)方法被調(diào)用。 onTouch() 來(lái)自 View.OnTouchListener。當(dāng)用戶操作屏幕時(shí)被調(diào)用,包括按下釋放或者其他的操作。 onCreateContextMenu() 來(lái)自 View.onCreateContextMenuListener。當(dāng)一個(gè)Context Menu菜單被建立時(shí)調(diào)用。 這些方法都有自己的接口方法。如果想定義這些方法來(lái)處理自己的事件,只要在activity里面使用匿名類即可。然后使用View.setXXXListener()方法,將匿名類傳遞給view。 下面的例子演示了怎樣給一個(gè)Button注冊(cè)一個(gè)監(jiān)聽(tīng)器:
- // Create an anonymous implementation of OnClickListener
private OnClickListener mCorkyListener = new OnClickListener() {
public void onClick(View v) {
// do something when the button is clicked
}
};
protected void onCreate(Bundle savedValues) {
...
// Capture our button from layout
Button button = (Button)findViewById(R.id.corky);
// Register the onClick listener with the implementation above
button.setOnClickListener(mCorkyListener);
...
}
復(fù)制代碼你會(huì)發(fā)現(xiàn)讓activity實(shí)現(xiàn)監(jiān)聽(tīng)器接口是非常方便的,他可以讓你的程序避免多余的對(duì)象分配。 - [size=14px]public class ExampleActivity extends Activity implements OnClickListener {
protected void onCreate(Bundle savedValues) {
...
Button button = (Button)findViewById(R.id.corky);
button.setOnClickListener(this);
}
// Implement the OnClickListener callback
public void onClick(View v) {
// do something when the button is clicked
}
...
} [/size]
復(fù)制代碼注意,上面例子中的onClick()回調(diào)方法沒(méi)有返回值,但其他的時(shí)間監(jiān)聽(tīng)器必須返回一個(gè)boolean類型的返回值,這是由監(jiān)聽(tīng)器的類型決定的,例如:onLongClick()這個(gè)方法會(huì)返回一個(gè)布爾值,來(lái)說(shuō)明這個(gè)事件正在進(jìn)行,也就是說(shuō),返回true表明此事件正在被處理不會(huì)被繼續(xù)傳遞了。onKey()也會(huì)返回一個(gè)布爾值,返回true的話說(shuō)明此按鍵事件將會(huì)被處理并不會(huì)被繼續(xù)響應(yīng)。如果你沒(méi)有處理或者希望事件繼續(xù)被其他監(jiān)聽(tīng)器響應(yīng),那么返回false。onTouch()返回同上,也是返回true就不再被傳遞。重點(diǎn)是有很多類型的事件與這個(gè)事件有關(guān),例如,當(dāng)接收到鍵被按下的事件時(shí),如果你此時(shí)返回false,那么表明你將不會(huì)處理這個(gè)按鍵事件。因此,你不會(huì)處理這個(gè)事件,例如手勢(shì)或者其他后續(xù)事件。記住這些按鍵事件總會(huì)讓當(dāng)前veiw成為當(dāng)前焦點(diǎn),他們從view層次結(jié)構(gòu)的頂端開(kāi)始被一級(jí)級(jí)傳遞,直到到達(dá)應(yīng)該被響應(yīng)的地方。如果你的view或者子view當(dāng)前擁有焦點(diǎn),那么你可以看到事件怎樣傳遞到dispatchKeyEvent()方法。作為一種捕捉按鍵事件的替代方法,你可以接收activity里的所有的onKeyDown()和onKeyUp()事件。注意:Android會(huì)首先調(diào)用事件處理程序,然后再調(diào)用自定義的事件處理類。例如:返回true將會(huì)阻止事件被繼續(xù)傳遞給下一層,也會(huì)阻止系統(tǒng)做一些默認(rèn)的處理,所以如果你確定要終止這個(gè)事件就返回true。 如果你創(chuàng)建了一個(gè)自定義的view組件,那么你要定義幾種回調(diào)方法來(lái)。在Building Custom Components文檔中,你會(huì)學(xué)習(xí)到以下幾個(gè)回調(diào)事件:onKeyDown(int,ketEvent);鍵被按下onKeyUp(int,keyEvent);鍵彈起onTrackballEvent(MotionEvent);軌跡球事件onTouchEvent(MotionEvent);觸摸屏幕事件onFocusChanged(boolean,int,Rect);焦點(diǎn)改變事件這里有一些你需要知道的方法,他們不是view類的一部分,但是會(huì)直接影響到你對(duì)事件的處理。所以遇到十分復(fù)雜的布局時(shí),可以考慮以下的幾個(gè)方法:Activity.dispatchTouchEvent(MotionEvent)它允許你的activity攔截所有的觸摸事件ViewGroup.onInterceptTouchEvent(MotionEvent)允許VeiwGroup來(lái)觀察子view的事件ViewParent.requestDisallowInterceptTouchEvent(boolean)告訴父View不應(yīng)該使用相關(guān)方法來(lái)攔截事件。
當(dāng)用戶正在使用導(dǎo)航鍵或者軌跡球來(lái)與手機(jī)交互時(shí),有必要給當(dāng)前互動(dòng)的item例如button一個(gè)焦點(diǎn),來(lái)讓用戶看到接收輸入、或者說(shuō)當(dāng)前的控件。如果一個(gè)設(shè)備支持觸摸,那么操作時(shí)就不需要用上面的高亮顯示的方式來(lái)告訴用戶。因此,便有了這種觸摸模式。對(duì)于有觸摸功能的設(shè)備來(lái)說(shuō),一旦用戶觸摸了屏幕,設(shè)備便會(huì)進(jìn)入觸摸模式。只有那些isFocusableInTouchMode()返回true的控件才可以獲得焦點(diǎn),例如文本編輯框。別的view是touchable的,例如按鈕,但被點(diǎn)擊時(shí)不會(huì)顯示焦點(diǎn)。當(dāng)被按下時(shí),他們的事件監(jiān)聽(tīng)器將會(huì)無(wú)效。任何時(shí)候用戶點(diǎn)擊了導(dǎo)航鍵或者軌跡球,設(shè)備都會(huì)退出touch模式,并且找一個(gè)view來(lái)顯示焦點(diǎn)?,F(xiàn)在,用戶可以不用觸摸屏幕來(lái)與設(shè)備進(jìn)行交互了。Touch模式存在于整個(gè)系統(tǒng)中。包括窗口和activity??梢杂胕sinTouchMode()方法來(lái)查詢當(dāng)前模式。
框架會(huì)處理常規(guī)的焦點(diǎn)改變事件來(lái)響應(yīng)用戶的輸入。包括一些veiw的顯示和隱藏。view通過(guò)isFocusable()方法來(lái)設(shè)定是否可以得到焦點(diǎn)。調(diào)用setFocusable()方法可以改變focusable狀態(tài)。當(dāng)view在觸摸模式,你可以通過(guò)調(diào)用isFocusableInTouchMode()方法查詢到是否支持,通過(guò)setFocusableInTouchMode()來(lái)設(shè)置。焦點(diǎn)的運(yùn)動(dòng)是根據(jù)給定方向最近的一個(gè)view來(lái)確定的。在極少情況下,默認(rèn)的這種算法或許不符合開(kāi)發(fā)者預(yù)期的要求。這種情況下,可以通過(guò)xml來(lái)明確確定焦點(diǎn)的轉(zhuǎn)移情況。例如: - <LinearLayout
android:orientation="vertical"
... >
<Button android:id="@+id/top"
android:nextFocusUp="@+id/bOTTom"
... />
<Button android:id="@+id/bottom"
android:nextFocusDown="@+id/top"
... />
</LinearLayout>
復(fù)制代碼一般的,在垂直的布局里,往下或者往上移動(dòng)軌跡球或是導(dǎo)航鍵多不能移動(dòng)焦點(diǎn),現(xiàn)在可以通過(guò)xml的定義來(lái)達(dá)到移動(dòng)焦點(diǎn)的目的。如果你想要聲明可以獲得焦點(diǎn)的view,可以在xml里添加android:focusable這個(gè)屬性,設(shè)置為true,你也可以在Touch模式下添加android:focusableInTouchMode。使用requestFocus()方法可以使一個(gè)特定的師徒取的焦點(diǎn)。使用onFocusChange()方法來(lái)監(jiān)聽(tīng)焦點(diǎn)事件。
|