1. 程式人生 > >android基礎--ListView控制元件,android對話方塊

android基礎--ListView控制元件,android對話方塊

ListView

用ScrollVeiw+TextView方式顯示多條目列表時,會創建出所有可顯示的物件,易造成記憶體溢位。谷歌工程師給我們提供了ListView控制元件。

ListView,只需要建立(一屏能顯示出來的物件個數+1)個Item物件,再下拉顯示時,之前顯示現在完全隱藏的物件會被賦值給介面卡getView()方法的convertView引數,可以在getView()方法中反覆複用convertView物件,後面新顯示的物件都不需要再新建立物件。

ListView是典型的按MVC模式設計的。
--- M:SQLite資料庫
--- V:ListView
--- C:Adapter


ListView控制元件使用時需要為其配置資料介面卡:void setAdapter(ListAdapter adapter)。


直接繼承ListAdapter介面有很多方法要複寫,可繼承其預設實現類BaseAdapter。 
---android介面預設實現類,要麼以simple開頭,要麼以default或base開頭。

BaseAdapter的2個重要方法
int getCount(),獲取要顯示在ListView中的總記錄數。
View getView(int position,View convertView,ViewGroup parent),指定ListView中的條目,從資料庫或集合指定位置獲取資料構造一個View,這個View可以new TextView(),也可以是通過View.inflat()填充出來的,還可以複用convertView。
---position就是ListView中的條目。
---convertView,接收完全隱藏起來的子條目的view物件。可複用這個convertView,不用每次都new EditView()或inflat()出新的檢視。


複用convertView()的程式碼如下:

public View getView(int position, View convertView, ViewGroup parent)
{

     TextView tv = null;
     if(convertView == null) {
        System.out.println("getView 新建: " + position);
	// 如果convertView等於null, 沒有快取過物件, 新建一個
	tv = new TextView(MainActivity.this);
     } else {
	System.out.println("getView 複用: " + position);
	// 如果convertView不等於null, 某個條目的物件被快取了, 拿過來直接複用
	tv = (TextView) convertView;
     }
     ....
}

或者
public View getView(int position, View convertView, ViewGroup parent)
{
	View view = null;
	if(convertView == null) {
		System.out.println("新建:" + position);
		// 佈局填充器, 打氣筒, 功能: 把佈局檔案, 轉換成一個View物件
		LayoutInflater inflater = LayoutInflater.from(MainActivity2.this);
		view = inflater.inflate(R.layout.listview_item, null);
	} else {
		System.out.println("複用:" + position);
		view = convertView;
	}        
	TextView tvName = (TextView) view.findViewById(R.id.tv_listview_item_name);
	TextView tvAge = (TextView) view.findViewById(R.id.tv_listview_item_age);
	TextView tvBalance = (TextView) view.findViewById(R.id.tv_listview_item_balance);
        
        ......  
}
上面程式碼中,static View inflate(Context context, int resource, ViewGroup root),是View的靜態方法,從一個xml 佈局檔案中轉換成一個View物件。 

ListView資料顯示的進一步優化,使用靜態內部類ViewHolder:

class ChatListAdapter extends BaseAdapter
{
 static class ViewHolder 
    {
  TextView text;
  ImageView icon;
    }
    public View getView(int position, View convertView, ViewGroup parent) 
    {
     ViewHolder holder;
     if (convertView == null) 
        {
      convertView = mInflater.inflate(R.layout.list_item_icon_text, null);
      holder = new ViewHolder();
      holder.text = (TextView) convertView.findViewById(R.id.text);
      holder.icon = (ImageView) convertView.findViewById(R.id.icon);
            convertView.setTag(holder);
     } 
        else 
        {
      holder = (ViewHolder) convertView.getTag();
     }
        holder.text.setText(DATA[position]);
     holder.icon.setImageBitmap((position & 1) == 1 ? mIcon1 : mIcon2);
     return convertView;
    }
}

ViewHolder的作用:優化顯示效率,即之前顯示過的不用再從佈局檔案讀取,直接從快取中讀取。可以看到它只是一個靜態類,它的作用就在於減少不必要的呼叫findViewById。

常用現成的資料介面卡(都有侷限性,最靈活的還是BaseAdapter)
1)  ArrayAdapter
     是BaseAdapter的子類,內部已有預設實現,使用時直接傳入引數構造出來即可,4種構造方法:
         ArrayAdapter(Context context, int resource, int textViewResourceId, List<T> objects)
ArrayAdapter(Context context, int resource, int textViewResourceId, T[] objects)
ArrayAdapter(Context context, int textViewResourceId, List<T> objects)
ArrayAdapter(Context context, int textViewResourceId, T[] objects) 
     ArrayAdapter不能實現類似setting應用的介面,它只能指定listview前面的圖示都一樣。SimpleAdapter可以實現這種效果。

2)  SimpleAdapter
     建構函式:SimpleAdapter(Context context, List<? extends Map<String,?>> data, int resource, String[] from, int[] to);
     ----data:繫結的資料,是一個List集合。
     ----resource:R.layout.list_item,資料顯示對應的佈局。
     ----from[]: map集合裡面資料的key。
     ----to[]:佈局檔案裡面的id。from和to用於資料跟view物件間建立一個對映關係。

android對話方塊

通知對話方塊

//使用AlertDailog包下的Builder
new AlertDialog.Builder(context)
 .setTitle("java培訓")
 .setCancelable(false) //設定不能通過“後退”按鈕關閉對話方塊
 .setMessage("瀏覽傳智播客網站?")
        .setCancelable(false) //設定按返回鍵無法關閉對話方塊---取消和確認均可以關閉對話方塊。
 .setPositiveButton("確認",
  new DialogInterface.OnClickListener(){
  public void onClick(DialogInterface dialoginterface, int i){
          Uri uri = Uri.parse("http://www.itcast.cn/");//開啟連結
          Intent intent = new Intent(Intent.ACTION_VIEW, uri);
          startActivity(intent);
      }
 })
 .setNegativeButton("取消", new DialogInterface.OnClickListener() {
             public void onClick(DialogInterface dialog, int id) {
                   dialog.cancel();
             }
     })
     .show();//顯示對話方塊
上面程式碼採用的是一個鏈式呼叫,像setTitle()、setMessage()這些方法,他們的返回值都是當前對話方塊物件。

選項列表對話方塊
---裡面有一個ListView控制元件

final String[] items = {"java", ".net", "php"};
new AlertDialog.Builder(SenderNotificationActivity.this).setTitle("選擇語言")
 .setItems(items, new DialogInterface.OnClickListener() {
     public void onClick(DialogInterface dialog, int item) {
             Toast.makeText(getApplicationContext(), items[item], 
  Toast.LENGTH_SHORT).show();
     }
 }).show();//顯示對話方塊
也可以加按鈕,意義不大。

單選對話方塊

final String[] items = {"java", ".net", "php"};
new AlertDialog.Builder(SenderNotificationActivity.this).setTitle("選擇語言")
.setSingleChoiceItems(items, 1, new DialogInterface.OnClickListener() {
  public void onClick(DialogInterface dialog, int item) {
         Toast.makeText(getApplicationContext(), items[item], 
  Toast.LENGTH_SHORT).show();
         dialog.cancel();
   }
}).show();//顯示對話方塊
setSingleChoiceItems()的第二個引數是設定預設選項,選項索引從0開始,-1代表不選擇任何選項。

多選對話方塊

final String[] items = {"java", ".net", "php"};
new AlertDialog.Builder(SenderNotificationActivity.this).setCancelable(false)
.setTitle("選擇語言")
.setMultiChoiceItems(items, new boolean[]{false,true,false}, new DialogInterface.OnMultiChoiceClickListener() {
 @Override
 public void onClick(DialogInterface dialog, int which, boolean isChecked) {
  if(isChecked){
  Toast.makeText(getApplicationContext(), items[which], 
   Toast.LENGTH_SHORT).show();
  }
  }
 })
.setPositiveButton("確認",
 new DialogInterface.OnClickListener(){
 public void onClick(DialogInterface dialoginterface, int i){
  dialoginterface.dismiss();
  }
})
.show();//顯示對話方塊

進度條

<ProgressBar
 style="@android:style/Widget.ProgressBar.Horizontal" // 改變為長條的樣式
 android:layout_width="fill_parent"
 android:layout_height="wrap_content"
 android:max="100" // 設定進度條的最大刻度
 android:progress="0" /> // 設定當前的進度值

進度對話方塊
有2種方式可以開啟進度對話方塊
方式一:
ProgressDialog.show(this, "請稍等", "資料正在載入中...", true);
方式二:

final ProgressDialog pd = new ProgressDialog(this);
pd.setIcon(android.R.drawable.ic_dialog_alert);
pd.setTitle("請稍候");
pd.setMessage("正在下載中...");
// 修改進度條的樣式
pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
pd.setMax(100);
pd.show(); // 彈出進度對話方塊時, 預設把進度設定為0

new Thread(new Runnable() {
 @Override
 public void run() {
  while(true) {
   SystemClock.sleep(100);
   
   pd.incrementProgressBy(5);
   
   if(pd.getMax() == pd.getProgress()) {
    System.out.println("下載完成了..");
    pd.dismiss(); // 把對話方塊給關閉掉
    break;
   }
  }
 }
}).start();
注:pd.show(),//彈出進度對話方塊時,預設把進度設定為0,所以pd.setProgress()放在show()之後才生效。
       ProgressDialog和ProgressBar,可以在子執行緒中重新整理,內部已封裝了handler物件,進行了特殊處理。

android常用控制元件

Spinner控制元件,下拉單選列表框,列表顯示方式也是ListView。
有2種使用方式
方式一:
佈局檔案中新增Spinner控制元件:

    <Spinner
        android:id="@+id/spinner"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
在activity中執行程式碼
 Spinner mSpinner = (Spinner) findViewById(R.id.spinner);

 String[] items = {"java", ".net", "c#", "php", "c", "c++"};
 ArrayAdapter<String> mAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, items);
 mSpinner.setAdapter(mAdapter);

 mSpinner.getSelectedItemPosition();//獲取被選中項的索引,從0開始。

方式二:
在佈局檔案中設定Spinner控制元件的entries屬性,這時是使用android系統預設樣式,控制元件樣式與方式一略有不同:

<Spinner
 android:id="@+id/spinner"
 android:entries="@array/lagu" // 指定展示的資料
 android:layout_width="fill_parent"
 android:layout_height="wrap_content" />

// 定義在strings.xml檔案中
<string-array name="lagu">
 <item>java</item>
 <item>.net</item>
 <item>c#</item>
 <item>c</item>
 <item>c++</item>
 <item>java</item>
 <item>.net</item>
 <item>c#</item>
 <item>c</item>
 <item>c++</item>
</string-array>
AutoCompleteTextView 自動提示文字框
佈局檔案中:
<AutoCompleteTextView
 android:id="@+id/actv"
 android:completionThreshold="1" // 設定從第一個字元開始提示, 預設值為: 2
 android:layout_width="fill_parent"
 android:layout_height="wrap_content" />
activity中程式碼:
AutoCompleteTextView actv = (AutoCompleteTextView) findViewById(R.id.actv);
String[] items = {"老方", "老黎", "老馮", "張澤華", "張三", "張衝", "王1", "王昭珽", "王友軍", "王友紅"};
ArrayAdapter<String> mAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, items);
actv.setAdapter(mAdapter);
MultiAutoCompleteTextView 多個自動提示文字框
程式碼與AutoCompleteTextView基本一樣,只是activity中多了一個步驟:
   // 設定一個分隔符號: 逗號
   mactv.setTokenizer(new MultiAutoCompleteTextView.CommaTokenizer());

android Style樣式(作用在控制元件上),主題(作用在activity上)

樣式寫在res/styles.xml檔案中,在佈局檔案中用style="@style/textview_style",其中textview_style為styles.xml檔案中樣式的名稱。
樣式可繼承。

 <style name="textview_style">
  <item name="android:layout_width">wrap_content</item>
  <item name="android:layout_height">wrap_content</item>
  <item name="android:layout_marginBottom">10dip</item>
  <item name="android:layout_marginLeft">20dip</item>
  <item name="android:layout_marginRight">20dip</item>
  <item name="android:layout_marginTop">10dip</item>
  <item name="android:background">#3300FF00</item>
  <item name="android:paddingBottom">15dip</item>
  <item name="android:paddingLeft">60dip</item>
  <item name="android:paddingRight">60dip</item>
  <item name="android:paddingTop">15dip</item>
  <item name="android:textColor">#0000FF</item>
  <item name="android:textSize">25sp</item>
 </style>
 <style name="textview_style_red" parent="textview_style">
  <item name="android:textColor">#FF0000</item>
 </style>

主題, 作用在Activity
 <style name="custom_theme">

  <item name="android:windowBackground">@drawable/a</item>
  <item name="android:windowNoTitle">true</item>
  <item name="android:windowFullscreen">true</item>
 </style>
 <style name="custom_theme_1" parent="custom_theme">
  <item name="android:windowBackground">@drawable/b</item>
 </style>

---#00FF00,#後面再加2個16進位制數,表示透明度。
---主題也可以自定義,也是styles.xml新增style標籤。
---自定義主題時,對activity中的屬性,不會有程式碼提示。

前景透明主題自定義