- Android經典應用程序開發
- 韓超編著
- 1180字
- 2019-01-09 15:18:45
2.2 屏幕中內容的控制和響應
Android屏幕中的內容是android.view.View類的繼承者。按照通常的概念,這些View的繼承者可以稱為控件。對于屏幕中內容(控件)的控制和響應是GUI系統最基礎的內容。
程序中,對于屏幕中內容(控件)的控制和響應的兩個使用要點為:
獲得控件句柄;
定制控件的行為;
在Android中,得到控件的句柄通常是由id屬性來指定的。在布局文件中,用于指定id的XML屬性為android:id。
findViewById()方法用于得到一個控件句柄,其參數為控件的id,方法如下所示:
public View findViewById (int id)
findViewById()是View和Activity都具有的方法,對于View表示獲得其某個子控件句柄,對于Activity,表示獲得其中內容視圖(ContentView)的某個子控件句柄。
定制控件的行為,通常需要使用View類中的SetOn{XXX}Listener()系列方法,設置的內容也就是前面所述的android.view包中的幾個接口。這個方法可以在每一個繼承View控件中被調用。
2.2.1 基本響應方法
本節介紹Android中的幾種基本的程序控制方法,要獲得的效果是通過兩個按鈕來控制一個文本框的文字和字體顏色,其運行結果如圖2-3所示。

圖2-3 控件事件的響應運行結果
本例構建一個應用程序,TestEvent1是活動的名稱,res/layout目錄中的testevent.xml是界面布局文件。本例布局文件的代碼如下所示:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/screen" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical"> <TextView android:id="@+id/text1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:textSize="24sp" android:text="@string/text1" /> <Button android:id="@+id/button1" android:layout_width="80sp" android:layout_height="wrap_content" android:layout_gravity="center" android:text="@string/red"/> <Button android:id="@+id/button2" android:layout_width="80sp" android:layout_height="wrap_content" android:layout_gravity="center" android:text="@string/green"/> </LinearLayout>
以上布局文件中定義了兩個按鈕和一個文本框,這個布局文件被活動設置為Vi e w后,顯示的內容就如圖2-2所示,只是行為還沒有實現。
行為將在源代碼文件TestEvent1.java中實現,這部分的代碼如下所示:
import android.app.Activity; import android.os.Bundle; import android.graphics.Color; import android.widget.Button; import android.widget.TextView; import android.view.View; import android.view.View.OnClickListener; import android.util.Log; public class TestEvent1 extends Activity { private static final String TAG = "TestEvent1"; public TestEvent1() { } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.testevent); final TextView Text = (TextView) findViewById(R.id.text1); // 獲得句柄 final Button Button1 = (Button) findViewById(R.id.button1); final Button Button2 = (Button) findViewById(R.id.button2); Button1.setOnClickListener(new OnClickListener() { // 實現行為功能 public void onClick(View v) { Text.setTextColor(Color.RED); // 設置文本和文本顏色為“紅” Text.setText("RED"); } }); Button2.setOnClickListener(new OnClickListener() { public void onClick(View v) { Text.setTextColor(Color.GREEN); // 設置文本和文本顏色為“綠” Text.setText("GREEN"); } }); } }
在創建的過程中,通過findViewById()獲得各個屏幕上面的控件(控件)的背景,這里使用的R.id.button1等和布局文件中各個元素的id是對應的。在布局文件中即使不寫android:id這一項也可以正常顯示,這一項的目的是在代碼中對其進行控制:通過Activity的findViewById()方法根據id獲得每一個控件的句柄,以View類型返回,可以轉換成實際的類型來使用。
Button控件的setOnClickListener()設置了其中的點擊行為,這個方法的參數實際上是一個View.OnClickListener類型的接口,這個接口需要被實現才能夠使用,因此在本例的設置中,實現了其中的onClick()方法。這樣即可在點擊的時候實現相應的功能,在點擊的方法中,將通過Te x t的句柄對其進行控制。
在獲取句柄時需要轉換成相應的控件類型,findViewById()方法的參數是一個整數,返回值是View類型。通過R.id.XXX找到布局文件中定義的ID,然后通過將基類View轉換成其實際的類獲得真正的句柄。控件轉換類應該和布局文件中描述的控件一致,如果轉換成這個類的祖先類,將會損失部分繼承者自身功能,如果轉換成非祖先類并調用其中的方法將會錯誤。
提示:在代碼中使用R.id.myid的時候,如果當前包中根本沒有myid這個id,編譯將報錯。但是如果這個包中的其他布局文件中生成myid這個id,但當前布局文件中沒有這個id,編譯不會報錯,運行時將會返回null,造成運行錯誤。
2.2.2 變化的響應方法
在實現控件行為方面,除了上述的使用方法,根據Java的語法,還具有其他的實現方式。第二種響應方法可以將不同控件的同一種行為聚集到一個方法的實現中;第三種響應方法可以為一個控件單獨實現一個響應。
1.第二種響應方法:由Activity實現某接口
對控件的響應可以由Activity類來實現某個Listener接口,完成其中的方法,然后將其設置為某個控件的監聽者,以此得到對控件的響應。
以下程序使用的是上述實現方式,在使用同樣的布局文件的情況下,本例使用的源代碼文件如下所示:
import android.app.Activity; import android.os.Bundle; import android.graphics.Color; import android.widget.Button; import android.widget.TextView; import android.view.View; import android.view.View.OnClickListener; import android.util.Log; public class TestEvent2 extends Activity implements OnClickListener { // 實現相關的接口 private static final String TAG = "TestEvent2"; private TextView mText; // 保存控件類的引用 private Button mButton1; private Button mButton2; public TestEvent2() { } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.testevent); mText = (TextView) findViewById(R.id.text1); mButton1 = (Button) findViewById(R.id.button1); mButton1.setOnClickListener(this); // 設置監聽者為TestEvent2 mButton2 = (Button) findViewById(R.id.button2); mButton2.setOnClickListener(this); // 設置監聽者為TestEvent2 } public void onClick(View v) { Log.v(TAG, "onClick()"); switch(v.getId()){ // 通過getId()區分不同的控件 case R.id.button1: mText.setTextColor(Color.RED); // 設置文本和文本顏色為“紅” mText.setText("RED");
break; case R.id.button2: mText.setTextColor(Color.GREEN); // 設置文本和文本顏色為“綠” mText.setText("GREEN"); break; default: Log.v(TAG, "other"); break; } } }
這個例子的主要變化是讓活動實現了(implements)OnClickListener()這個接口,也就是需要實現其中的onClick()方法。然后通過setOnClickListener()將其設置到按鈕中的參數就是this,表示了當前的活動。
通過以這種方式設置,如果程序中有多個控件需要設置,那么所設置的也都是一個方法。為了保證對不同控件有不同的處理,可以由onClick()方法的參數進行判斷,參數是一個View類型,通過getId()獲得它們的ID,使用switch…case分別進行處理。
在本例中,需要將文本框(TextView)句柄保存為類的成員(mText),這樣就可以在類的各個方法中都能獲得這個句柄進行處理。這和第一種方法是有區別的,因為第一個例子實現的接口和獲得的TextView在同一個方法中,因此不需要保存TextView的句柄,只需要使用final的局部變量即可。
2.第三種響應方法:構建一個類實現某接口
在響應控件事件方面,一種最為直接的方法是:構建一個類實現所需要的Listener接口,創建這個類的實例之后,將其設置到控件中。
以下為同樣功能的第三種實現方法,在布局文件相同的情況下,Java源代碼的內容如下所示:
package com.android.basicapp; import android.app.Activity; import android.os.Bundle; import android.graphics.Color; import android.widget.Button; import android.widget.TextView; import android.view.View; import android.view.View.OnClickListener; import android.util.Log; public class TestEvent3 extends Activity{ private static final String TAG = "TestEvent3"; private TextView mText; private Button1_OnClickListener mListener1 = new Button1_Listener(); private Button2_OnClickListener mListener2 = new Button2_Listener(); public TestEvent3() { } class Button1_Listener implements OnClickListener { // 接口的第一個實現 public void onClick(View v) { mText.setTextColor(Color.RED); // 設置文本和文本顏色為“紅” mText.setText("RED"); } }
class Button2_Listener implements OnClickListener { // 接口的第一個實現 public void onClick(View v) { mText.setTextColor(Color.GREEN); //設置文本和文本顏色為“綠” mText.setText("GREEN"); } } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.testevent); mText = (TextView) findViewById(R.id.text1); final Button mButton1 = (Button) findViewById(R.id.button1); final Button mButton2 = (Button) findViewById(R.id.button2); mButton1.setOnClickListener(mListener1); // 設置監聽者的類 mButton2.setOnClickListener(mListener2); // 設置監聽者的類 } }
本例通過定義實現活動類中的兩個子類,來實現View.OnClickListener這個接口,這種方式是一種最為直接的方式,即為不同的控件單獨實現它的相應類。
使用這種實現方法,如果由一個類繼承若干個Listener接口,可以讓其實現多個不同的行為。實現同時點擊和長按事件的方法如下所示:
class MyListener implements OnClickListener,OnLongClickListener { public void onClick(View v) { // ......點擊事件的實現 } public boolean onLongClick(View v){ // ......長按事件的實現 } }
隨后可以調用setOnClickListener()和setOnLongClickListener()將這個監聽者的實現設置到某個控件當中。這種方式尤其適合一個控件需要定制多個行為,并且可能多個行為之間還有共同處理(例如,調用同一個方法)的場合。
2.2.3 控件響應方法比較
以上列出了在Java代碼中對控件事件做出響應的三種方法,比較這三種方法,分別具有以下的特點。
第一種方法利用Java的語法,將所有內容都組織到一個方法當中。這種方法雖然看似簡單,但是這種程序的結構性并不好。
第二種方法將不同控件的同一種行為聚集到一個方法中:只需要實現一個接口中的方法,就可以為所有控件使用。
第三種方法可以將同一個控件的不同行為聚集到一個類當中。如果構建一個類讓其繼承多個Listener,并實現其中的方法,可以同時完成對多個行為的響應。
在實際的應用場景中,由于多個同類控件響應同一種行為的情況比較多見,因此在Android應用程序的實現中,第二種方法的使用比第三種方法多。
如果同一個布局中控件的id有所重復,即多個控件使用相同的id,在這種情況下,第二種方法的switch…case將不太容易區分每個控件。這時可以考慮使用第三種方法,自己實現不同的類,在設置監聽器的階段對不同控件做出區分。