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

圖2-3 控件事件的響應(yīng)運行結(jié)果
本例構(gòu)建一個應(yīng)用程序,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>
以上布局文件中定義了兩個按鈕和一個文本框,這個布局文件被活動設(shè)置為Vi e w后,顯示的內(nèi)容就如圖2-2所示,只是行為還沒有實現(xiàn)。
行為將在源代碼文件TestEvent1.java中實現(xiàn),這部分的代碼如下所示:
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() { // 實現(xiàn)行為功能 public void onClick(View v) { Text.setTextColor(Color.RED); // 設(shè)置文本和文本顏色為“紅” Text.setText("RED"); } }); Button2.setOnClickListener(new OnClickListener() { public void onClick(View v) { Text.setTextColor(Color.GREEN); // 設(shè)置文本和文本顏色為“綠” Text.setText("GREEN"); } }); } }
在創(chuàng)建的過程中,通過findViewById()獲得各個屏幕上面的控件(控件)的背景,這里使用的R.id.button1等和布局文件中各個元素的id是對應(yīng)的。在布局文件中即使不寫android:id這一項也可以正常顯示,這一項的目的是在代碼中對其進行控制:通過Activity的findViewById()方法根據(jù)id獲得每一個控件的句柄,以View類型返回,可以轉(zhuǎn)換成實際的類型來使用。
Button控件的setOnClickListener()設(shè)置了其中的點擊行為,這個方法的參數(shù)實際上是一個View.OnClickListener類型的接口,這個接口需要被實現(xiàn)才能夠使用,因此在本例的設(shè)置中,實現(xiàn)了其中的onClick()方法。這樣即可在點擊的時候?qū)崿F(xiàn)相應(yīng)的功能,在點擊的方法中,將通過Te x t的句柄對其進行控制。
在獲取句柄時需要轉(zhuǎn)換成相應(yīng)的控件類型,findViewById()方法的參數(shù)是一個整數(shù),返回值是View類型。通過R.id.XXX找到布局文件中定義的ID,然后通過將基類View轉(zhuǎn)換成其實際的類獲得真正的句柄??丶D(zhuǎn)換類應(yīng)該和布局文件中描述的控件一致,如果轉(zhuǎn)換成這個類的祖先類,將會損失部分繼承者自身功能,如果轉(zhuǎn)換成非祖先類并調(diào)用其中的方法將會錯誤。
提示:在代碼中使用R.id.myid的時候,如果當(dāng)前包中根本沒有myid這個id,編譯將報錯。但是如果這個包中的其他布局文件中生成myid這個id,但當(dāng)前布局文件中沒有這個id,編譯不會報錯,運行時將會返回null,造成運行錯誤。
2.2.2 變化的響應(yīng)方法
在實現(xiàn)控件行為方面,除了上述的使用方法,根據(jù)Java的語法,還具有其他的實現(xiàn)方式。第二種響應(yīng)方法可以將不同控件的同一種行為聚集到一個方法的實現(xiàn)中;第三種響應(yīng)方法可以為一個控件單獨實現(xiàn)一個響應(yīng)。
1.第二種響應(yīng)方法:由Activity實現(xiàn)某接口
對控件的響應(yīng)可以由Activity類來實現(xiàn)某個Listener接口,完成其中的方法,然后將其設(shè)置為某個控件的監(jiān)聽者,以此得到對控件的響應(yīng)。
以下程序使用的是上述實現(xiàn)方式,在使用同樣的布局文件的情況下,本例使用的源代碼文件如下所示:
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 { // 實現(xiàn)相關(guān)的接口 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); // 設(shè)置監(jiān)聽者為TestEvent2 mButton2 = (Button) findViewById(R.id.button2); mButton2.setOnClickListener(this); // 設(shè)置監(jiān)聽者為TestEvent2 } public void onClick(View v) { Log.v(TAG, "onClick()"); switch(v.getId()){ // 通過getId()區(qū)分不同的控件 case R.id.button1: mText.setTextColor(Color.RED); // 設(shè)置文本和文本顏色為“紅” mText.setText("RED");
break; case R.id.button2: mText.setTextColor(Color.GREEN); // 設(shè)置文本和文本顏色為“綠” mText.setText("GREEN"); break; default: Log.v(TAG, "other"); break; } } }
這個例子的主要變化是讓活動實現(xiàn)了(implements)OnClickListener()這個接口,也就是需要實現(xiàn)其中的onClick()方法。然后通過setOnClickListener()將其設(shè)置到按鈕中的參數(shù)就是this,表示了當(dāng)前的活動。
通過以這種方式設(shè)置,如果程序中有多個控件需要設(shè)置,那么所設(shè)置的也都是一個方法。為了保證對不同控件有不同的處理,可以由onClick()方法的參數(shù)進行判斷,參數(shù)是一個View類型,通過getId()獲得它們的ID,使用switch…case分別進行處理。
在本例中,需要將文本框(TextView)句柄保存為類的成員(mText),這樣就可以在類的各個方法中都能獲得這個句柄進行處理。這和第一種方法是有區(qū)別的,因為第一個例子實現(xiàn)的接口和獲得的TextView在同一個方法中,因此不需要保存TextView的句柄,只需要使用final的局部變量即可。
2.第三種響應(yīng)方法:構(gòu)建一個類實現(xiàn)某接口
在響應(yīng)控件事件方面,一種最為直接的方法是:構(gòu)建一個類實現(xiàn)所需要的Listener接口,創(chuàng)建這個類的實例之后,將其設(shè)置到控件中。
以下為同樣功能的第三種實現(xiàn)方法,在布局文件相同的情況下,Java源代碼的內(nèi)容如下所示:
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 { // 接口的第一個實現(xiàn) public void onClick(View v) { mText.setTextColor(Color.RED); // 設(shè)置文本和文本顏色為“紅” mText.setText("RED"); } }
class Button2_Listener implements OnClickListener { // 接口的第一個實現(xiàn) public void onClick(View v) { mText.setTextColor(Color.GREEN); //設(shè)置文本和文本顏色為“綠” 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); // 設(shè)置監(jiān)聽者的類 mButton2.setOnClickListener(mListener2); // 設(shè)置監(jiān)聽者的類 } }
本例通過定義實現(xiàn)活動類中的兩個子類,來實現(xiàn)View.OnClickListener這個接口,這種方式是一種最為直接的方式,即為不同的控件單獨實現(xiàn)它的相應(yīng)類。
使用這種實現(xiàn)方法,如果由一個類繼承若干個Listener接口,可以讓其實現(xiàn)多個不同的行為。實現(xiàn)同時點擊和長按事件的方法如下所示:
class MyListener implements OnClickListener,OnLongClickListener { public void onClick(View v) { // ......點擊事件的實現(xiàn) } public boolean onLongClick(View v){ // ......長按事件的實現(xiàn) } }
隨后可以調(diào)用setOnClickListener()和setOnLongClickListener()將這個監(jiān)聽者的實現(xiàn)設(shè)置到某個控件當(dāng)中。這種方式尤其適合一個控件需要定制多個行為,并且可能多個行為之間還有共同處理(例如,調(diào)用同一個方法)的場合。
2.2.3 控件響應(yīng)方法比較
以上列出了在Java代碼中對控件事件做出響應(yīng)的三種方法,比較這三種方法,分別具有以下的特點。
第一種方法利用Java的語法,將所有內(nèi)容都組織到一個方法當(dāng)中。這種方法雖然看似簡單,但是這種程序的結(jié)構(gòu)性并不好。
第二種方法將不同控件的同一種行為聚集到一個方法中:只需要實現(xiàn)一個接口中的方法,就可以為所有控件使用。
第三種方法可以將同一個控件的不同行為聚集到一個類當(dāng)中。如果構(gòu)建一個類讓其繼承多個Listener,并實現(xiàn)其中的方法,可以同時完成對多個行為的響應(yīng)。
在實際的應(yīng)用場景中,由于多個同類控件響應(yīng)同一種行為的情況比較多見,因此在Android應(yīng)用程序的實現(xiàn)中,第二種方法的使用比第三種方法多。
如果同一個布局中控件的id有所重復(fù),即多個控件使用相同的id,在這種情況下,第二種方法的switch…case將不太容易區(qū)分每個控件。這時可以考慮使用第三種方法,自己實現(xiàn)不同的類,在設(shè)置監(jiān)聽器的階段對不同控件做出區(qū)分。