[Android] การใช้ SimpleAdapter

จากตัวอย่างที่แล้วเราได้ใส่รูปลงใน ListActivity ของเราแล้วแต่ว่าทุกๆรายการเป็นรูปเดียวกันหมด วันนี้เราจะมาสร้าง ListActivity ที่แต่ละรายการสามารถใช้รูปที่แตกต่างกันได้ โดยใช้ SimpleAdapter (ชื่อ Simple แต่ไม่แน่ใจว่า Simple จริงหรือป่าว 555) ก่อนอื่นดูผลลัพธ์โปรแกรมก่อนครับ


activity_main.xml
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@android:id/list"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    />
row.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal"
    android:gravity="center_vertical"
    >
    <ImageView 
        android:id="@+id/img"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginRight="10dp"
        />
 <TextView 
     android:id="@+id/name"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:gravity="center_vertical"
     />    
</LinearLayout>
MainActivity.java
package com.simplelist;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import android.app.ListActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.Toast;

public class MainActivity extends ListActivity {

 final String[] fruit = {"Apple", "Banana", "Coconut", "Durian", "Guava", "Mango", "Mangosteen", "Rambutant"};
 final int[] img = {R.drawable.ico_apple, 
   R.drawable.ico_banana,
   R.drawable.ico_coconut,
   R.drawable.ico_durian,
   R.drawable.ico_guava,
   R.drawable.ico_mango,
   R.drawable.ico_mangosteen,
   R.drawable.ico_rambutant
  };
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  ArrayList<HashMap<String, Object>> listArg = new ArrayList<HashMap<String, Object>>();
  HashMap<String, Object> map = null;
  int i = 0;
  for(String f : fruit){
   map = new HashMap<String, Object>();
   map.put("name", f);
   map.put("img", img[i]);
   listArg.add(map);
   i++;
  }
  SimpleAdapter adapter = new SimpleAdapter(this, listArg, R.layout.row, new String[]{"name", "img"}, new int[]{R.id.name, R.id.img});
  this.setListAdapter(adapter);
 }
 
 @Override
 public void onListItemClick(ListView lv, View v, int position, long id){
  Toast.makeText(this, "You click " + fruit[position], Toast.LENGTH_SHORT).show();
 }

}


ในส่วนของ activity_main.xml นั้นเหมือนกับตัวอย่างก่อนหน้านี้ ในส่วนของ row.xml นั้นสร้าง TextView และ ImageView ภายใต้ LinearLayout โดยกำหนด id ให้เป็น name และ img ตามลำดับ
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal"
    android:gravity="center_vertical"
    >
    <ImageView 
        android:id="@+id/img"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginRight="10dp"
        />
 <TextView 
     android:id="@+id/name"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:gravity="center_vertical"
     />    
</LinearLayout>
ใน activity เราเพิ่ม array int ชื่อ arrImg ขึ้นมาเพื่อเก็บ id ของรูป คู่กับ arrFruit จากนั้นสร้าง ArrayList<HashMap<String, Object>> ชื่อ listArg ขึ้นมาเพื่อเก็บ HashMap ก่อนอื่น Map คืออะไร ถ้าจะให้อธิบายคร่าวๆ ก็คือการเก็บข้อมูลแบบ key : value ครับเพราฉะนั้น <HashMap<String, Object>> ก็คือ Map ที่ key เป็นชนิด String ส่วน value เป็น Object ทำไมเราถึงกำหนด value เป็น Object ? เพราะข้อมูลที่เราจะเก็บมีทั้ง String และ int เราจึงต้องกำหนด value เป็น Object จากนั้นเราวน loop นำค่าของ arrFruit และ arrImg มาสร้าง Map และใส่ลงในตัวแปร listArg
  
  ArrayList<HashMap<String, Object>> listArg = new ArrayList<HashMap<String, Object>>();
  HashMap<String, Object> map = null;
  int i = 0;
  for(String f : arrFruit){
   map = new HashMap<String, Object>();
   map.put("name", f);
   map.put("img", arrImg[i]);
   listArg.add(map);
   i++;
  }

ต่อไปเราจะ new SimpleAdapter กันครับ โดย Parameter ที่ต้องส่งให้มีทั้งหมด 5ตัว
  1. Context
  2. List<? extends Map<String, ?>>
  3. layout id (R.layout.xxxx)
  4. Array String from
  5. Array int to
parameter ตัวแรกเราส่ง this เข้าไป ตัวที่สอง ส่ง listArg ตัวที่สามส่ง R.layout.row (ไฟล์ row.xml) ตัวที่สี่ from เราสร้าง string array ขึ้นมาใหม่หนึ่งตัว โดยอิงจาก key ที่เราใช้ใน HashMap ตัวที่ห้า เราสร้าง int array ขึ้นมาโดยใน Array จะเป็น id ของ view ที่เราจะเอาข้อมูลไปใส่ตามลำดับให้ตรงกับ parameter ตัวที่ 4 เพื่อจะบอกว่าจะต้องนำค่าจาก key ใดไปใส่ใน view id อะไร
  SimpleAdapter adapter = new SimpleAdapter(this, listArg, R.layout.row, new String[]{"name", "img"}, new int[]{R.id.name, R.id.img});
  setListAdapter(adapter);
จากนั้นลองรันดูครับ ก็จะพบว่าหน้าตาจะเป็นไปตามภาพผลลัพธ์ด้านบน จากตัวอย่างนี้เราสามารถใส่รูปให้กับ ListView ของเราให้แตกต่างกันในแต่ละรายการได้ แต่ถ้าเราต้องการที่จะจัดการให้ได้มากกว่านี้ล่ะ มีวิธีอื่นอีกไหม ? ลองมาดูกันในตัวอย่างหน้าการใช้ BaseAdapter