詳解Dialog(二)——有關列表的構建

上篇給大家講了Dialog的基本元素的構建方法,今天給大家說說有關列表對話框的構建。本篇講的所有列表項都是通過系統自帶的函數生成的,對於完全自定義對話框的方法,我們會在最後一篇講。

 

列表對話框主要有四種:普通列表、單選列表、雙選列表、自定義視圖的列表,下面我們一個個來分析。
 

一、普通列表

普通列表的樣式是這樣的:

要實現這樣的列表樣式,是通過下面的方法來實現的:

builder.setItems(CharSequence[] items, DialogInterface.OnClickListener listener)
builder.setItems(int itemsId, DialogInterface.OnClickListener listener)

這兩種方法實現的效果都是一樣的,

setItems(CharSequence[] items, DialogInterface.OnClickListener listener)

這個items傳進去的是一個字符串數組;

 

setItems(int itemsId, DialogInterface.OnClickListener listener)

這個傳進去的一個itemsId,是在XML中定義好的一個字符串數組資源的ID;

 

下面,我們一個個看看他們的具體用法:

 

1、字符串數組

下面是上圖是實現上圖效果的代碼:

String[] mItems = {"item0", "item1", "itme2", "item3", "itme4", "item5", "item6"};
AlertDialog.Builder builder = new AlertDialog.Builder(MyActivity.this);
builder.setIcon(R.drawable.ic_launcher);
builder.setTitle("使用列表字符串");
builder.setItems(mItems, new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int which) {
        Toast.makeText(MyActivity.this, "clicked:" + which, Toast.LENGTH_LONG).show();
    }
});
builder.create();
builder.show();

可以看到首先構造一個mItems數組,然後在buidler.setItems直接傳進去就好了。至於DialogInterface.OnClickListener(){}函數就是對點擊事件的監聽,which表示當前點擊的是哪個ITEM的索引。

 

2、字符串資源ID

首先在xml文件夾下建一個字符串資源XML,命名爲:array.xml,位置如圖:

 

然後定義一段字符串數組:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string-array name="dialog_items">
        <item>王菲</item>
        <item>王力宏</item>
        <item>帥哥</item>
        <item>美女</item>
    </string-array>
</resources>

下面就是利用SetItem來生成列表了:

AlertDialog.Builder builder = new AlertDialog.Builder(MyActivity.this);
builder.setIcon(R.drawable.ic_launcher);
builder.setTitle("使用Resource ID");
builder.setItems(R.array.dialog_items, new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int which) {
        Toast.makeText(MyActivity.this, "clicked:" + which, Toast.LENGTH_LONG).show();
    }
});
builder.create();
builder.show();

在這裏的SetItems時直接將我們字符串數組的name直接設置進去,出來的效果就是這樣的:

 

二、單選列表

單選列表的樣式是這樣的:

要實現單選列表,主要是通過下面四個其中之一來實現的:

方法一:

setSingleChoiceItems(CharSequence[] items, int checkedItem, DialogInterface.OnClickListener listener)

與上面一樣,傳進去一個字符串數組,和初始化時選中的ITEM,構造一個單選列表


方法二:

setSingleChoiceItems (int itemsId, int checkedItem, DialogInterface.OnClickListener listener)

同樣,與上面的例子相同,這裏傳進去的是一個字符串數組的資源ID,字符串數組的構造方法與上面相同,就不再贅述

 

方法三:

setSingleChoiceItems (ListAdapter adapter, int checkedItem, DialogInterface.OnClickListener listener)

這個方法是最難理解的方法,因爲這裏的ListAdapter並不能是普通的Adapter,不信你傳一個Adapter,保證出來只是你自己的ITEM視圖,旁邊的單選按鈕卻出不來,其實這裏的Adapter只是重寫單選按鈕旁的文字的樣式,並不支持所有的Adapter,這個我會在本文最後講述。
 

方法四:

setSingleChoiceItems (Cursor cursor, int checkedItem, String labelColumn, DialogInterface.OnClickListener listener)

這裏通過傳進去一個Cursor來構造對應的字符串數組,可以是數據庫Cursor,也可以其它系統自帶的數據Cursor,但基本上用不到,就不再講了
好了,關於方法三,因爲下面會接着講SetAdapter的知識,所以這部分我留在最後再講,這裏先講下方法一和方法二:

 

方法一和方法二,與上例沒什麼區別,下面我就以方法一以例來講講上面的效果圖是怎麼實現的吧:

代碼如下:

String[] mItems = {"攻", "受", "全能型", "不告訴你"};
AlertDialog.Builder builder = new AlertDialog.Builder(MyActivity.this);
builder.setIcon(R.drawable.ic_launcher);
builder.setTitle("你懂的");
builder.setSingleChoiceItems(mItems, 0, new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int which) {
        // TODO Auto-generated method stub
        Toast.makeText(MyActivity.this, "clicked:" + which, Toast.LENGTH_LONG).show();
    }
});
builder.create();
builder.show();

很簡單,構造一個mItems的String字符串,然後直接傳進去setSingleChoiceItems中,默認選中第一個,即索引是0的項。

 

三、多選列表

先看看效果圖:

自帶的多選構造函數有如下幾個:

方法一:

setMultiChoiceItems (CharSequence[] items, boolean[] checkedItems, DialogInterface.OnMultiChoiceClickListener listener)

一樣,傳進去一個ITEMS數組和對應的項目的選中與否狀態的數組;

 

方法二:

 setMultiChoiceItems (int itemsId, boolean[] checkedItems, DialogInterface.OnMultiChoiceClickListener listener)

這裏傳進去的是一個字符串數組,與第一部分相同

 

方法三:

setMultiChoiceItems (Cursor cursor, String isCheckedColumn, String labelColumn, DialogInterface.OnMultiChoiceClickListener listener)

同樣,這裏傳進去的是一個CURSOR,可以是數據庫的指針,也可以是系統自帶數據的指針,基本不怎麼用,就不講了

 

下面以方法一爲例看看多選列表的構造過程:

String[] mItems = {"經常犯二", "傻叉一枚", "逗逼", "小清純", "沉穩大叔", "有時可愛"};
AlertDialog.Builder builder = new AlertDialog.Builder(MyActivity.this);
builder.setIcon(R.drawable.ic_launcher);
builder.setTitle("性格類型");
builder.setMultiChoiceItems(mItems,
        new boolean[]{false, false, false, false, false, false, false},
        new DialogInterface.OnMultiChoiceClickListener() {
 
            @Override
            public void onClick(DialogInterface dialog, int which, boolean isChecked) {
                Toast.makeText(MyActivity.this, "clicked:" + which, Toast.LENGTH_LONG).show();
            }
        }
);
builder.show();

這裏構造了兩個數組,一個是字符串數組,另一個每項對應是否選中的boolean數組

String[] mItems = {"經常犯二", "傻叉一枚", "逗逼", "小清純", "沉穩大叔", "有時可愛"};

對應的選中項的布爾值數組:

new boolean[]{false, false, false, false, false, false, false}

四、自定義列表項

 

這節我帶大家自定義列表項的實現,故名思義,就是每個ITEM都是我們自己來定義,使用我們自己的Adapter,先看看效果:

要實現自定義列表主要是造下面這個函數來實現的:

setAdapter (ListAdapter adapter, DialogInterface.OnClickListener listener)

直接將我們構造好的Adapter設置進去。

下面就帶大家實現下圖示中的視圖:

1、構造Adapter

有關派生自BaseAdapter來構造ListViewAdapter的過程就不再細講了,大家可以參考我以前的兩篇文章:

首先是單個Item的佈局:(list_item.xml)

很簡單,採用水平佈局,左邊一個圖像,右邊一個對應的TEXT,這裏只是基本實現功能,大家完全可以在理解這篇文章的基礎上派生出更復雜的視圖

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="wrap_content"
    android:layout_height="match_parent">
    <ImageView
        android:id="@+id/item_imageview"
        android:layout_width="80dip"
        android:layout_height="80dip"
        android:scaleType="fitCenter"/>
    <TextView
        android:id="@+id/item_text"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:gravity="center_vertical|left"
        android:textSize="20sp"/>
</LinearLayout>

對應的視圖類:

private class ViewHolder{
    public TextView mTvTitle;
    public ImageView mImageView;
}

其中有兩個變量,一個存儲對應的TextView,另一個存儲對應的ImageView;

 

現在我們還需要一個類來存儲視圖類中TextView的標題字符串,和對應ImageView的圖片資源的ID值,這就是我們的數據類:

public static class DataHolder{
    public String title;
    public int ImageID;
    public DataHolder(String title,int imageID){
        this.title = title;
        this.ImageID = imageID;
    }
}

我們先階段性的看看我們的ListViewAdapter:

 

首先是派生自BaseAdapter,然後是構造函數,我們傳進去一個DataHolder的列表,用來存儲每個Item應該顯示的內容

public class ListItemAdapter extends BaseAdapter {
    private List<DataHolder> mDataList = new ArrayList<DataHolder>();
    private LayoutInflater mInflater;
 
    public ListItemAdapter(Context context, ArrayList<DataHolder> datalist) {
        if (datalist != null && datalist.size() > 0) {
            mDataList.addAll(datalist);
        }
        mInflater = LayoutInflater.from(context);
    }
    ………………
}

然後是最關鍵的getView部分:

public View getView(int position, View convertView, ViewGroup viewGroup) {
    ViewHolder holder = null;
    if (convertView == null) {
        holder=new ViewHolder();
        convertView = mInflater.inflate(R.layout.list_item, null);
        holder.mTvTitle = (TextView)convertView.findViewById(R.id.item_text);
        holder.mImageView = (ImageView)convertView.findViewById(R.id.item_imageview);
        convertView.setTag(holder);
 
    }else {
        holder = (ViewHolder)convertView.getTag();
    }
    holder.mImageView.setImageResource(mDataList.get(position).ImageID);
    holder.mTvTitle.setText(mDataList.get(position).title);
 
    return convertView;
}
holder.mImageView.setImageResource(mDataList.get(position).ImageID);
holder.mTvTitle.setText(mDataList.get(position).title);

最後返回convertView,讓系統去做繪圖
到這裏ListViewAdapter的構造過程就基本完成了,下面是完整的代碼:

/**
 * Created by harvic
 * date 2015-1-11
 * */
public class ListItemAdapter extends BaseAdapter {
    private List<DataHolder> mDataList = new ArrayList<DataHolder>();
    private LayoutInflater mInflater;
    public ListItemAdapter(Context context,ArrayList<DataHolder> datalist){
        if (datalist != null && datalist.size()>0){
            mDataList.addAll(datalist);
        }
        mInflater = LayoutInflater.from(context);
    }
    @Override
    public int getCount() {
        return mDataList.size();
    }
 
    @Override
    public Object getItem(int position) {
        return mDataList.get(position);
    }
 
    @Override
    public long getItemId(int position) {
        return position;
    }
 
    @Override
    public View getView(int position, View convertView, ViewGroup viewGroup) {
        ViewHolder holder = null;
        if (convertView == null) {
 
            holder=new ViewHolder();
 
            convertView = mInflater.inflate(R.layout.list_item, null);
            holder.mTvTitle = (TextView)convertView.findViewById(R.id.item_text);
            holder.mImageView = (ImageView)convertView.findViewById(R.id.item_imageview);
            convertView.setTag(holder);
 
        }else {
            holder = (ViewHolder)convertView.getTag();
        }
        holder.mImageView.setImageResource(mDataList.get(position).ImageID);
        holder.mTvTitle.setText(mDataList.get(position).title);
 
        return convertView;
    }
 
    private class ViewHolder{
        public TextView mTvTitle;
        public ImageView mImageView;
    }
    public static class DataHolder{
        public String title;
        public int ImageID;
        public DataHolder(String title,int imageID){
            this.title = title;
            this.ImageID = imageID;
        }
    }
}

2、構造列表

在MainActivity中,首先是初始化我們的ListViewAdapter,要初始化Adapter,就要首先傳進去一個DataHolder的數組,所有要先構造一個DataHolder的數組

private ArrayList<ListItemAdapter.DataHolder> initDataHolder(){
    ArrayList<ListItemAdapter.DataHolder> datalist = new ArrayList<ListItemAdapter.DataHolder>();
    ListItemAdapter.DataHolder data_1 = new ListItemAdapter.DataHolder("可愛萌寵1", R.drawable.animal1);
    ListItemAdapter.DataHolder data_2 = new ListItemAdapter.DataHolder("可愛萌寵2", R.drawable.animal2);
    ListItemAdapter.DataHolder data_3 = new ListItemAdapter.DataHolder("可愛萌寵3", R.drawable.animal3);
    ListItemAdapter.DataHolder data_4 = new ListItemAdapter.DataHolder("可愛萌寵4", R.drawable.animal4);
    datalist.add(data_1);
    datalist.add(data_2);
    datalist.add(data_3);
    datalist.add(data_4);
    return datalist;
}

在構造完成數據列表之後,下面就是構造我們的自定義的列表了,我把整個對話框顯示過程整合成了一個函數createCustomList,代碼如下:

private void createCustomList() {
    ArrayList<ListItemAdapter.DataHolder> dataHolders = initDataHolder();
    ListItemAdapter adapter = new ListItemAdapter(MyActivity.this, dataHolders);
    AlertDialog.Builder builder = new AlertDialog.Builder(MyActivity.this);
    builder.setIcon(R.drawable.ic_launcher);
    builder.setTitle("可愛萌寵");
    builder.setAdapter(adapter, new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialogInterface, int which) {
            Toast.makeText(MyActivity.this, "clicked:" + which, Toast.LENGTH_LONG).show();
        }
    });
    builder.create();
    builder.show();
}

OK啦,到這,整個自列表項的內容就講完了,下面再回過來給大家說說上面我們提到的有關單選列表自定義Adapter的問題。
 

五、有關單選列表自定義Adapter

這裏主要講的函數是第二部分單選列表中的方法三:

setSingleChoiceItems (ListAdapter adapter, int checkedItem, DialogInterface.OnClickListener listener)

在第四部分,我們構造了一個ListAdapter,這裏需要的也是同樣的一個ListAdapter,那我們直接將第四部分中的Adapter傳進去,會是什麼效果呢?

 

也就是利用下面的代碼:

我們直接在createCustomList()上面改一下,即把builder.setAdapter()直接換成setSingleChoiceItems() ,傳進去Adpter,看看在我們定義的視圖後面會不會出現一個單選按鈕呢?
 

private void createCustomList() {
    ArrayList<ListItemAdapter.DataHolder> dataHolders = initDataHolder();
    ListItemAdapter adapter = new ListItemAdapter(MyActivity.this, dataHolders);
    AlertDialog.Builder builder = new AlertDialog.Builder(MyActivity.this);
    builder.setIcon(R.drawable.ic_launcher);
    builder.setTitle("可愛萌寵");
    builder.setSingleChoiceItems(adapter, 0,new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialogInterface, int which) {
            Toast.makeText(MyActivity.this, "clicked:" + which, Toast.LENGTH_LONG).show();
        }
    });
    builder.create();
    builder.show();
}

運行一下,效果是這樣的:

看見了沒,毛也沒有,坑爹玩意,那這個函數到底是用來做什麼的呢,在源碼中有這樣一個文件:

地址在:$android_sdk_home/platforms/android-x.x/data/res/layout/simple_list_item_single_choice.xml
文件內容是這樣的:
 

<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/single_list_item"
    android:layout_width="match_parent"
    android:layout_height="?android:attr/listPreferredItemHeightSmall"
    android:textAppearance="?android:attr/textAppearanceListItemSmall"
    android:gravity="center_vertical"
    android:checkMark="?android:attr/listChoiceIndicatorSingle"
    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
  />

利用這個玩意是可以實現效果的,我們來試一下。

1、新建Adapter

新建一個佈局文件,來保存ListVIew的每項的Item,代碼如下:

<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/single_list_item"
    android:layout_width="match_parent"
    android:layout_height="?android:attr/listPreferredItemHeightSmall"
    android:textAppearance="?android:attr/textAppearanceListItemSmall"
    android:gravity="center_vertical"
    android:checkMark="?android:attr/listChoiceIndicatorSingle"
    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
  />

在Adapter中,同樣,用來保存ITEM視圖的ViewHolder類,如下:

    private class ViewHolder{
        public TextView  mName;
    }

因爲在佈局中只有一個TextView,所以在ViewHolder中也只需要一個TextView與其對應,至於類似上面的承載對應數據的DataHolder,因爲我們只需要一個String字符串數組就足夠了,所以就沒必要再新建一個類來承載這些數據了,所以我們要構造Adapter時,傳進來一個字符串數組就好了:

 

所以簡單的構造函數爲:

在構造時,傳進來我們每項要顯示的標題的字符串數組String[] items,並將其直接添加到我們的List<String> mList中。
 

public class SingleChoiceAdapter extends BaseAdapter {
    private LayoutInflater mInflater;
    private List<String> mList = new ArrayList<String>();
 
    public SingleChoiceAdapter(Context context, String[] items) {
        mInflater = LayoutInflater.from(context);
        if (items == null || items.length <= 0) {
            return;
        }
        for (String item : items) {
            mList.add(item);
        }
    }
 
    …………
}

然後是最關鍵的getView()部分:

public View getView(int position, View convertView, ViewGroup viewGroup) {
    ViewHolder holder = null;
    if (convertView == null) {
 
        holder=new ViewHolder();
 
        convertView = mInflater.inflate(R.layout.single_choice_item, null);
        holder.mName = (TextView)convertView.findViewById(R.id.single_list_item);
        convertView.setTag(holder);
 
    }else {
        holder = (ViewHolder)convertView.getTag();
    }
    holder.mName.setText(mList.get(position));
 
    return convertView;
}

這段代碼難度不大,就是每次繪圖時,將TextView的內容設置爲我們指定的字符串:

holder.mName.setText(mList.get(position));

下面是SingleChoiceAdapter完整的代碼:

/**
 * Created by harvic
 * date 2015-1-11
 */
public class SingleChoiceAdapter extends BaseAdapter {
    private LayoutInflater mInflater;
    private List<String> mList = new ArrayList<String>();
    public SingleChoiceAdapter(Context context,String[] items){
        mInflater = LayoutInflater.from(context);
        if (items == null || items.length<=0){
            return;
        }
        for(String item:items){
            mList.add(item);
        }
    }
    @Override
    public int getCount() {
        return mList.size();
    }
 
    @Override
    public Object getItem(int position) {
        return mList.get(position);
    }
 
    @Override
    public long getItemId(int position) {
        return position;
    }
 
    @Override
    public View getView(int position, View convertView, ViewGroup viewGroup) {
        ViewHolder holder = null;
        if (convertView == null) {
 
            holder=new ViewHolder();
 
            convertView = mInflater.inflate(R.layout.single_choice_item, null);
            holder.mName = (TextView)convertView.findViewById(R.id.single_list_item);
            convertView.setTag(holder);
 
        }else {
            holder = (ViewHolder)convertView.getTag();
        }
        holder.mName.setText(mList.get(position));
 
        return convertView;
    }
 
    private class ViewHolder{
        public TextView  mName;
    }
}

然後就是使用的階段了

2、構造單選列表

 

這裏首先構造SingleChoiceAdapter的實例,然後將其傳入setSingleChoiceItems中,代碼如下:

String[] mItems = {"攻", "受", "全能型", "不告訴你"};
SingleChoiceAdapter adapter = new SingleChoiceAdapter(MyActivity.this,mItems);
AlertDialog.Builder builder = new AlertDialog.Builder(MyActivity.this);
builder.setIcon(R.drawable.ic_launcher);
builder.setTitle("可愛萌寵");
builder.setSingleChoiceItems(adapter, 0, new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialogInterface, int which) {
        Toast.makeText(MyActivity.this, "clicked:" + which, Toast.LENGTH_LONG).show();
    }
});
builder.create();
builder.show();

運行出來的效果如圖:

看到沒,這裏效果是出來了,可見,在單選按鈕中,定義Adapter並不是隨便定義的,只能定義CheckedTextView的視圖,其它是不支持的!!!!

 

好了,到這裏本篇就結束了,下篇給大家講講有關自定義對話框的內容。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章