《Android》『GridView』- 網格視圖元件的基本用法、如何避免 OnItemClickListener 失效
《Android Developers 參考文獻》
《簡單介紹》
GridView 是一種網格視圖圖庫的瀏覽元件,它可以將資料以網格的方式排列,在自訂 GridView 介面的實作方法上,它與之前所介紹的 Spinner、Gallery 以及 ListView 一樣,都可以透過自訂一個繼承 BaseAdapter 的 Adapter,客製化出自己想要的介面。這邊我們就不再贅述,這篇主要要來說明的是,當自訂的 item 介面裡的元件有另外實作按鈕功能時,要如何讓 AdapterView.OnItemClickListener 的事件與該按鈕的事件不互相衝突。
➥自訂一個繼承 BaseAdapter 的 Adapter 以實作 GridView
➥避免 item 介面裡的按鈕事件導致 AdapterView.OnItemClickListener 事件失效
自訂一個 Adapter 以實作 GridView
這邊直接透過程式碼片段,說明如何透過自訂一個繼承 BaseAdapter 的 Adapter,以實作 GridView。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
package ... import ... public class GridViewAdapter extends BaseAdapter { private LayoutInflater mLayoutInflater; List<Map<String, Object>> mItemList; public GridViewAdapter(Context context, List<Map<String, Object>> itemList) { mLayoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); mItemList = itemList; } @Override public int getCount() { //取得 GridView 列表 Item 的數量 return mItemList.size(); } @Override public Object getItem(int position) { //取得 GridView列表於 position 位置上的 Item return mItemList.get(position); } @Override public long getItemId(int position) { //取得 GridView 列表於 position 位置上的 Item 的 ID return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { //設定與回傳 convertView 作為顯示在這個 position 位置的 Item 的 View。 View v = mLayoutInflater.inflate(R.layout.grid_view_item, parent, false); ImageView imgView = (ImageView) v.findViewById(R.id.imgView); TextView txtView = (TextView) v.findViewById(R.id.txtView); imgView.setImageResource(Integer.valueOf(mItemList.get(position).get("Item icon").toString())); txtView.setText(mItemList.get(position).get("Item title").toString()); //為 imgView 設定按紐點擊監聽器 imgView.setOnClickListener(new ItemButton_Click(this.MainActivity, position)); return v; } //自訂按鈕監聽事件 class ItemButton_Click implements OnClickListener { private int position; private MainActivity mainActivity; ItemButton_Click(MainActivity context, int pos) { this.MainActivity = context; //可以同時將 MainActivity 傳入 position = pos; //傳入 item 位置 } @Override public void onClick(View v) { Log.d("xavier", "ItemButton = " + list.get(position).get("id")); ... } } } |
GridViewAdapter.java
在此範例中,我們想為 item 中的 imgView 元件設定按鈕監聽器,我們都知道 item 的概念其實是一個類似藍圖的框架,在 getView 中,Adapter 其實是根據其所傳入的 position 參數,一直取得並定義在不同欄位的 item 介面資訊,因此,若要在 item 裡面定義按鈕監聽器,我們就必須自訂一個實作 OnClickListener 介面的類別(ItemButton_Click),且此類別需傳入其 item 的位置(position),以定義不同位置的動作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="10dp" > <ImageView android:id="@+id/imgView" android:layout_width="wrap_content" android:layout_height="match_parent" /> <TextView android:id="@+id/txtView" android:layout_width="match_parent" android:layout_height="match_parent" android:textSize="20sp" android:paddingLeft="10dp" /> </LinearLayout> |
grid_view_item.xml
我們自訂了一個名為 grid_view_item.xml 的介面,裡面包含了一個 ImageView 與 TextView,並在GalleryAdapter 中的 getView() 方法中指定這個介面為每個 item 的 layout。接著,在 MainActivity 中宣告 GridView 並使用定義好的 GridViewAdapter,程式碼片段如下 –
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
package ... import ... public class MainActivity extends Activity { private static final String ITEM_TITLE = "Item title"; private static final String ITEM_ICON = "Item icon"; private TextView mTxtR; private GridView gridview; private GridViewAdapter mGridViewAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTxtR = (TextView) findViewById(R.id.txtR); //宣告 Gallery 元件 gridview = (GridView)findViewById(R.id.gridview); //定義 Gallery 中每個 Item 的資料 List<Map<String, Object>> itemList = new ArrayList<Map<String, Object>>(); String[] regionList = {"1", "2", "3", "4"}; TypedArray regionIconList = getResources().obtainTypedArray(R.array.region_icon_list); for (int i = 0; i < regionList.length; i++) { Map<String, Object> item = new HashMap<String, Object>(); item.put(ITEM_TITLE, regionList[i]); item.put(ITEM_ICON, regionIconList.getResourceId(i, 0)); itemList.add(item); } // GridView 中所需之資料參數可透過修改 Adapter 的建構子傳入 mGridViewAdapter = new GridViewAdapter(MainActivity.this, itemList); gridview.setAdapter(mGridViewAdapter); //設定 GridView 的 Adapter gridview.setOnItemClickListener(GalleryOnItemClickListener);//設定 Item 點擊事件監聽器 } //定義 Item 的 OnClick 事件監聽器 private AdapterView.OnItemClickListener GalleryOnItemClickListener = new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { TextView txtItemTitle = (TextView) view.findViewById(R.id.txtView); mTxtR.setText(txtItemTitle.getText()); } }; . . . } |
MainActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.example.listviewcustomsample.MainActivity" > <TextView android:id="@+id/txtR" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="123" android:textSize="20sp" /> <GridView android:id="@+id/gridview" android:layout_height="wrap_content" android:layout_width="match_parent" /> </RelativeLayout> |
activity_main.xml
1 2 3 4 5 6 7 8 9 10 11 12 |
<resources> . . . <string-array name="region_icon_list"> <item >@drawable/list_view_region_asia</item> <item >@drawable/list_view_region_america</item> <item >@drawable/list_view_region_europe</item> <item >@drawable/list_view_region_oceania</item> </string-array> ... </resources> |
避免 item 介面裡的按鈕事件衝突
做到這裡,如果有將程式碼實際跑過的人會發現,在 MainActivity 中所設定的 AdapterView.OnItemClickListener 事件失效了,這是因為我們為每個 Item 中的 imgView 加入了按鈕事件的緣故,要解決這個問題,我們把觸發按鈕事件的元件之 focusable 設定為false(android:focusable=”false”) 即可。這種現象不僅僅是在 GridVeiw,在同樣以 Adapter 定義資料內容的 Spinner、Gallery 以及 ListView 中,處理方式也是相同的。
臉書留言
一般留言