1. 程式人生 > >UI元件:AdapterView及子類(二)

UI元件:AdapterView及子類(二)

自動完成文字框(AutoCompleteTextView)

AutoCompleteTextView是從EditView派生出來的。它實際上也是一個文字編輯框,當用戶輸入一定字元之後,自動完成會顯示一個下拉選單,供使用者選擇,當用戶選擇了某個選單項之後,AutoCompleteTextView按使用者選擇自動填寫該文字框。
使用AutoCompleteTextView,只要為其設定一個Adapter,該Adapter封裝了AutoCompleteTextView預設的提示資訊。
AutoCompleteTextView還派生了一個字類MultiAutoCompleteTextView,該子類的功能與AutoCompleteTextView基本相似,只是MultiAutoCompleteTextView允許輸入多個提示項,提示項以分隔符分隔。可用setTokenizer()方法來設定分隔符。
佈局檔案如下所示:

<?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">

    <AutoCompleteTextView
        android:id="@+id/auto"
        android:layout_width
="match_parent" android:layout_height="wrap_content" android:completionHint="請選擇您喜歡的圖書:" android:dropDownHorizontalOffset="10dp" android:completionThreshold="1"/>
<MultiAutoCompleteTextView android:id="@+id/mauto" android:layout_width="match_parent"
android:layout_height="wrap_content" android:completionThreshold="1"/>
</LinearLayout>
android:completionThreshold 設定使用者至少輸入幾個字元才會顯示提示
android:dropDownHorizontalOffset 設定下拉選單與文字框之間的水平偏移,下拉選單預設與文字框左對齊
android:completionHint 設定下拉選單的提示標題

Activity中的程式碼如下所示:

public class AutoCompleteTextViewActivity extends AppCompatActivity {

    private AutoCompleteTextView auto;
    private MultiAutoCompleteTextView mAuto;
    private String[] books = new String[]{"瘋狂Android講義","瘋狂Java講義","瘋狂XML講義","瘋狂Ajax講義"};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_auto_complete_text_view);
        auto = (AutoCompleteTextView) findViewById(R.id.auto);
        mAuto = (MultiAutoCompleteTextView) findViewById(R.id.mauto);
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,android.R.layout.simple_dropdown_item_1line,books);
        auto.setAdapter(adapter);
        mAuto.setAdapter(adapter);
        //MultiAutoCompleteTextView設定分隔條
        mAuto.setTokenizer(new MultiAutoCompleteTextView.CommaTokenizer());
    }
}

介面效果如下所示:

網格檢視(GridView)

GridView與ListView有著相同的父類:AbsListView。它們之間的區別在於GridView可以顯示多行多列,而ListView只能顯示一列。
下面演示如何實現帶預覽的圖片瀏覽器,效果圖如下:

佈局檔案程式碼如下:

<?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/grid_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:horizontalSpacing="2dp"
        android:verticalSpacing="2dp"
        android:numColumns="4"
        android:gravity="center"/>
    <ImageView
        android:id="@+id/image"
        android:layout_width="240dp"
        android:layout_height="240dp"
        android:layout_gravity="center_horizontal"/>
</LinearLayout>
android:horizontalSpacing 設定各元素之間的水平間距
android:verticalSpacing 設定各元素之間的垂直間距
android:numColumns 設定列數

Activity的程式碼如下:

public class GridViewActivity extends AppCompatActivity {

    private GridView gridView;
    private ImageView imageView;
    private int[] imageIds = new int[]{R.drawable.bomb5,R.drawable.bomb6,R.drawable.bomb7,R.drawable.bomb8,
            R.drawable.bomb9,R.drawable.bomb10,R.drawable.bomb11,R.drawable.bomb12,
            R.drawable.bomb13,R.drawable.bomb14,R.drawable.bomb15,R.drawable.bomb16};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_grid_view);

        gridView = (GridView) findViewById(R.id.grid_view);
        imageView = (ImageView) findViewById(R.id.image_view);

        List<Map<String,Object>> listItems = new ArrayList<>();
        for (int i = 0; i < imageIds.length; i++) {
            Map<String,Object> item = new ArrayMap<>();
            item.put("image",imageIds[i]);
            listItems.add(item);
        }
        SimpleAdapter adapter = new SimpleAdapter(this,listItems,R.layout.ceil,new String[]{"image"},new int[]{R.id.image1});
        gridView.setAdapter(adapter);
        //新增列表項單擊的監聽器
        gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                //顯示被單擊的圖片
                imageView.setImageResource(imageIds[position]);
            }
        });
    }
}

R.layout.ceil檔案對應的程式碼如下所示:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center_horizontal">
    <ImageView
        android:id="@+id/image1"
        android:layout_width="50dp"
        android:layout_height="50dp" />
</LinearLayout>

可展開的列表元件(ExpandableListView)

ExpandableListView是ListView的子類。
它把應用中的列表項分為幾組,每組又可包含多個列表項。
它所顯示的列表項應該由ExpandableListAdapter提供,ExpandableListAdapter是一個介面。
與Adapter類似,實現ExpandableListAdapter有三種常用方法。

擴充套件BaseExpandableListAdapter(ExpandableListAdapter的子類)實現ExpandableListAdapter
使用SimpleExpandableListAdapter(BaseExpandableListAdapter的子類) 將兩個List集合包裝成ExpandableListAdapter
使用SimpleCursorTreeAdapter(BaseExpandableListAdapter的實現類)將Cursor中的資料包裝成SimpleCursorTreeAdapter

下面程式通過自定義的ExpandableListAdapter為ExpandableListView提供列表項。
當擴充套件BaseExpandableListAdapter時,關鍵是實現如下4個方法:

getGroupCount() : 該方法返回的是包含的組列表項的數量。
getGroupView() : 該方法返回的View物件將作為組列表項。
getChildrenCount() : 該方法返回的是特定組所包含的子列表項的數量。
getChildView() : 該方法返回的View物件將作為特定組、特定位置的子列表項。

佈局檔案程式碼如下:

<ExpandableListView
        android:id="@+id/expandable_list_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

建立一個類,繼承BaseExpandableListAdapter,程式碼如下:

package com.example.administrator.adapterviewinfo;

import android.content.Context;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.BaseExpandableListAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

public class MyAdapter extends BaseExpandableListAdapter{

    private int[] logos = new int[]{R.drawable.p,R.drawable.z,R.drawable.t};
    private String[] armTypes = new String[]
            { "神族兵種", "蟲族兵種", "人族兵種"};
    private String[][] arms = new String[][]
            {
                    { "狂戰士", "龍騎士", "黑暗聖堂", "電兵" },
                    { "小狗", "刺蛇", "飛龍", "自爆飛機" },
                    { "機槍兵", "護士MM" , "幽靈" }
            };
    private Context context;

    public MyAdapter(Context context) {
        this.context = context;
    }

    @Override
    public int getGroupCount() {
        return armTypes.length;
    }

    @Override
    public int getChildrenCount(int groupPosition) {
        return arms[groupPosition].length;
    }

    /**
     * 獲取指定組位置處的組資料
     * @param groupPosition
     * @return
     */
    @Override
    public Object getGroup(int groupPosition) {
        return armTypes[groupPosition];
    }

    /**
     * 獲取指定組位置,指定子列表項處的子列表項資料
     * @param groupPosition
     * @param childPosition
     * @return
     */
    @Override
    public Object getChild(int groupPosition, int childPosition) {
        return arms[groupPosition][childPosition];
    }

    @Override
    public long getGroupId(int groupPosition) {
        return groupPosition;
    }

    @Override
    public long getChildId(int groupPosition, int childPosition) {
        return childPosition;
    }

    @Override
    public boolean hasStableIds() {
        return true;
    }

    /**
     * 該方法決定每個組選項的外觀
     * @param groupPosition
     * @param isExpanded
     * @param convertView
     * @param parent
     * @return
     */
    @Override
    public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
        LinearLayout linearLayout = new LinearLayout(context);
        linearLayout.setOrientation(LinearLayout.HORIZONTAL);
        ImageView logo = new ImageView(context);
        logo.setImageResource(logos[groupPosition]);
        linearLayout.addView(logo);
        TextView textView = getTextView();
        textView.setText(getGroup(groupPosition).toString());
        linearLayout.addView(textView);
        return linearLayout;
    }

    /**
     * 該方法決定每個子選項的外觀
     * @param groupPosition
     * @param childPosition
     * @param isLastChild
     * @param convertView
     * @param parent
     * @return
     */
    @Override
    public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
        TextView textView = getTextView();
        textView.setText(getChild(groupPosition,childPosition).toString());
        return textView;
    }

    @Override
    public boolean isChildSelectable(int groupPosition, int childPosition) {
        return true;
    }

    private TextView getTextView(){
        AbsListView.LayoutParams params = new AbsListView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,64);
        TextView textView = new TextView(context);
        textView.setLayoutParams(params);
        textView.setGravity(Gravity.CENTER_VERTICAL|Gravity.LEFT);
        textView.setPadding(36,0,0,0);
        textView.setTextSize(17);
        return textView;
    }
}

Activity中的程式碼如下所示:

public class ExpandableListViewActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_expandable_list_view);
        ExpandableListView expandableListView = (ExpandableListView) findViewById(R.id.expandable_list_view);
        MyAdapter myAdapter = new MyAdapter(this);
        expandableListView.setAdapter(myAdapter);
    }
}

效果圖如下所示 :

Spinner

Spinner就是一個列表選擇框。
Spinner和Gallery(如今已過時)都繼承了AbsSpinner。

若下拉列表框中的列表項是確定的,只要為Spinner指定android:entries屬性即可實現Spinner。
若需要動態決定下拉列表項的內容,可以使用Adapter為Spinner新增列表項。

下面定義了兩個Spinner,一個指定了android:entries屬性,另一個使用Adapter為Spinner新增列表項。
佈局檔案如下所示:

<?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" >
    <!--指定顯示Spinner元件的陣列-->
    <Spinner
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:entries="@array/list"/>
    <Spinner
        android:id="@+id/spinner"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</LinearLayout>

@array/list對應的檔案內容如下:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string-array name="list">
        <item>AbsListView</item>
        <item>AbsSpinner</item>
        <item>AdapterViewAnimator</item>
    </string-array>
</resources>

Activity中的檔案如下所示:

public class SpinnerActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_spinner);
        String[] arr = new String[]{"孫悟空","豬八戒","唐僧"};
        Spinner spinner = (Spinner) findViewById(R.id.spinner);
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,android.R.layout.simple_spinner_item,arr);
        spinner.setAdapter(adapter);
    }
}

效果如下所示:

AdapterViewFlipper

AdapterViewFlipper繼承自AdapterViewAnimator。
AdapterViewFlipper每次只顯示一個元件,可以通過showPrevious()和showNext()方法控制該元件顯示上一個、下一個元件。
AdapterViewFlipper支援的Xml屬性如下:

XML屬性 相關方法 說明
android:autoStart startFlipping() 設定顯示該元件是否自動播放
android:flipInterval setFlipInterval(int) 設定自動播放的時間間隔

下面的例項使用AdapterViewFlipper實現圖片的自動播放。
佈局檔案程式碼如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <AdapterViewFlipper
        android:id="@+id/adapter_view_flipper"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:flipInterval="5000" />
    <Button
        android:id="@+id/prev"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:text="上一個"/>
    <Button
        android:id="@+id/auto"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:text="自動播放"/>
    <Button
        android:id="@+id/next"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:text="上一個"/>
</RelativeLayout>

Activity中的程式碼如下所示:

public class AdapterViewFlipperActivity extends AppCompatActivity implements View.OnClickListener{

    private int[] imageIds = new int[]
            {       R.drawable.shuangzi, R.drawable.shuangyu,
                    R.drawable.chunv, R.drawable.tiancheng, R.drawable.tianxie,
                    R.drawable.sheshou, R.drawable.juxie, R.drawable.shuiping,
                    R.drawable.shizi, R.drawable.baiyang, R.drawable.jinniu,
                    R.drawable.mojie };
    private AdapterViewFlipper adapterViewFlipper;
    private Button prev;
    private Button next;
    private Button auto;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_adapter_view_flipper);
        initUI();

        BaseAdapter adapter = new BaseAdapter() {
            @Override
            public int getCount() {
                return imageIds.length;
            }

            @Override
            public Object getItem(int position) {
                return position;
            }

            @Override
            public long getItemId(int position) {
                return position;
            }

            @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                ImageView imageView = new ImageView(AdapterViewFlipperActivity.this);
                imageView.setImageResource(imageIds[position]);
                //設定圖片的縮放方式
                imageView.setScaleType(ImageView.ScaleType.FIT_XY);
                //設定圖片的佈局引數
                imageView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
                return imageView;
            }
        };
        adapterViewFlipper.setAdapter(adapter);
    }

    private void initUI() {
        adapterViewFlipper = (AdapterViewFlipper) findViewById(R.id.adapter_view_flipper);
        prev = (Button) findViewById(R.id.prev);
        auto = (Button) findViewById(R.id.auto);
        next = (Button) findViewById(R.id.next);
        prev.setOnClickListener(this);
        auto.setOnClickListener(this);
        next.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.prev:
                prev();
                break;
            case R.id.auto:
                auto();
                break;
            case R.id.next:
                next();
                break;
            default:
                break;
        }
    }

    /**
     * 顯示下一個元件
     */
    private void next() {
        //顯示下一個元件
        adapterViewFlipper.showNext();
        //停止自動播放
        adapterViewFlipper.stopFlipping();
    }

    /**
     * 自動播放
     */
    private void auto() {
        //開始自動播放
        adapterViewFlipper.startFlipping();
    }

    /**
     * 顯示上一個元件
     */
    private void prev() {
        //顯示上一個元件
        adapterViewFlipper.showPrevious();
        //停止自動播放
        adapterViewFlipper.stopFlipping();
    }
}

效果圖如下所示:

StackView

StackView也是AdapterViewAnimator的子類。
StackView將以堆疊的方式顯示多個列表項。
StackView提供了兩種控制其View元件的方式:

拖走StackView處於頂端的View,下一個View將會顯示出來。將上一個View拖進StackView,將使其顯示出來。
通過呼叫StackView的showPrevious()、showNext()控制顯示上一個、下一個元件。

佈局檔案如下所示:

<?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="horizontal">
    <!--android:loopViews設定迴圈到最後一個元件時是否自動“轉頭”到第一個元件-->
    <StackView
        android:id="@+id/stack_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:loopViews="true"/>
    <Button
        android:id="@+id/prev"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="20dp"
        android:text="上一個"/>
    <Button
        android:id="@+id/next"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="20dp"
        android:text="下一個"/>
</LinearLayout>

Activity中的程式碼如下所示:

public class StackViewActivity extends AppCompatActivity{

    private int[] imageIds = new int[]{
            R.drawable.bomb5,R.drawable.bomb6,R.drawable.bomb7,R.drawable.bomb8,
            R.drawable.bomb9,R.drawable.bomb10,R.drawable.bomb11,R.drawable.bomb12,
            R.drawable.bomb13,R.drawable.bomb14,R.drawable.bomb15,R.drawable.bomb16
    };
    private StackView stackView;
    private Button prev;
    private Button next;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_stack_view);
        initUI();
        List<Map<String,Object>> listItems = new ArrayList<>();
        for (int i = 0; i < imageIds.length; i++) {
            Map<String,Object> item = new ArrayMap<>();
            item.put("image",imageIds[i]);
            listItems.add(item);
        }
        SimpleAdapter adapter = new SimpleAdapter(this,listItems,R.layout.ceil,new String[]{"image"},new int[]{R.id.image1});
        stackView.setAdapter(adapter);
    }

    private void initUI() {
        stackView = (StackView) findViewById(R.id.stack_view);
        prev = (Button) findViewById(R.id.prev);
        next = (Button) findViewById(R.id.next);
        prev.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //顯示上一個元件
                stackView.showPrevious();
            }
        });
        next.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //顯示下一個元件
                stackView.showNext();
            }
        });
    }
}

R.layout.ceil檔案對應的程式碼如下所示:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center_horizontal">
    <ImageView
        android:id="@+id/image1"
        android:layout_width="50dp"
        android:layout_height="50dp" />
</LinearLayout>

效果如下所示:

拖動頂端的圖片或者點選“下一個”都可以切換到下一張圖片。