官术网_书友最值得收藏!

4.4 常用Widget組件

在前面章節的學習中講解了用戶界面UI設計中布局方面的知識,其中涉及少數幾個常用的組件,例如按鈕、文本框等。在這一節中著重講解Android用戶UI設計中常用的各種組件的用法。

Android SDK提供了名為android.widget的包,其中提供了在應用程序界面設計中大部分常用的UI可視組件。之前章節中涉及的各種布局以及文本框、按鈕等組件,都包含在這個包中。Android提供了強大的用戶UI功能,要設計自己獨特的應用程序界面,需要對各個組件有一個詳細的了解。

4.4.1 創建Widget組件實例

在Eclipse中創建一個新的工程,名字為WidgetDemo,用于對各種常見UI組件進行學習。下面是工程實現步驟,在后續的章節中不會再贅述該過程:

步驟01 新建項目。單擊File | New | Android Project,打開New Android Projec對話框,如圖4.12所示。

圖4.12 新建項目

步驟02 輸入工程名稱WidgetDemo,在Location后的文本框中輸入工程的保存路徑,單擊Next后選擇Android4.0,單擊Next。

步驟03 輸入包名“introduction.android.widgetDemo”和Activity的名稱WidgetDemoActivity,單擊Finish,則Eclipse會生成工程目錄和相關文件。

WidgetDemoActivity.java文件是當前應用程序的入口類WidgetDemoActivity的定義文件。雙擊WidgetDemoActivity.java,發現Eclipse已經為其生成代碼如下:

    package introduction.android.widgetDemo;
    import android.app.Activity;
    import android.os.Bundle;
    public class WidgetDemoActivity extends Activity {
        /** Called when the activity is first created. */
        @Override
        public void onCreate(Bundle savedInstanceState){
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
        }
    }

其中onCreate()方法中的setContentView(R.layout.main)表明WidgetDemoActivity使用的用戶界面UI文件為main.xml。

雙擊main.xml文件,發現Eclipse為其提供了“Graphical Layout”和“main.xml”兩種瀏覽方式。其中“Graphical Layout”方式為以圖形方式瀏覽main.xml文件,其效果等同于main.xml在手機設備上運行的效果;“main.xml”方式為以代碼方式瀏覽main.xml文件。這兩種方式是等效的,都可以對main.xml文件進行編輯和查看。單擊“main.xml”標簽,發現Eclipse已經為其生成代碼如下:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="vertical">
       <TextView
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="@string/hello" />
    </LinearLayout>

該文件表明,當前main.xml文件所使用的布局為LinearLayout布局,該布局自動填滿整個手機屏幕。在該布局中,放置了一個TextView組件,該TextView顯示的內容為"@string/hello",表示string.xml文件中定義的hello變量的內容。雙擊values目錄下的string.xml文件,會發現hello變量對應的值為“Hello World, WidgetDemoActivity!”。

單擊main.xml的“Graphical Layout”瀏覽方式,可查看當前文件的圖形化效果,如圖4.13所示。

圖4.13 文件的圖形化效果

程序開發人員可以在該圖形方式下,將左側的各種組件直接拖動到屏幕上形成自己想要的布局,也可以直接修改main.xml文件的代碼。

在后續章節中,在對布局文件進行修改時,若非特殊情況將不再單獨描述。

4.4.2 按鈕(Button)

Button按鈕應該是用戶交互中使用最多的組件,在很多應用程序中都很常見。當用戶單擊按鈕的時候,會有相對應的響應動作。下面在WidgetDemo工程的主界面中main.xml中放置一個名為Button的按鈕。文件代碼如下:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="vertical">
       <TextView
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="@string/hello" />



       <Button
            android:id="@+id/button1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button" />



    </LinearLayout>

其中,

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button" />

表明在用戶界面上放置了一個id為“button1”的按鈕,按鈕的高度(layout_height)和寬度(layout_width)都會根據實際內容調整(wrap_content),按鈕上顯示文字為Button,其運行效果如圖4.14所示。

圖4.14 Button的應用界面

按鈕最重要的用戶交互事件是“單擊”事件。下面為Button1添加事件監聽器和相應的單擊事件。該過程在WidgetDemoActivity.java文件中完成,代碼如下:

    package introduction.android.widgetDemo;



    import android.app.Activity;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.Button;



    public class WidgetDemoActivity extends Activity {
        /** Called when the activity is first created. */
        @Override
        public void onCreate(Bundle savedInstanceState){
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
            Button btn=(Button)this.findViewById(R.id.button1);
            btn.setOnClickListener(new OnClickListener(){
                            @Override
                            public void onClick(View v){
                                    // TODO Auto-generated method stub
    setTitle("button1 被用戶點擊了");
                                    Log.i("widgetDemo", "button1 被用戶點擊了。");
                            }
            });
        }
    }

在WidgetDemoActivity的onCreate()方法中,通過findViewById(R.id.button1)方法獲得的Button1的對象,通過setOnClickListener()方法為Button1設置了監聽器。此處新建了一個實現了OnClickListener接口的匿名類作為監聽器,并實現了onClick()方法。當Button1被單擊,當前應用程序的標題被設置成“button1被用戶單擊了”,對應在LogCat中也會打印相應的字符串,運行結果如圖4.15所示。

圖4.15 單擊按鈕運行效果

4.4.3 文本框(TextView)

TextView是用于在界面上顯示文字的組件,其顯示的文本不可被用戶直接編輯。程序開發人員可以設置TextView字體大小、顏色、樣式等屬性。在工程WidgetDemo的main.xml中添加一個TextView,代碼如下:

    <TextView
            android:id="@+id/textView1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="TextView" />

運行效果如圖4.16所示。

圖4.16 TextView的應用界面

修改Button1的單擊事件為:

    public void onClick(View view){
                    // TODO Auto-generated method stub
                    //setTitle("button1 被用戶單擊了");
                    Log.i("widgetDemo", "button1 被用戶單擊了。");
    TextView textview=(TextView)findViewById(R.id.textView1);
                    textview.setText("設置TextView的字體");
                    textview.setTextColor(Color.RED);
                    textview.setTextSize(TypedValue.COMPLEX_UNIT_SP, 20);
    textview.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
    }

當Button1被單擊時,通過setText()方法更改textView的顯示內容為“設置TextView的字體”,通過setTextColor()方法修改textView顯示字體的顏色為紅色,通過setTextSize()方法修改textView顯示字體的大小為20sp,通過setTypeface()方法修改textView顯示字體的風格為加粗。

圖4.17 再次單擊按鈕運行效果

當然,該過程也可以通過修改main.xml文件來實現。將TextView標簽按照如下代碼修改也可得到同樣效果,但是失去了應用程序中與用戶交互的過程:

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="設置TextView的字體"
        android:textColor="#ff0000"
        android:textSize="20sp"
        android:textStyle="bold"/>

4.4.4 編輯框(EditText)

EditText是TextView的子類,在TextView的基礎上增加了文本編輯功能,用于處理用戶輸入,例如登錄框等,是非常常用的組件。

在工程WidgetDemo的main.xml文件中添加一個EditText,并實現如下功能:當用戶在EditText中輸入信息的同時,用一個TextView顯示用戶輸入的信息。

工程WidgetDemo中的布局文件main.xml中增加的代碼如下:

    <EditText
        android:id="@+id/editText1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

在WidgetDemoActivity的onCreate()方法中添加下列代碼:

    editText=(EditText)findViewById(R.id.editText1);
    editText.addTextChangedListener(new TextWatcher(){



    @Overridepublic void afterTextChanged(Editable s){
            // TODO Auto-generated method stub



    }



    @Overridepublic void beforeTextChanged(CharSequence s, int start, int count,
            int after){
            // TODO Auto-generated method stub



    }



    @Overridepublic void onTextChanged(CharSequence s, int start, int before,
            int count){
            // TODO Auto-generated method stub
            String text=editText.getText().toString();
            textview.setText(text);
    }



    });

運行結果如圖4.18所示。

圖4.18 EditText的應用界面

4.4.5 多項選擇按鈕(CheckBox)

多項選擇按鈕CheckBox屬于輸入型組件,該組件允許用戶一次選擇多個選項。當不方便用戶在手機屏幕上進行直接輸入操作時,該組件的使用顯得尤為便利。

下面通過實例講解CheckBox的使用方法。該實例運行效果如圖4.19所示。

圖4.19 CheckBox的應用界面

在工程WidgetDemo的布局文件main.xml文件中添加一個Button,代碼如下:

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="CheckBoxDemo" />

當該Button被用戶單擊時,啟動一個名為CheckBoxActivity的Activity,在該Activity中演示CheckBox的使用方法。啟動CheckBoxActivity的相關代碼如下:

    Button ckbtn=(Button)this.findViewById(R.id.button2);
    ckbtn.setOnClickListener(new OnClickListener(){



    @Override
    public void onClick(View v){
            // TODO Auto-generated method stub
            Intent intent=new Intent(WidgetDemoActivity.this,CheckBoxActivity.class);
            startActivity(intent);
    }
    });

同時在AndroidManifest.xml文件中聲明該Activity:

    <activity android:name="CheckBoxActivity"></activity>

CheckBoxActivity所使用的布局文件為checkbox.xml,使用LinearLayout布局,其中放置了一個TextView和三個CheckBox。Checkbox.xml的文件內容如下:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">



       <TextView
            android:id="@+id/text"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="@string/checkboxhello"/>
       <CheckBox
            android:id="@+id/CheckBox1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/football"/>
       <CheckBox
            android:id="@+id/CheckBox2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/song"/>
       <CheckBox
            android:id="@+id/CheckBox3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/book"/>



    </LinearLayout>

這四個組件在對應的strings.xml文件中定義的變量為:

    <string name="checkboxhello">你的愛好是:</string>
       <string name="football">籃球</string>
       <string name="song">聽歌曲</string>
    <string name="book">看書</string>

當用戶對多項選擇按鈕進行選擇時,為了確定用戶選擇的是哪幾項,需要對每個多項選擇按鈕進行監聽。CompouButton.OnCheckedChangedListener接口可用于對CheckBox的狀態進行監聽。當CheckBox的狀態在未被選中和被選中直接變化時,該接口的onCheckedChanged()方法會被系統調用。CheckBox通過setOnCheckedChangeListener()方法將該接口對象設置為自己的監聽器。

CheckBoxActivity.java代碼如下:

    package introduction.android.widgetDemo;



    import android.app.Activity;
    import android.os.Bundle;
    import android.widget.CheckBox;
    import android.widget.CompoundButton;
    import android.widget.TextView;



    public class CheckBoxActivity extends Activity {
    private TextView textView;
    private CheckBox bookCheckBox;
    private CheckBox songCheckBox;
    private CheckBox footbaCheckBox;
    @Override
    protected void onCreate(Bundle savedInstanceState){
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        this.setContentView(R.layout.checkbox);
        textView=(TextView)findViewById(R.id.text);
        footbaCheckBox=(CheckBox)findViewById(R.id.CheckBox1);
        songCheckBox=(CheckBox)findViewById(R.id.CheckBox2);
        bookCheckBox=(CheckBox)findViewById(R.id.CheckBox3);



        footbaCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener(){



        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked){
            // TODO Auto-generated method stub
            if(footbaCheckBox.isChecked()){
                textView.append(footbaCheckBox.getText().toString());
            }else {
                if(textView.getText().toString().contains("足球")){
                textView.setText(textView.getText().toString().replace("足球", ""));
                }
            }
            }
        });
        songCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener(){



            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked){
            // TODO Auto-generated method stub
            if(songCheckBox.isChecked()){
                textView.append(songCheckBox.getText().toString());
            }else {
                if(textView.getText().toString().contains("唱歌")){
                textView.setText(textView.getText().toString().replace("唱歌", ""));
                }
            }
            }
        });



        bookCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener(){



            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked){
            // TODO Auto-generated method stub
            if(bookCheckBox.isChecked()){
                textView.append(bookCheckBox.getText().toString());
            }else {
                if(textView.getText().toString().contains("讀書")){
                textView.setText(textView.getText().toString().replace("讀書", ""));
                }
            }
            }
        });
    }



    }

CheckBoxActivity為Checkbox.xml文件中的三個CheckBox分別添加了監聽器。當CheckBox的狀態發生改變時,通過Checkbox.isChecked()方法可以獲取當前CheckBox按鈕的選中狀態,進而進行處理。

4.4.6 單項選擇按鈕組(RadioGroup)

RadioGroup為單選按鈕組,其中可以包含多個RadioButton,即單選按鈕,它們共同為用戶提供一種多選一的選擇方式。在多個RadioButton被同一個RadioGroup包含的情況下,多個RadioButton之間自動形成互斥關系,僅有一個可以被選擇。單選按鈕的使用方法和CheckBox的使用方法高度相似,其事件監聽接口使用的是RadioGroup.OnCheckedChangeListener(),使用setOnCheckedChangeListener()方法將監聽器設置到單選按鈕上。按照CheckBox的講解思路,啟動一個名為RadioGroupActivity的Activity來對RadioGroup進行講解。

RadioGroupActivity運行效果如圖4.20所示。

圖4.20 RadioGroup的應用界面

在工程WidgetDemo的布局文件main.xml文件中添加一個Button,并啟動RadioGroupActivity的相關代碼。在main.xml中添加代碼如下:

    <Button
        android:id="@+id/button3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="RadioGroupDemo" />

啟動處理RadioGroup的Activity RadioGroupActivity的代碼如下:

    Button radiotn=(Button)this.findViewById(R.id.button3);
    radiotn.setOnClickListener(new OnClickListener(){



    @Override
    public void onClick(View v){
            // TODO Auto-generated method stub
            Intent intent=new Intent(WidgetDemoActivity.this,RadioGroupActivity.class);
            startActivity(intent);
    }
    });

同時在AndroidManifest.xml文件中聲明該Activity:

    <activity android:name=" RadioGroupActivity "></activity>

RadioGroupActivity使用的是radiogroup.xml,其代碼如下:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">



       <TextView
            android:id="@+id/radiohello"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="@string/hello"/>



       <RadioGroup
            android:id="@+id/radiogroup1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:layout_x="3px"
       >
           <RadioButton
                android:id="@+id/radiobutton1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/football"
            />
           <RadioButton
                android:id="@+id/radiobutton2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/bascketball"
            />
           <RadioButton
                android:id="@+id/radiobutton3"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/badminton"
            />
       </RadioGroup>



    </LinearLayout>

該布局文件使用了LinearLayout布局,并且在其中放置了一個TextView和一個RadioGroup。RadioGroup中含有三個RadioButton。這些組件對應的strings.xml文件中定義的變量為:

    <string name="radiohello">你最喜歡的運動是:</string>
       <string name="bascketball">籃球</string>
       <string name="badminton">羽毛球</string>
    <string name="football">足球</string>

RadioGroupActivity.java代碼如下:

    package introduction.android.widgetDemo;



    import android.app.Activity;
    import android.os.Bundle;
    import android.widget.RadioButton;
    import android.widget.RadioGroup;
    import android.widget.TextView;



    public class RadioGroupActivity extends Activity {
     private TextView textview;
     private RadioGroup radiogroup;
     private RadioButton radio1,radio2,radio3;
     @Override
     public void onCreate(Bundle savedInstanceState){
          super.onCreate(savedInstanceState);
          setContentView(R.layout.radiogroup);
          textview=(TextView)findViewById(R.id.radiohello);
          radiogroup=(RadioGroup)findViewById(R.id.radiogroup1);
          radio1=(RadioButton)findViewById(R.id.radiobutton1);
          radio2=(RadioButton)findViewById(R.id.radiobutton2);
          radio3=(RadioButton)findViewById(R.id.radiobutton3);
          radiogroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener(){



        @Override
        public void onCheckedChanged(RadioGroup group, int checkedId)
            {
            // TODO Auto-generated method stub
                String text="我最喜歡的運動是";
            if(checkedId==radio1.getId()){
                text+=radio1.getText().toString();
                textview.setText(text);
            }else if(checkedId==radio2.getId()){
                text+=radio2.getText().toString();
                textview.setText(text);
            }else if(checkedId==radio3.getId()){
                text+=radio3.getText().toString();
                textview.setText(text);
            }
            }
        });
    }
    }

在RadioGroupActivity的onCreate()方法中為RadioGroup添加監視器RadioGroup。OnCheckedChangeListener,在其回調方法onCheckedChanged()中對三個RadioButton分別進行處理。需要說明的是如果把RadioGroup去掉,只使用RadioButton的話,則需要為每個RadioButton單獨設置監聽器,其使用方法和CheckBox沒有任何區別。

4.4.7 下拉列表(Spinner)

Spinner提供下拉列表式的輸入方式,該方法可以有效節省手機屏幕上的顯示空間。

下面用一個簡單的實例講解Spinner的使用方法。在工程WidgetDemo的布局文件main.xml文件中添加一個Button,用以啟動SpinnerActivity。

在main.xml中添加代碼如下:

    <Button
            android:id="@+id/button4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="SpinnerDemo" />

單擊Button并啟動SpinnerActivity的代碼如下:

    Button spinnerbtn=(Button)this.findViewById(R.id.button4);
    spinnerbtn.setOnClickListener(new OnClickListener(){
     @Override
     public void onClick(View v){
            // TODO Auto-generated method stub
            Intent intent=new Intent(WidgetDemoActivity.this,SpinnerActivity.class);
            startActivity(intent);
    }
    });

同時在AndroidManifest.xml文件中聲明該Activity:

    <activity android:name=" SpinnerActivity "></activity>

SpinnerActivity的運行效果如圖4.21所示。

圖4.21 Spinner的應用界面

SpinnerActivity使用的布局文件為spiner.xml,其代碼如下:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
    <TextView
            android:id="@+id/textView1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="textview"/>
       <Spinner
            android:id="@+id/spinner1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />



    </LinearLayout>

SpinnerActivity.java文件代碼如下:

    package introduction.android.widgetDemo;



    import java.util.ArrayList;
    import java.util.List;
    import android.app.Activity;
    import android.os.Bundle;
    import android.view.MotionEvent;
    import android.view.View;
    import android.widget.AdapterView;
    import android.widget.ArrayAdapter;
    import android.widget.Spinner;
    import android.widget.TextView;



    public class SpinnerActivity extends Activity {
     private List<String>list=new ArrayList<String>();
     private TextView textview;
     private Spinner spinnertext;
     private ArrayAdapter<String>adapter;
     public void onCreate(Bundle savedInstanceState){
             super.onCreate(savedInstanceState);
             setContentView(R.layout.spiner);
             //第一步:定義下拉列表內容
             list.add("沈陽");
             list.add("天津");
             list.add("北京");
             list.add("上海");
             list.add("深圳");
             textview=(TextView)findViewById(R.id.textView1);
             spinnertext=(Spinner)findViewById(R.id.spinner1);
             //第二步:為下拉列表定義一個適配器
             adapter=new ArrayAdapter<String>(this,android.R.layout.simple_spinner_item, list);
             //第三步:設置下拉列表下拉時的菜單樣式。
             adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
             //第四步:將適配器添加到下拉列表上
             spinnertext.setAdapter(adapter);
             //第五步:添加監聽器,為下拉列表設置事件的響應
             spinnertext.setOnItemSelectedListener(new Spinner.OnItemSelectedListener(){
                 public void onItemSelected(AdapterView<?>arg0, View arg1, int arg2, long arg3){
                     // TODO Auto-generated method stub
                     /* 將所選spinnertext的值帶入myTextView 中*/
                 textview.setText("我來自:"+adapter.getItem(arg2));
                     /* 將spinnertext顯示*/
                     arg0.setVisibility(View.VISIBLE);
                 }
                 public void onNothingSelected(AdapterView<?>arg0){
                     // TODO Auto-generated method stub
                 textview.setText("NONE");
                     arg0.setVisibility(View.VISIBLE);
                 }
             });
             //將spinnertext添加到OnTouchListener 對內容選項觸屏事件處理
             spinnertext.setOnTouchListener(new Spinner.OnTouchListener(){
                  @Override
                  public boolean onTouch(View v, MotionEvent event){
                        // TODO Auto-generated method stub
                        // 將mySpinner 隱藏
                                v.setVisibility(View.INVISIBLE);
                                Log.i("spinner","Spinner Touch事件被觸發!");
                                return false;
                  }
             });
             //焦點改變事件處理
             spinnertext.setOnFocusChangeListener(new Spinner.OnFocusChangeListener(){
                 public void onFocusChange(View v, boolean hasFocus){
                     // TODO Auto-generated method stub
                     v.setVisibility(View.VISIBLE);
                     Log.i("spinner","Spinner FocusChange 事件被觸發!");
                 }
             });
      }
    }

SpinnerActivity通過五個步驟將Spinner初始化并進行事件處理。分別為:


●定義下拉列表的列表項內容List<String>。

●為下拉列表Spinner定義一個適配器ArrayAdapter<String>,并與列表項內容相關聯。

●使用ArrayAdapter.setDropDownViewResource()設置Spinner下拉列表在打開時的下拉菜單樣式。

●使用Spinner. setAdapter()將適配器數據與Spinner關聯起來。

●為Spinner添加事件監聽器,進行事件處理。


Spinner支持多種事件處理方式,本實例中對Spinner被單擊事件、焦點改變事件和Spinner的列表項被選中事件進行了處理。

在本實例中,SpinnerActivity在程序代碼中動態建立了下拉列表每一項的內容。除此之外,還可以在XML文件中定義Spinner的下拉列表項,步驟如下:

在res/values文件夾下新建cities.xml文件夾:

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
       <string-array name="city">
           <item>shenyang</item>
           <item>nanjing</item>
           <item>beijing</item>
           <item>tianjin</item>
       </string-array>
    </resources>

在SpinnerActivity.java中初始化Spinner:

    Spinner spinner=(Spinner)findViewById(R.id.spinner1);
    ArrayAdapter<CharSequence>adapter=ArrayAdapter.createFromResource(this, R.array.city, android.R.layout.simple_spinner_item);
    adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    spinner.setAdapter(adapter);

運行效果如圖4.22所示。

圖4.22 Spinner的事件處理

4.4.8 自動完成文本(AutoCompleteTextView)

在使用百度或者Google搜索信息時,只需要在搜索框中輸入幾個關鍵字,就會有很多相關的信息以列表形式被列舉出來供用戶選擇,這種效果在Android SDK中可以通過AutoCompleteTextView來實現。

下面用一個簡單的實例講解AutoCompleteTextView的使用方法。在工程WidgetDemo的布局文件main.xml中添加一個Button,用以啟動AutoCompleteTextViewActivity。

在main.xml中添加代碼如下:

    <Button
        android:id="@+id/button5"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="AutoCompleteTextViewDemo" />

單擊Button,并啟動AutoCompleteTextViewActivity的代碼如下:

    Button autobtn=(Button)this.findViewById(R.id.button5);
    autobtn.setOnClickListener(new OnClickListener(){
     @Override
     public void onClick(View v){
            // TODO Auto-generated method stub
            Intent intent=new Intent(WidgetDemoActivity.this,AutoCompleteTextViewActivity.class);
            startActivity(intent);
     }
    });

同時在AndroidManifest.xml文件中聲明該Activity:

    <activity android:name=" AutoCompleteTextViewActivity"></activity>

AutoCompleteTextViewActivity運行效果如圖4.23所示。

圖4.23 AutoCompleteTextViewActivity運行效果

AutoCompleteTextViewActivity使用的布局文件為autocompletetextview.xml,其具體內容如下:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
     <TextView
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="AutoCompleteTextView演示:" />



       <AutoCompleteTextView
            android:id="@+id/autoCompleteTextView1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="">
           <requestFocus />
       </AutoCompleteTextView>



    </LinearLayout>

AutoCompleteTextViewActivity.java代碼如下:

    package introduction.android.widgetDemo;



    import android.app.Activity;
    import android.os.Bundle;
    import android.widget.ArrayAdapter;
    import android.widget.AutoCompleteTextView;



    public class AutoCompleteTextViewActivity extends Activity {
     private AutoCompleteTextView textView;
        private static final String[] autotext=new String[] {"hello","hello World","hello Android"};
        @Override
        public void onCreate(Bundle savedInstanceState){
            super.onCreate(savedInstanceState);
            setContentView(R.layout.autocompletetextview);
            textView=(AutoCompleteTextView )findViewById(R.id.autoCompleteTextView1);
            /*new ArrayAdapterd對象將autotext字符串數組傳入*/
            ArrayAdapter<String>adapter=new ArrayAdapter<String>(this,android.R.layout.simple_dropdown_item_1line,autotext);
            /*將ArrayAdapter添加到AutoCompleteTextView中*/
            textView.setAdapter(adapter);
        }
    }

AutoCompleteTextViewActivity中為可自動補全的內容建立對應字符串數組autotext,然后將該數組關聯到ArrayAdapter中,然后將ArrayAdapter與AutoCompleteTextView相關聯,進而實現自動完成文本功能。

AutoCompleteTextView提供一系列屬性對顯示效果進行設置,例如:


●completionThreshold:它的值決定了你在AutoCompleteTextView至少輸入幾個字符,它才會具有自動提示的功能。另外默認最多提示20條。

●dropDownAnchor:它的值是一個View的ID,指定后,AutoCompleteTextView會在這個View下彈出自動提示。

●dropDownSelector:設置自動提示項中當前選中項的背景色。

●dropDownWidth:設置自動提示列表的寬度。

4.4.9 日期選擇器和時間選擇器(DatePicker和TimePicker)

Android SDK提供了DatePicker和TimePicker組件,分別對日期和時間進行選擇,方便日期和時間設定。

下面用一個簡單的實例講解DatePicker和TimePicker組件的使用方法。在工程WidgetDemo的布局文件main.xml中添加一個名為“Date/Time”的Button,用以啟動TimeActivity。

在main.xml中添加代碼如下:

    <Button
        android:id="@+id/button6"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text=" Date/Time " />

單擊Button并啟動TimeActivity的代碼如下:

    Button timebtn=(Button)this.findViewById(R.id.button6);
            timebtn.setOnClickListener(new OnClickListener(){
                @Override
                public void onClick(View v){
                    // TODO Auto-generated method stub
                    Intent intent=new Intent(WidgetDemoActivity.this,TimeActivity.class);
                    startActivity(intent);
                }
            });

同時在AndroidManifest.xml文件中聲明該Activity:

    <activity android:name=" TimeActivity"></activity>

TimeActivity運行效果如圖4.24所示。

圖4.24 TimeActivity運行效果

TimeActivity使用的布局文件為time.xml,其內容如下:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
         <TextView
            android:id="@+id/timeview"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="DatePicker和TimePicker演示" />
    <TimePicker
            android:id="@+id/timepicker"
            android:layout_width="wrap_content"
            android:layout_height="116dp"
            android:background="#778888" />
    <!-- 設置背景色為墨綠 -->
     <DatePicker
            android:id="@+id/datepicker"
            android:layout_width="271dp"
            android:layout_height="196dp"
            android:background="#778899" />
    </LinearLayout>

TimeActivity.java的代碼如下:

    package introduction.android.widgetDemo;
     import java.util.Calendar;
     import android.app.Activity;import android.os.Bundle;import android.widget.DatePicker;import android.widget.TextView;import android.widget.TimePicker;
     public class TimeActivity extends Activity {
     private TextView textview;
        private TimePicker timepicker;
        private DatePicker datepicker;
        /* 聲明日期及時間變量 */
        private int year;
        private int month;
        private int day;
        private int hour;
        private int minute;



        @Override
        public void onCreate(Bundle savedInstanceState){
     super.onCreate(savedInstanceState);
     setContentView(R.layout.time);
     /* 獲取當前日期及時間 */
     Calendar calendar=Calendar.getInstance();
     year=calendar.get(Calendar.YEAR);
     month=calendar.get(Calendar.MONTH);
     day=calendar.get(Calendar.DAY_OF_MONTH);
     hour=calendar.get(Calendar.HOUR);
     minute=calendar.get(Calendar.MINUTE);
     datepicker=(DatePicker)findViewById(R.id.datepicker);
     timepicker=(TimePicker)findViewById(R.id.timepicker);
     /* 設置TextView對象,顯示初始日期時間 */
     textview=(TextView)findViewById(R.id.timeview);
     textview.setText(new StringBuilder().append(year).append("/")
            .append(format(month+1)).append("/").append(format(day))
            .append("  ").append(format(hour)).append(":")
            .append(format(minute)));
     /* 設置OnDateChangedListener()*/
     datepicker.init(year, month, day,
            new DatePicker.OnDateChangedListener(){
                @Override
                public void onDateChanged(DatePicker view, int year,
                    int monthOfYear, int dayOfMonth){
                // TODO Auto-generated method stub
                TimeActivity.this.year=year;
                month=monthOfYear;
                day=dayOfMonth;
                textview.setText(new StringBuilder().append(year)
                    .append("/").append(format(month+1))
                    .append("/").append(format(day)).append("  ")
                    .append(format(hour)).append(":")
                    .append(format(minute)));
                }
            });
        timepicker.setOnTimeChangedListener(new TimePicker.OnTimeChangedListener()
            {



                @Override
                public void onTimeChanged(TimePicker view, int hourOfDay, int minute)
                {
                    // TODO Auto-generated method stub
                    hour=hourOfDay;
                    TimeActivity.this.minute=minute;
                    textview.setText(new StringBuilder().append(year)
                .append("/").append(format(month+1))
                .append("/").append(format(day)).append("  ")
                .append(format(hour)).append(":")
                .append(format(minute)));
                }
            });



        }



        private String format(int time){
    String str=""+time;if(str.length()==1)
        str="0"+str;return str;
        }
    }

TimeActivity中使用java.util.Calendar對象獲取當前系統時間。當更改DatePicker組件中的日期時,會觸發DatePicker的OnDateChange()事件;當修改TimePacker的時間時,會觸發TimePacker的OnDateChange()事件。

由本實例可見,DatePicker實現OnDateChangedListener監聽器的方法與TimePicker實現setOnTimeChangedListener監聽器的方法有所類似。DatePicker用init()方法設定年、月、日的同時設定監聽器,而TimePicker使用setOnTimeChangedListener()直接設定。

4.4.10 進度條(ProgressBar)

當應用程序在后臺運行時,可以使用進度條反饋給用戶當前的進度信息。進度條被用以顯示當前應用程序運行狀況,功能完成多少等情況。Android SDK提供兩種樣式的進度條,一種是圓形的進度條,另一種是水平進度條。其中圓形進度條分大、中、小三種。

進度條本質上是一個整數,顯示當前的整數值在特定范圍內的比重。下面用一個簡單的實例講解ProgressBar組件的使用方法。

在工程WidgetDemo的布局文件main.xml中添加一個名為ProgressBarDemo的Button,用以啟動ProcessBarActivity。

在main.xml中添加代碼如下:

    <Button
        android:id="@+id/button7"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="ProgressBarDemo" />

單擊Button并啟動ProcessBarActivity的代碼如下:

    Button processbtn=(Button)this.findViewById(R.id.button7);
            processbtn.setOnClickListener(new OnClickListener(){
                @Override
                public void onClick(View v){
                    // TODO Auto-generated method stub
                    Intent intent=new Intent(WidgetDemoActivity.this,ProcessBarActivity.class);
                    startActivity(intent);
                }
            });

同時在AndroidManifest.xml文件中聲明該Activity:

    <activity android:name="ProcessBarActivity"></activity>

ProcessBarActivity運行效果如圖4.25所示。

圖4.25 ProcessBarActivity運行效果

ProcessBarActivity使用的布局文件為processbar.xml,其內容如下:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
    <ProgressBar
            android:id="@+id/progressBar1"
            style="?android:attr/progressBarStyleSmall"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />



       <ProgressBar
            android:id="@+id/progressBar2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />



       <ProgressBar
            android:id="@+id/progressBar3"
            style="?android:attr/progressBarStyleLarge"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />






       <ProgressBar
            android:id="@+id/progressBar4"
            style="?android:attr/progressBarStyleHorizontal"
            android:layout_width="209dp"
            android:layout_height="30dp"
            android:max="100"/>



    </LinearLayout>

該布局中放置了小、中、大三種類型的圓形進度條各一個,以及一個水平放置的條形進度條。一般情況下,開發人員不會為圓形進度條指定進度,圓形進度條只是展示運行效果,而不反映實際的進度。水平進度條則不同,開發人員會為條形進度條指定最大值,以及進度條當前值的獲取方法。在本實例中,條形進度條的最大值為100。

ProcessBarActivity.java代碼如下:

    package introduction.android.widgetDemo;
     import android.app.Activity;import android.os.Bundle;import android.os.Handler;import android.widget.ProgressBar;
     public class ProcessBarActivity extends Activity {
        ProgressBar progressBar;
        int i=0;
        int progressBarMax=0;
        /* 創建Handler對象 */
        Handler handler=new Handler();



        @Override
        public void onCreate(Bundle savedInstanceState){
            super.onCreate(savedInstanceState);
            setContentView(R.layout.processbar);
            progressBar=(ProgressBar)findViewById(R.id.progressBar4);
            /* 獲取最大值 */
            progressBarMax=progressBar.getMax();
            /* 匿名內部類啟動實現效果的線程 */
            new Thread(new Runnable(){
                @Override
                public void run(){
                    while(i++<progressBarMax){
                        // 設置滾動條當前狀態值
                        progressBar.setProgress(i);
                        try {
                            Thread.sleep(15);



                        } catch(Exception e){
                            e.printStackTrace();
                        }
                    }
                }
            }).start();
        }
    }

ProcessBarActivity對水平進度條進行了處理。先獲取了水平進度條的最大值,然后啟動了一個線程,由該線程來控制進度條的值,從0開始,每隔15毫秒增加1。

4.4.11 滾動視圖(ScrollView)

當Activity提供的用戶界面上有很多內容,以致當前手機屏幕不能完全顯示全部內容時,就需要滾動視圖來幫助瀏覽全部的內容。

以工程WidgetDemo為例,由于在講述過程中不斷地在main.xml文件中添加按鈕和其他組件,目前已經不能顯示全部內容,效果如圖4.26所示。

圖4.26 添加大量組件后的效果

這時候就需要使用ScrollView,即將當前的Activity的視圖轉化為滾動視圖,以便于瀏覽。ScrollView的使用非常方便,只需在main.xml的<LinearLayout>標簽外面加上ScrollView組件的聲明即可。布局文件main.xml的內容如下:

    <ScrollView
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent">
       <LinearLayout>....</LinearLayout>
    </ScrollView>

添加ScrollView后,main.xml布局的運行效果如圖4.27所示。

圖4.27 ScrollView的運行效果

4.4.12 拖動條(SeekBar)

SeekBar是水平進度條ProgressBar的間接子類,相當于一個可以拖動的水平進度條。下面仍以一個簡單的實例講解SeekBar組件的使用方法。

在工程WidgetDemo的布局文件main.xml中添加一個名為“SeekBarDemo”的Button,用以啟動SeekBarActivity。

在main.xml中添加代碼如下:

    <Button
        android:id="@+id/button8"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="SeekBarDemo" />

單擊Button并啟動SeekBarActivity的代碼如下:

    Button processbtn=(Button)this.findViewById(R.id.button8);
    processbtn.setOnClickListener(new OnClickListener(){
        @Override
        public void onClick(View v){
            // TODO Auto-generated method stub
            Intent intent=new Intent(WidgetDemoActivity.this, SeekBarActivity.class);
            startActivity(intent);
        }
    });

同時在AndroidManifest.xml文件中聲明該Activity:

    <activity android:name="SeekBarActivity"></activity>

SeekBarActivity運行效果如圖4.28所示。

圖4.28 SeekBarActivity運行效果

SeekBarActivity使用的布局文件為seekbar.xml,其內容如下:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">



       <TextView
            android:id="@+id/textView1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="TextView" />



       <SeekBar
            android:id="@+id/seekBar1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
    android:max="100"/>



    </LinearLayout>

該文件確定SeekBar對象的最大值為100,寬度為手機屏幕的寬度。

SeekBarActivity.java的代碼如下:

    package introduction.android.widgetDemo;
     import android.app.Activity;import android.os.Bundle;import android.util.Log;import android.widget.SeekBar;import android.widget.TextView;
     public class SeekBarActivity extends Activity {
        private TextView textView;
        private SeekBar seekBar;
        @Override
        public void onCreate(Bundle savedInstanceState){
            super.onCreate(savedInstanceState);
            setContentView(R.layout.seekbar);
            textView=(TextView)findViewById(R.id.textView1);
            seekBar=(SeekBar)findViewById(R.id.seekBar1);
            /* 設置SeekBar監聽setOnSeekBarChangeListener */
            seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener(){
                /* 拖動條停止拖動的時調用 */
                @Override
                public void onStopTrackingTouch(SeekBar seekBar){
                    Log.i("SeekBarActivity", "拖動停止");
                }
                /* 拖動條開始拖動的時調用 */
                @Override
                public void onStartTrackingTouch(SeekBar seekBar){
                    Log.i("SeekBarActivity", "開始拖動");
                }
                /* 拖動條進度改變的時調用 */
                @Override
                public void onProgressChanged(SeekBar seekBar, int progress,
                    boolean fromUser){
                    /* 拖動條進度改變的時調用 */
                    textView.setText("當前進度為:"+progress+"%");
                }
            });
        }
    }

SeekBar的事件處理接口為OnSeekBarChangeListener,該監聽器提供對三種事件的監聽,分別為當SeekBar的拖動條開始被拖動時、拖動條拖動停止時和拖動條的位置發生改變時。SeekBarActivity在拖動條開始被拖動和拖動停止時,會通過Logcat打印相關信息。當拖動條位置發生改變時,將當前的數值顯示到TextView中。

4.4.13 評價條(RatingBar)

在網上購物的時候,經常會對所購買商品進行打分的情況。一般對商品的評價和打分是以五顆星的方式進行的。Android SDK提供了RatingBar這個組件來實現該功能。

RatingBar是SeekBar和ProgressBar的擴展,是ProgressBar的間接子類,可以使用ProgressBar相關的屬性。RatingBar有三種風格分別為:默認風格(ratingBarStyle)、小風格(ratingBarStyleSmall)、大風格(ratingBarStyleIndicator)。其中,默認風格的RatingBar是我們通常使用的,可以進行交互,而其他兩種不能進行交互。

以一個簡單的實例講解RatingBar組件的使用方法。在工程WidgetDemo的布局文件main.xml中添加一個名為“RatingBarrDemo”的Button,用以啟動RatingBarActivity。

在main.xml中添加代碼如下:

    <Button
         android:id="@+id/button9"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:text="RatingBarDemo" />

單擊Button并啟動RatingBarActivity的代碼如下:

    Button ratingbarbtn=(Button)this.findViewById(R.id.button9);
    ratingbarbtn.setOnClickListener(new OnClickListener(){
        @Override
        public void onClick(View v){
            // TODO Auto-generated method stub
            Intent intent=new Intent(WidgetDemoActivity.this,RatingBarActivity.class);
            startActivity(intent);
        }
    });

同時在AndroidManifest.xml文件中聲明該Activity:

    <activity android:name="RatingBarActivity"></activity>

RatingBarActivity運行效果如圖4.29所示。

圖4.29 RatingBarActivity運行效果

RatingBarActivity使用的布局文件ratingbar.xml內容如下:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">



       <TextView
            android:id="@+id/textView1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="TextView" />



       <RatingBar
            android:id="@+id/ratingBar1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:numStars="5"
            android:stepSize="0.5"
            android:rating="3"/>



    </LinearLayout>

該布局文件使用LinearLayout布局,其中放置了一個TextView和一個RatingBar,并對RatingBar的相關屬性進行了設置。android:numStars="5"用于設置RatingBar顯示的星星數量為5顆;android:stepSize="0.5"用于設置RatingBar的最小變化單位為半顆星星;android:rating ="3"表示RatingBar在初始狀態下被選中的星星數量為3顆。

RatingBarActivity.java代碼如下:

    package introduction.android.widgetDemo;



    import android.app.Activity;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.View.OnTouchListener;
    import android.widget.RatingBar;
    import android.widget.RatingBar.OnRatingBarChangeListener;
    import android.widget.TextView;
    import android.widget.Toast;



    public class RatingBarActivity extends Activity {
        private RatingBar chooseRatingBar;
        private TextView textView;
        @Override
        public void onCreate(Bundle savedInstanceState){
            super.onCreate(savedInstanceState);
            setContentView(R.layout.ratingbar);
            textView=(TextView)findViewById(R.id.textView1);
            chooseRatingBar=(RatingBar)findViewById(R.id.ratingBar1);



                /*創建RatingBar監聽器 */
            chooseRatingBar.setOnRatingBarChangeListener(new
    OnRatingBarChangeListener(){



                      @Override
                public void onRatingChanged(RatingBar ratingBar,float rating, boolean fromUser){
                    chooseRatingBar=(RatingBar)findViewById(R.id.ratingBar1);
                    chooseRatingBar.setRating(rating);
                    textView.setText("您選擇了"+rating+"個星星");
                }
            });
        }
    }

RatingBarActivity為RatingBar對象設置了OnRatingBarChangeListener監聽器,當用戶單擊RatingBar引起被選中星星數量的變化時,該接口會監測到該事件,并且調用onRatingChanged()方法,更新TextView顯示的內容。

onRatingChanged()的三個參數所對應的含義為:


●ratingBar:多個RatingBar可以同時指定同一個RatingBar監聽器。該參數就是當前觸發RatingBar監聽器的那一個RatingBar對象。

●rating:當前評級分數。取值范圍從0到RatingBar的總星星數。

●fromUser:如果觸發監聽器的是來自用戶觸屏點擊或軌跡球左右移動,則為true。

4.4.14 圖片視圖(ImageView)和圖片按鈕(ImageButton)

ImageView是用于顯示圖片的組件,在很多場合都有比較普遍的使用。ImageView可以顯示任意圖像,加載各種來源的圖片(如資源或圖片庫)。ImageView可以計算圖片的尺寸以便在任意的布局中使用,并且可以提供縮放或者著色等選項供開發者使用。

ImageButton是ImageView的子類,相當于一個表明是圖片而不是文字的Button。其使用方法和Button完全相同。

下面通過一個實例來了解一下這兩個組件的使用方法。在工程WidgetDemo的布局文件main.xml中添加一個名為ImageButtonDemo的Button,用以啟動ImageButtonActivity。

在main.xml中添加代碼如下:

    <Button
            android:id="@+id/button10"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="ImageButtonDemo" />

單擊Button并啟動RatingBarActivity的代碼如下:

    Button imgbtn=(Button)this.findViewById(R.id.button10);
    imgbtn.setOnClickListener(new OnClickListener(){
        @Override
        public void onClick(View v){
            // TODO Auto-generated method stub
            Intent intent=new Intent(WidgetDemoActivity.this,ImageButtonActivity.class);
            startActivity(intent);
        }
    });

同時在AndroidManifest.xml文件中聲明該Activity:

    <activity android:name="ImageButtonActivity"></activity>

ImageButtonActivity運行效果如圖4.30所示。

圖4.30 ImageButtonActivity運行效果

ImageButtonActivity的布局文件imgbtn.xml內容如下:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">



       <ImageView
            android:id="@+id/imageView1"
            android:layout_width="250dp"
            android:layout_height="250dp"
            android:src="@drawable/girl" />



       <ImageButton
            android:id="@+id/imageButton1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/ic_launcher" />



    </LinearLayout>

該文件使用LinearLayout布局,其中放入了一個ImageView組件,一個ImageButton組件。兩個組件都通過android:src屬性指定了顯示的圖片。該實例用到了兩個圖片資源,一個為girl,一個為ic_launcher。由于Android會根據手機設備的配置高低選擇不同的資源,因此為了應用程序的通用性,在三個drawable文件夾下,都放置了girl.gif圖像。ic_launcher.png是系統自帶的資源文件。

圖4.31 工程中的圖片資源

ImageButtonActivity.java代碼如下:

    package introduction.android.widgetDemo;import android.app.Activity;import android.os.Bundle;import android.view.View;import android.view.ViewGroup.LayoutParams;import android.widget.ImageButton;import android.widget.ImageView;public class ImageButtonActivity extends Activity {
        private ImageButton imgbtn;
        private ImageView imgview;
        @Override
        protected void onCreate(Bundle savedInstanceState){
            // TODO Auto-generated method stub
            super.onCreate(savedInstanceState);
            setContentView(R.layout.imgbtn);
            imgbtn=(ImageButton)this.findViewById(R.id.imageButton1);
            imgview=(ImageView)this.findViewById(R.id.imageView1);
            imgbtn.setOnClickListener(new View.OnClickListener(){
                @Override
                public void onClick(View v){
                    // TODO Auto-generated method stub
                    LayoutParams params=imgview.getLayoutParams();
                    params.height+=3;
                    params.width+=3;
                    imgview.setLayoutParams(params);
                }
            });
        }
    }

ImageButtonActivity為ImageButton添加了單擊監聽器,對用戶單擊imgbtn的事件進行了處理。每次用戶單擊圖片按鈕,都把ImageView組件的寬和高增大3。隨著用戶的不斷單擊,ImageView中顯示的圖片越來越大,顯示了ImageView組件對圖片的縮放功能。

4.4.15 圖片切換器ImageSwitcher和圖庫Gallery

在使用Android手機設置壁紙的時候,會看到屏幕底部有很多可以滾動的圖片,當單擊某一圖片時,在其上面的空間會顯示當前選中的圖片,此時我們用到的就是Gallery和ImageSwitcher。

Gallery組件用于橫向顯示圖像列表,并且自動將當前圖像放置到中間位置。ImageSwitcher則像是圖片瀏覽器,可以切換圖片,通過它可以制作簡單的幻燈片等等。通常將這兩個類結合在一起使用,可以制作有一定效果的相冊。

下面通過一個實例來了解一下這兩個組件的使用方法。

在工程WidgetDemo的布局文件main.xml中添加一個名為GalleryDemo的Button,用以啟動GalleryActivity。在main.xml中添加代碼如下:

    <Button
        android:id="@+id/button11"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="GalleryDemo" />

單擊Button并啟動GalleryActivity的代碼如下:

    Button gallerybtn=(Button)this.findViewById(R.id.button11);
    gallerybtn.setOnClickListener(new OnClickListener(){
        @Override
        public void onClick(View v){
            // TODO Auto-generated method stub
            Intent intent=new Intent(WidgetDemoActivity.this,GalleryActivity.class);
                startActivity(intent);
            }
    });

同時在AndroidManifest.xml文件中聲明該Activity:

    <activity android:name="GalleryActivity"></activity>

GalleryActivity運行效果如圖4.32所示。

圖4.32 GalleryActivity運行效果

GalleryActivity使用的布局文件為gallery.xml,內容如下:

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="vertical">
       <ImageSwitcher
            android:id="@+id/switcher"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_alignParentTop="true"
            android:layout_alignParentLeft="true">
       </ImageSwitcher>
    <Gallery
         android:id="@+id/gallery"
         android:background="#333333"
         android:layout_width="fill_parent"
         android:layout_height="60dp"
         android:layout_alignParentBottom="true"
         android:layout_alignParentLeft="true"
         android:gravity="center_vertical"
         android:spacing="16dp" />
    </RelativeLayout>

該布局文件使用的是相對布局,通過android:layout_alignParentTop="true"這個屬性將ImageSwitcher放置于視圖的頂端,其頂部與其父組件的頂部對齊,同時使用android:layout_alignParentLeft="true"這個屬性使ImageSwitcher的左邊緣與其父組件的左邊緣對齊。在設置Gallery組件時,將其與屏幕的左下角對其,android:layout_alignParentBottom="true"是將該組件的底部與其父組件的底部對齊,并且使用android:spacing="16dp"屬性設置了圖片之間的間距。

GalleryActivity.java代碼如下:

    package introduction.android.widgetDemo;
     import android.app.Activity;import android.content.Context;import android.os.Bundle;import android.view.View;import android.view.ViewGroup;import android.view.ViewGroup.LayoutParams;import android.view.animation.AnimationUtils;import android.widget.AdapterView;import android.widget.AdapterView.OnItemSelectedListener;import android.widget.BaseAdapter;import android.widget.Gallery;import android.widget.ImageSwitcher;import android.widget.ImageView;import android.widget.ViewSwitcher.ViewFactory;
     public class GalleryActivity extends Activity {
        private Gallery gallery;
        private ImageSwitcher imageSwitcher;
        private int[] resids=new int[] {
              R.drawable.sample_0, R.drawable.sample_1,
                R.drawable.sample_2, R.drawable.sample_3,
                R.drawable.sample_4, R.drawable.sample_5,
                R.drawable.sample_6, R.drawable.sample_7};
        @Override
        public void onCreate(Bundle savedInstanceState){
            super.onCreate(savedInstanceState);
            setContentView(R.layout.gallery);
            /* 加載Gallery和ImageSwitcher */
            gallery=(Gallery)findViewById(R.id.gallery);
            imageSwitcher=(ImageSwitcher)findViewById(R.id.switcher);
            /* 創建用于描述圖像數據的ImageAdapter對象 */
            ImageAdapter imageAdapter=new ImageAdapter(this);
            /* 設置Gallery組件的Adapter對象 */
            gallery.setAdapter(imageAdapter);
            /* 添加Gallery監聽器 */
            gallery.setOnItemSelectedListener(new OnItemSelectedListener(){



                @Override
                public void onItemSelected(AdapterView<?>parent, View view,
                        int position, long id){
                    // TODO Auto-generated method stub
                    // 當選取Grallery上的圖片時,在ImageSwitcher組件中顯示該圖像
                    imageSwitcher.setImageResource(resids[position]);
                }



                @Override
                public void onNothingSelected(AdapterView<?>arg0){
                    // TODO Auto-generated method stub
                }



            });
            /* 設置ImageSwitcher組件的工廠對象 */
            imageSwitcher.setFactory(new ViewFactory(){
                /* ImageSwitcher用這個方法來創建一個View對象去顯示圖片 */
                @Override
                public View makeView(){
                    // TODO Auto-generated method stub
                    ImageView imageView=new ImageView(GalleryActivity.this);
                    /* setScaleType可以設置當圖片大小和容器大小不匹配時的剪輯模式 */
                    imageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
                    imageView.setLayoutParams(new ImageSwitcher.LayoutParams(
                            LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
                    return imageView;
                }



            });
            /* 設置ImageSwitcher組件顯示圖像的動畫效果 */
            imageSwitcher.setInAnimation(AnimationUtils.loadAnimation(this,
                    android.R.anim.fade_in));
            imageSwitcher.setOutAnimation(AnimationUtils.loadAnimation(this,
                    android.R.anim.fade_out));
        }



        public class ImageAdapter extends BaseAdapter {
            /* 定義Context */
            private Context mContext;



            /* 聲明ImageAdapter */
            public ImageAdapter(Context context){
                mContext=context;
            }



            @Override
            /* 獲取圖片的個數 */
            public int getCount(){
                // TODO Auto-generated method stub
                return resids.length;
            }



            /* 獲取圖片在庫中的位置 */
            @Override
            public Object getItem(int position){
                // TODO Auto-generated method stub
                return position;
            }



            /* 獲取圖片ID */
            @Override
            public long getItemId(int position){
                // TODO Auto-generated method stub
                return position;
            }



            /* 返回具體位置的ImageView對象 */
            @Override
            public View getView(int position, View convertView, ViewGroup parent){
                ImageView imageview=new ImageView(mContext);
                /* 給ImageView設置資源 */
                imageview.setImageResource(resids[position]);
                /* 設置 圖片布局大小為100*100 */
                imageview.setLayoutParams(new Gallery.LayoutParams(100, 100));
                /* 設置顯示比例類型 */
                imageview.setScaleType(ImageView.ScaleType.FIT_XY);
                return imageview;
            }
        }
    }

Gallery要顯示的圖片來自資源文件。把需要顯示的圖片放在/res/drawable目錄下后,將這些圖片的ID保存在一個int數組中以備使用。相關代碼如下:

    private int[] resids=new int[] {
        R.drawable.sample_0, R.drawable.sample_1,
          R.drawable.sample_2, R.drawable.sample_3,
          R.drawable.sample_4, R.drawable.sample_5,
          R.drawable.sample_6, R.drawable.sample_7};

Gallery通過setAdapter(imageAdapter)方法將組件和要顯示的圖片關聯起來。本實例中為Gallery設定的適配器為ImageAdapter,主要用于描述圖像信息,其為android.widget. BaseAdapter的子類。

在ImageAdapter類中有兩個方法值得我們注意,其中一個是getCount()方法,它用于返回圖片的總數,通常使用獲取存放圖片數組長度的方法獲取圖片總數,也可以規定具體的返回數,但不能超過實際圖片數量;getView()方法是當Gallery中需要顯示某一個圖像時,將當前圖片的索引,也就是position的值傳入,從resids數組中獲得相應的圖片的ID。

GalleryActivity為添加Gallery監聽器,處理了用戶單擊Gallery中圖片的事件,并設置ImageSwitcher相關屬性。其中代碼如下:

    imageSwitcher.setInAnimation(AnimationUtils.loadAnimation(this,
                    android.R.anim.fade_in));



    imageSwitcher.setOutAnimation(AnimationUtils.loadAnimation(this,
                    android.R.anim.fade_out));

設置了ImageSwitcher組件圖片切換時的漸入和漸出效果。

4.4.16 網格視圖(GridView)

GridView提供了一個二維的可滾動的網格,按照行列的方式來顯示內容,一般適合顯示圖標、圖片等,適合瀏覽。

下面通過一個實例來了解一下GridView組件的使用方法。在工程WidgetDemo的布局文件main.xml中添加一個名為GridViewDemo的Button,用以啟動GridViewActivity。

在main.xml中添加代碼如下:

    <Button
        android:id="@+id/button12"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="GridViewDemo" />

單擊Button并啟動GridViewActivity的代碼如下:

    Button gridviewbtn=(Button)this.findViewById(R.id.button12);
    gridviewbtn.setOnClickListener(new OnClickListener(){
        @Override
        public void onClick(View v){
            // TODO Auto-generated method stub
            Intent intent=new Intent(WidgetDemoActivity.this,GridViewActivity.class);
                    startActivity(intent);
        }
    });

同時在AndroidManifest.xml文件中聲明該Activity:

    <activity android:name="GridViewActivity"></activity>

GridViewActivity運行效果如圖4.33所示。

圖4.33 GridViewActivity運行效果

GridViewActivity使用的布局文件為gridview.xml,其內容如下:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">



       <GridView
            android:id="@+id/gridView1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:numColumns="3">
       </GridView>



    </LinearLayout>

該視圖采用了LinearLayout的布局方式,其中放置了一個GridView組件,該組件由三列組成。

GridViewActivity.java代碼如下:

    package introduction.android.widgetDemo;
     import android.app.Activity;import android.content.Context;import android.os.Bundle;import android.util.Log;import android.view.View;import android.view.ViewGroup;import android.widget.AdapterView;import android.widget.AdapterView.OnItemClickListener;import android.widget.BaseAdapter;import android.widget.GridView;import android.widget.ImageView;
     public class GridViewActivity extends Activity {
        public void onCreate(Bundle savedInstanceState){
            super.onCreate(savedInstanceState);
            setContentView(R.layout.gridview);



            GridView gridview=(GridView)findViewById(R.id.gridView1);
            gridview.setAdapter(new ImageAdapter(this));



            gridview.setOnItemClickListener(new OnItemClickListener(){
                public void onItemClick(AdapterView<?>parent, View v,
                        int position, long id){
                    Log.i("gridview", "這是第"+position+"幅圖像。");
                }
            });
        }



        public class ImageAdapter extends BaseAdapter {
            private Context mContext;



            public ImageAdapter(Context c){
                mContext=c;
            }



            /* 獲取當前圖片數量 */
            @Override
            public int getCount(){
                return mThumbIds.length;
            }



            /* 根據需要position獲得在GridView中的對象 */
            @Override
            public Object getItem(int position){
                return position;
            }



            /* 獲得在GridView中對象的ID */
            @Override
            public long getItemId(int id){
                return id;
            }



            @Override
            public View getView(int position, View convertView, ViewGroup parent){
                ImageView imageView;
                if(convertView==null){
                    /* 實例化ImageView對象 */
                    imageView=new ImageView(mContext);
                    /* 設置ImageView對象布局 ,設置View的height和width */
                    imageView.setLayoutParams(new GridView.LayoutParams(85, 85));
                    /* 設置邊界對齊 */
                    imageView.setAdjustViewBounds(false);
                    /* 按比例統一縮放圖片(保持圖片的尺寸比例)*/
                    imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
                    /* 設置間距 */
                    imageView.setPadding(8, 8, 8, 8);
                } else {
                    imageView=(ImageView)convertView;
                }
                imageView.setImageResource(mThumbIds[position]);
                return imageView;
            }
        }



        // references to our images
        private Integer[] mThumbIds={ R.drawable.sample_2, R.drawable.sample_3,
                R.drawable.sample_4, R.drawable.sample_5, R.drawable.sample_6,
                R.drawable.sample_7, R.drawable.sample_0, R.drawable.sample_1,
                R.drawable.sample_2, R.drawable.sample_3, R.drawable.sample_4,
                R.drawable.sample_5, R.drawable.sample_6, R.drawable.sample_7,
                R.drawable.sample_0, R.drawable.sample_1, R.drawable.sample_2,
                R.drawable.sample_3, R.drawable.sample_4, R.drawable.sample_5,
                R.drawable.sample_6, R.drawable.sample_7 };
    }

在主程序GridViewActivity中,為GridView設置了一個數據適配器,并處理了GridView的單擊事件。適配器繼承自BaseAdapter類,與上章節中用到的適配器高度相似,在此不再重復。

4.4.17 標簽(Tab)

在有限的手機屏幕空間內,當要瀏覽的內容較多,無法在一個屏幕空間內全部顯示時,可以使用滾動視圖來延長屏幕的空間。當瀏覽的內容具有很強的類別性質時,更合適的方法是將不同類別的內容集中到各自的面板中,這時就需要使用面板Tab組件了。

Tab組件利用面板標簽把不同的面板內容切換到屏幕上,以顯示不同類別的內容。

下面通過一個實例來了解一下Tab組件的使用方法。在工程WidgetDemo的布局文件main.xml中添加一個名為TabDemo的Button,用以啟動TabActivity。

在main.xml中添加代碼如下:

    <Button
        android:id="@+id/button13"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="TabDemo" />

單擊Button并啟動GridViewActivity的代碼如下:

    Button tabbtn=(Button)this.findViewById(R.id.button13);
    tabbtn.setOnClickListener(new OnClickListener(){
    @Overridepublic void onClick(View v){
           // TODO Auto-generated method stub
        Intent intent=new Intent(WidgetDemoActivity.this,TabActivity.class);
           startActivity(intent);
    }
    });

同時在AndroidManifest.xml文件中聲明該Activity:

    <activity android:name="TabActivity"></activity>

TabActivity運行效果如圖4.34所示。

圖4.34 TabActivity運行效果

要使用Tab必然涉及它的容器TabHost,TabHost包括TabWigget和FrameLayout兩部分。TabWidget就是每個Tab的標簽,FrameLayout是Tab的內容。

TabActivity使用的布局文件是tab.xml。在tab.xml中定義了每個Tab中要顯示的內容,代碼如下:

    <?xml version="1.0" encoding="utf-8"?>
    <TabHost xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/tabhost"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent">
       <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:orientation="vertical">
           <TabWidget
                android:id="@android:id/tabs"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content" />
           <FrameLayout
                android:id="@android:id/tabcontent"
                android:layout_width="fill_parent"
                android:layout_height="fill_parent">
               <TextView
                    android:id="@+id/tab1"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:textSize="40dp"
                    android:text="Tab1頁面" />
               <TextView
                    android:id="@+id/tab2"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:textSize="40dp"
                    android:text="Tab2頁面" />
               <TextView
                    android:id="@+id/tab3"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:textSize="40dp"
                    android:text="Tab3頁面" />
           </FrameLayout>
       </LinearLayout>
    </TabHost>

在FrameLayout中我們放置了三個TextView組件,分別對應三個Tab所顯示的內容,當切換不同的Tab時會自動顯示不同的TextView內容。

在主程序TabActivity的OnCreate()方法中,首先獲得了TabHost的對象,并調用setup()方法進行初始化,然后通過TabHost.TabSpec增加Tab頁,通過setContent()增加當前Tab頁顯示的內容,通過setIndicator增加頁的標簽,最后設定當前要顯示的Tab頁。

TabActivity代碼如下:

    package introduction.android.widgetDemo;



    import android.app.Activity;
    import android.os.Bundle;
    import android.widget.TabHost;



    public class TabsActivity extends Activity {
        public void onCreate(Bundle savedInstanceState){
            super.onCreate(savedInstanceState);
            setContentView(R.layout.tab);
            // 步驟1:獲得TabHost的對象,并進行初始化setup()
            TabHost tabs=(TabHost)findViewById(R.id.tabhost);
            tabs.setup();
            // 步驟2:通過TabHost.TabSpec增加tab的一頁,通過setContent()增加內容,通過setIndicator增加頁的標簽
            /* 增加第1個Tab */
            TabHost.TabSpec spec=tabs.newTabSpec("Tag1");
            // 單擊Tab要顯示的內容
            spec.setContent(R.id.tab1);
            /* 顯示Tab3內容 */
            spec.setIndicator("Tab1");
            tabs.addTab(spec);
            /* 增加第2個Tab */
            spec=tabs.newTabSpec("Tag2");
            spec.setContent(R.id.tab2);// 單擊Tab要顯示的內容
            /* 顯示Tab3內容 */
            spec.setIndicator("Tab2");
            tabs.addTab(spec);
            /* 增加第3個Tab */
            spec=tabs.newTabSpec("Tag3");
            spec.setContent(R.id.tab3);// 單擊Tab要顯示的內容
            /* 顯示Tab3內容 */
            spec.setIndicator("Tab3");
            tabs.addTab(spec);
            /* 步驟3:可通過setCurrentTab(index)指定顯示的頁,從0開始計算。 */
            tabs.setCurrentTab(0);
        }
    }

除了使用上述方法設置Tab頁面的顯示內容外,還可以使用setContent(Intent)方法啟動某個Activity,并將該Activity的視圖作為Tab頁面的內容。

例如:

    Intent intent=new Intent().setClass(this, AlbumsActivity.class);
    spec=tabHost.newTabSpec("albums").setIndicator("Albums",
                          res.getDrawable(R.drawable.ic_tab_albums))
                      .setContent(intent);
    tabHost.addTab(spec);
主站蜘蛛池模板: 万州区| 铅山县| 大冶市| 玉龙| 札达县| 开江县| 嘉鱼县| 芜湖市| 石河子市| 改则县| 宁津县| 繁峙县| 富蕴县| 梁山县| 七台河市| 沧州市| 工布江达县| 贵州省| 昌邑市| 当阳市| 台山市| 连江县| 永年县| 金坛市| 安顺市| 林口县| 新宁县| 武平县| 定远县| 浦城县| 东安县| 阳高县| 镇江市| 汕头市| 麻江县| 尼勒克县| 黑龙江省| 于都县| 简阳市| 武冈市| 乐山市|