Page 1

27/7/2013

17:48

Co .,

Lt d.

ch04.doc

04

ov is

io n

ListView, ListActivity และ Spinner

Pr

เนื้อหาในบทนี้

การแสดงรายการข้อมูลด้วย ListView

13

การแสดงรายการข้อมูลด้วย ListActivity

การแสดงรายการข้อมูลที่เป็นตัวเลือกแบบ Multiple Choice

20

การตรวจสอบสถานะของตัวเลือกทั้งหมดใน ListView การสร้าง ListView ที่เราออกแบบ Layout ของแต่ละข้อมูลเอง การสร้าง Custom Adapter เพื่อใช้งานกับ ListView

ht

การแสดงรายการข้อมูลด้วย Spinner

Co

py

rig

การสร้าง Spinner ที่เราออกแบบ Layout ของแต่ละข้อมูลเอง

คู่มือเขียนแอพ Android ฉบับรวมโค้ด รายละเอียดเพิ่มเติม: bit.ly/10Bu0B7 97


27/7/2013

17:48

Lt d.

ch04.doc

การแสดงรายการขอมูลดวย ListView

Co .,

ในการเขียนแอพ เรามักต้องทํางานกับกลุ่มของข้อมูลที่มีลักษณะเป็นรายการ (List) อยู่บ่อยครั้ง ซึ่งแอนดรอยด์มีวิวหลายชนิดที่จะช่วยให้เราแสดงผลและทํางานกับข้อมูลเหล่านั้นได้โดยง่าย หนึ่งในนั้น ก็คือ ListView

ตัวอยาง

โปรเจ็ค ListViewDemo, ไฟล res\layout\activity_main.xml

io n

ตั วอย่ า งนี้ จ ะแสดงชื่ อ ประเทศในภู มิ ภ าคอาเซี ย นโดยใช้ ListView ซึ่ งเมื่ อ คลิ ก ชื่ อ ประเทศ ก็จะแสดงข้อความใน TextView 1 กําหนด Layout ของหน้าจอ

ov is

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"

android:layout_height="match_parent" android:orientation="vertical" > <TextView android:id="@+id/text"

Pr

android:layout_width="match_parent"

android:layout_height="wrap_content" android:background="#66ff99" android:gravity="center"

13

android:padding="5dp"

android:text="@string/hello_world" /> <ListView

20

android:id="@+id/list_of_countries" android:layout_width="match_parent" android:layout_height="match_parent" />

2

ht

</LinearLayout>

เพิ่มการประกาศตัวแปรอาร์เรย์ countries ในแอคทิวิตี

rig

โปรเจ็ค ListViewDemo, ไฟล MainActivity.java static final String[] countries = new String[] { "Brunei", "Cambodia", "Indonesia", "Laos", "Malaysia",

Co

py

"Myanmar (Burma)", "Philippines", "Singapore", "Thailand",

98

"Vietnam" };

คู่มือเขียนแอพ Android ฉบับรวมโค้ด รายละเอียดเพิ่มเติม: bit.ly/10Bu0B7


27/7/2013

17:48

เพิ่มโค้ดในเมธอด onCreate ของแอคทิวิตี

3

โปรเจ็ค ListViewDemo, ไฟล MainActivity.java final TextView text = (TextView) findViewById(R.id.text);

Lt d.

ch04.doc

Co .,

ListView list = (ListView) findViewById(R.id.list_of_countries); ArrayAdapter<String> adapter = new ArrayAdapter<String>(

this, android.R.layout.simple_list_item_1, countries); list.setAdapter(adapter);

@Override

io n

list.setOnItemClickListener(new AdapterView.OnItemClickListener() {

public void onItemClick(AdapterView<?> av, View v, int position, long id) {

String msg = "You have selected " + ((TextView) v).getText();

text.setText(msg); } });

Pr

ผลการรัน

ov is

msg += " at position " + String.valueOf(position);

คลิกเมาสคางแลวเลื่อนขึ้น-ลง เพื่อดูขอมูลทั้งหมด

Co

py

rig

ht

20

13

เมื่อรันจะได้หน้าจอที่มี TextView อยู่ด้านบน และพื้นที่ส่วนที่เหลือเป็น ListView โดยสามารถ คลิกเมาส์ค้างที่ ListView เพื่อเลื่อนดูข้อมูล (ชื่อประเทศ) ที่แสดงออกมาไม่ครบ

คู่มือเขียนแอพ Android ฉบับรวมโค้ด ListView, ListActivity และ Spinner รายละเอียดเพิ่มเติม: bit.ly/10Bu0B7

99


27/7/2013

17:48

Lt d.

ch04.doc

Co .,

เมื่อคลิกชื่อประเทศจะแสดงข้อความใน TextView ที่บอกชื่อประเทศที่ถูกคลิก รวมถึงตําแหน่ง ของชื่อประเทศนั้นใน ListView (ชื่อแรกคือตําแหน่งที่ 0)

Pr

ov is

io n

คลิก

คําอธิบาย

Co

py

rig

ht

20

13

การแสดงข้อมูลใน ListView จะใช้ Adapter เป็ นตัวกลางระหว่าง ListView กับแหล่งข้อมู ล กล่าวคือ Adapter จะทําหน้าที่อ่านข้อมูลจากแหล่งข้อมูล แล้วป้อนข้อมูลนั้นให้แก่ ListView เพื่อแสดง ผลออกมา ซึ่ งแหล่ งข้ อมู ลอาจเป็ น อาร์ เรย์ ในหน่ วยความจํ า (เช่ น ตั วอย่ างนี้ ), ฐานข้ อมู ล, ข้ อมู ลจาก เน็ตเวิร์ก/อินเทอร์เน็ต หรืออื่นๆ

100

Adapter

แหลงขอมูล (Data Source) ListView

คู่มือเขียนแอพ Android ฉบับรวมโค้ด รายละเอียดเพิ่มเติม: bit.ly/10Bu0B7


27/7/2013

17:48

Lt d.

ch04.doc

สราง Adapter

ในที่นี้แหล่งข้อมูลของเราคืออาร์เรย์ ดังนั้นเราต้องสร้าง Adapter ชนิด ArrayAdapter ขึ้นมา เป็นตัวกลาง

Co .,

ArrayAdapter<String> adapter = new ArrayAdapter<String>(

this, android.R.layout.simple_list_item_1, countries);

ov is

io n

คอนสตรัคเตอร์ของ ArrayAdapter มีพารามิเตอร์ 3 ตัว พารามิเตอร์ตัวที่ 1 ระบุคอนเท็กซ์ พารามิเตอร์ตัวที่ 2 ระบุ Layout สําหรับไอเท็ม (ข้อมูล) หนึ่งๆใน ListView ซึ่งค่า android.R.layout.simple_list_item_1 ที่เราระบุในที่นี้ คือการอ้างอิงไปยัง Layout ที่แอนดรอยด์เตรียมไว้ให้ ซึ่งเป็น Layout ที่มี TextView อยู่เพียงอันเดียว ดังนั้นชื่อประเทศ แต่ละชื่อจะถูกแสดงอยู่ภายใน TextView ดังรูป TextView TextView

Pr

TextView

พารามิเตอร์ตัวที่ 3 ระบุอาร์เรย์ที่จะแสดงข้อมูลออกมาใน ListView

13

กําหนด Adapter ใหกับ ListView

หลังจากสร้าง Adapter เรียบร้อยแล้ว เราจะนํา Adapter นั้นมากําหนดให้กับ ListView โดยใช้

20

เมธอด setAdapter

list.setAdapter(adapter);

ระบุการทํางานเมื่อไอเท็มใน ListView ถูกคลิก

ht

ขั้ น ตอนนี้ จ ะต้ อ ง Implement อิ น เทอร์ เฟซ AdapterView.OnItemClickListener และระบุ การทํ างานที่ ต้ องการในเมธอด onItemClick จากนั้ นจึ งนํ ามากํ าหนดให้ กั บ ListView โดยใช้ เมธอด

rig

setOnItemClickListener list.setOnItemClickListener(new AdapterView.OnItemClickListener() {

Co

py

@Override public void onItemClick(AdapterView<?> av, View v, int position, long id) { String msg = "You have selected " + ((TextView) v).getText(); msg += " at position " + String.valueOf(position);

คู่มือเขียนแอพ Android ฉบับรวมโค้ด ListView, ListActivity และ Spinner รายละเอียดเพิ่มเติม: bit.ly/10Bu0B7

101


27/7/2013

17:48

Lt d.

ch04.doc

text.setText(msg); } });

การแสดงรายการขอมูลดวย ListActivity

io n

Co .,

เมื่อผู้ใช้คลิกไอเท็มใน ListView แอนดรอยด์จะเรียกมายังเมธอด onItemClick พร้อมทั้งส่งผ่าน ค่ามายังพารามิเตอร์ทั้งสี่ ซึ่งพารามิเตอร์ตัวที่ 2 จะระบุถึงวิวของไอเท็มที่ถูกคลิก (วิวที่ใช้แสดงแต่ละข้อมูล ใน ListView ซึ่ ง ในที่ นี้ คื อ TextView) และพารามิ เตอร์ ตั ว ที่ 3 จะบอกตํ า แหน่ ง ของไอเท็ ม นั้ น ใน ListView (ไอเท็มแรกคือตําแหน่งที่ 0)

ov is

โดยมากเมื่ อนั กพั ฒ นาต้ องการแสดงรายการข้ อมู ล ก็ มักจะสร้างหน้ าจอที่ มี ListView เพี ยง อั น เดี ย วและแสดงผลเต็ ม จอ ด้ ว ยเหตุ นี้ แ อนดรอยด์ จึ ง ได้ เตรี ย มแอคทิ วิ ตี แ บบพิ เศษไว้ ให้ นั่ น คื อ ListActivity ซึ่งเป็นซับคลาสของ Activity อีกทีหนึ่ง แอคทิวิตีชนิดนี้จะมี ListView มาให้ในตัวเลย ช่วยให้เราแสดงรายการข้อมูลและจัดการอีเวนต์ได้สะดวกยิ่งขึ้น

ตัวอยาง

13

Pr

ตั วอย่ างนี้ จะทํ างานคล้ ายตั วอย่ างที่ แล้ ว แต่ ในหน้ าจอจะมี ListView เพี ยงอย่ างเดี ยว (ไม่ มี TextView) ซึ่งเมื่อคลิกไอเท็มใน ListView จะแสดง Toast ออกมาแทน 1 แก้ไขคลาส MainActivity ให้สืบทอดจาก ListActivity แทนที่จะเป็น Activity และเพิ่มการ ประกาศอาร์เรย์ countries ภายในคลาส โปรเจ็ค ListActivityDemo, ไฟล MainActivity.java

20

public class MainActivity extends ListActivity { static final String[] countries = new String[] { "Brunei", "Cambodia", "Indonesia", "Laos", "Malaysia", "Myanmar (Burma)", "Philippines", "Singapore", "Thailand",

ht

"Vietnam" };

...

rig

}

2

ที่เมธอด onCreate ให้ลบบรรทัดที่เรียกเมธอด setContentView และเพิ่มโค้ดดังนี้

โปรเจ็ค ListActivityDemo, ไฟล MainActivity.java

py

@Override

protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);

Co

//setContentView(R.layout.activity_main);

102

คู่มือเขียนแอพ Android ฉบับรวมโค้ด รายละเอียดเพิ่มเติม: bit.ly/10Bu0B7


27/7/2013

17:48

ArrayAdapter<String> adapter = new ArrayAdapter<String>( this, android.R.layout.simple_list_item_1, countries); setListAdapter(adapter);

Co .,

}

เพิ่มเมธอด onListItemClick ในแอคทิวิตี

3

Lt d.

ch04.doc

โปรเจ็ค ListActivityDemo, ไฟล MainActivity.java @Override

protected void onListItemClick(ListView l, View v, int position,

io n

long id) { String msg = "You have selected " + ((TextView) v).getText(); msg += " at position " + String.valueOf(position);

Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();

ov is

}

คลิก

Co

py

rig

ht

20

13

Pr

ผลการรัน

คู่มือเขียนแอพ Android ฉบับรวมโค้ด ListView, ListActivity และ Spinner รายละเอียดเพิ่มเติม: bit.ly/10Bu0B7

103


27/7/2013

17:48

Lt d.

ch04.doc

คําอธิบาย

ov is

io n

Co .,

จุดที่แตกต่างเมื่อเทียบกับตัวอย่างที่แล้วคือ MainActivity สืบทอดจาก ListActivity ไม่ใช่ Activity ในเมธอด onCreate ไม่มีการเรียกเมธอด setContentView เพื่อกําหนด Layout ของหน้าจอ เนื่องจาก ListActivity จะเตรียม Layout มาให้แล้ว และเป็น Layout ที่มี ListView เพียงอย่างเดียว การกําหนด Adapter ให้กับ ListView จะใช้เมธอด setListAdapter ของ ListActivity แทนการใช้เมธอด setAdapter ของ ListView การระบุการทํางานเมื่อไอเท็มใน ListView ถูกคลิก จะทําได้โดย Override เมธอด OnListItemClick ของ ListActivity แทนการ Implement อินเทอร์เฟส AdapterView. OnItemClickListener และระบุการทํางานในเมธอด onItemClick

ตองการใช ListActivity และกําหนด Layout เองดวย

Pr

ถ้ าหากคุ ณ ต้ อ งการใช้ งาน ListActivity และขณะเดี ยวกั น ก็ ต้ อ งการกํ าหนด Layout เอง ก็สามารถทําได้เช่นกัน แต่มีเงื่อนไขคือ จะต้องสร้าง ListView ที่มี ID เป็น @android:id/list ไว้ภายใน Layout นั้ น เช่ น ถ้ าจะออกแบบหน้ าจอเหมื อ นตั วอย่ างที่ แล้ ว (มี TextView อยู่ ด้ านบน) ให้ กํ าหนด Layout ดังนี้ โปรเจ็ค ListActivityDemo, ไฟล res\layout\activity_main.xml

13

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"

20

android:orientation="vertical" > <TextView

android:id="@+id/text" android:layout_width="match_parent"

ht

android:layout_height="wrap_content" android:background="#66ff99" android:gravity="center"

rig

android:padding="5dp" android:text="@string/hello_world" />

<ListView

py

android:id="@android:id/list" android:layout_width="match_parent" android:layout_height="match_parent" />

Co

</LinearLayout>

104

คู่มือเขียนแอพ Android ฉบับรวมโค้ด รายละเอียดเพิ่มเติม: bit.ly/10Bu0B7


27/7/2013

17:48

Lt d.

ch04.doc

Co .,

จากนั้ น ในเมธอด onCreate ให้ เรี ยก setContentView เพื่ อ กํ าหนด Layout ให้ กั บ แอคทิ วิ ตี ตามปกติ แต่เมื่อต้องการเข้าถึง ListView ให้ใช้เมธอด getListView แทนการใช้เมธอด findViewById (ดูตัวอย่างในหัวข้อถัดไป) สํ าหรับการผู ก Adapter และระบุ การทํ างานเมื่ อไอเท็ มถู กคลิ กนั้ นสามารถใช้ ตามตั วอย่ างนี้ ต่ อ ไปได้ (ไม่ ต้ อ งแก้ ไ ขกลั บ ไปเหมื อ นตั ว อย่ า งที่ แล้ ว ) ซึ่ ง จะมี ผลกั บ ListView ที่ มี ID เป็ น @android:id/list โดยอัตโนมัติ

io n

การแสดงรายการขอมูลที่เปนตัวเลือกแบบ Multiple Choice

ov is

เราสามารถใช้ ListView ในการแสดงรายการตัวเลือกแบบ Multiple Choice ได้ ซึ่งหมายถึ ง รายการตัวเลือกที่อนุญาตให้ผู้ใช้เลือกได้หลายตัวเลือกพร้อมกัน ดังตัวอย่างต่อไปนี้

ตัวอยางและคําอธิบาย

20

13

Pr

ตัวอย่างนี้จะดัดแปลงจากตัวอย่างที่แล้ว โดยสมมติว่าต้องการแสดงหน้าจอให้ผู้ใช้เลือกชื่อประเทศ ต่ างๆได้ ม ากกว่ า 1 ประเทศ ดั งรู ป ซึ่ งแต่ ล ะครั้ ง ที่ ค ลิ ก เลื อ ก (select) หรื อ คลิ ก ยกเลิ ก (deselect) ก็ จะแสดง Toast ออกมา ตรงนี้ จะทํ าให้ คุ ณ เห็ น วิ ธีก ารเขี ยนโค้ ดเพื่ อตรวจสอบสถานะของตั วเลื อ ก ขณะเกิดอีเวนต์

แก้ไขคลาส MainActivity ให้สืบทอดจาก ListActivity แทนที่จะเป็น Activity และเพิ่มการ ประกาศอาร์เรย์ countries ภายในคลาส

1

ht

โปรเจ็ค ListMultipleChoiceDemo, ไฟล MainActivity.java

rig

public class MainActivity extends ListActivity {

py

static final String[] countries = new String[] { "Brunei", "Cambodia", "Indonesia", "Laos", "Malaysia", "Myanmar (Burma)", "Philippines", "Singapore", "Thailand", "Vietnam" };

...

Co

}

คู่มือเขียนแอพ Android ฉบับรวมโค้ด ListView, ListActivity และ Spinner รายละเอียดเพิ่มเติม: bit.ly/10Bu0B7

105


27/7/2013

17:48

ที่เมธอด onCreate ให้ลบบรรทัดที่เรียกเมธอด setContentView และเพิ่มโค้ดดังนี้

2

โปรเจ็ค ListMultipleChoiceDemo, ไฟล MainActivity.java @Override

Lt d.

ch04.doc

super.onCreate(savedInstanceState); //setContentView(R.layout.activity_main); ListView list = getListView();

list.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);

Co .,

protected void onCreate(Bundle savedInstanceState) {

io n

ArrayAdapter<String> adapter = new ArrayAdapter<String>(

this, android.R.layout.simple_list_item_checked, countries); setListAdapter(adapter);

}

ใช้เมธอด getListView เข้าถึง ListView ที่ ListActivity เตรียมมาให้ ใช้เมธอด setChoiceMode กําหนดรูปแบบการเลือกของ ListView เป็นแบบ CHOICE_MODE_MULTIPLE คือเป็นตัวเลือกที่สามารถเลือกได้หลายตัวเลือกพร้อมกัน  สร้าง ArrayAdapter โดยกําหนด Layout ของแต่ละไอเท็มใน ListView เป็นแบบ simple_list_item_checked ซึ่งก็คือ CheckedTextView ที่มีข้อความอยู่ทางซ้าย และเครื่องหมายเช็คถูกอยู่ทางขวา  กําหนด ArrayAdapter ให้กับ ListView เพิ่มเมธอด onListItemClick ในแอคทิวิตี เพื่อระบุการทํางานเมื่อผู้ใช้คลิกไอเท็มใน ListView

3

13

Pr

ov is

 

@Override

20

โปรเจ็ค ListMultipleChoiceDemo, ไฟล MainActivity.java protected void onListItemClick(ListView l, View v, int position, long id) { String msg;

ht

CheckedTextView check = (CheckedTextView) v; if (check.isChecked()) {

msg = "You have selected " + check.getText();

rig

}

else {

msg = "You have deselected " + check.getText();

}

py

msg += " at position " + String.valueOf(position); Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();

Co

}

106

คู่มือเขียนแอพ Android ฉบับรวมโค้ด รายละเอียดเพิ่มเติม: bit.ly/10Bu0B7


27/7/2013

17:48

Lt d.

ch04.doc

Co .,

เราทราบแล้วว่า วิวของไอเท็มที่ถูกคลิกจะส่งผ่านมายังพารามิเตอร์ตัวที่สอง (v) ซึ่งในตัวอย่างนี้วิว ของแต่ละไอเท็มคือ CheckedTextView ก่อนอื่นเราจึงแปลง (cast) ค่าของ v เป็นชนิดวิวดังกล่าว  จากนั้นตรวจสอบสถานะการเลือกของมันโดยใช้เมธอด isChecked  เพื่อสร้างข้อความ เก็บไว้ในตัวแปร msg ให้เหมาะสม แล้วแสดงข้อความนั้นออกมาใน Toast 

ov is

คลิก

io n

ผลการรัน

คลิก

13

Pr

คลิก

การตรวจสอบสถานะของตัวเลือกทั้งหมดใน ListView

20

ในตัวอย่างที่แล้ว เราตรวจสอบสถานะของตัวเลือกที่ทําให้เกิดอีเวนต์เท่านั้น แต่บางครั้งเราอาจ ปล่อยให้ผู้ใช้เลือกไปก่อน แล้วค่อยตรวจสอบสถานะของตัวเลือกทั้งหมดทีเดียว เช่น หลังจากผู้ใช้คลิกปุ่ม OK เป็นต้น

ht

ตัวอยางและคําอธิบาย

rig

เราจะปรับปรุงตัวอย่างที่แล้ว โดยเพิ่มปุ่มไว้ด้านบน ซึ่งเมื่อคลิกปุ่มนี้จะตรวจสอบสถานะของ ตัวเลือกทั้งหมดใน ListView แล้วแสดง Toast ออกมา 1 กําหนด Layout ของหน้าจอ

py

โปรเจ็ค ListMultipleChoiceDemo, ไฟล res\layout\activity_main.xml

Co

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"

คู่มือเขียนแอพ Android ฉบับรวมโค้ด ListView, ListActivity และ Spinner รายละเอียดเพิ่มเติม: bit.ly/10Bu0B7

107


27/7/2013

17:48

Lt d.

ch04.doc

android:orientation="vertical" > <ListView android:id="@android:id/list" android:layout_width="match_parent"

Co .,

android:layout_height="0dp" android:layout_weight="1" /> <Button android:id="@+id/button" android:layout_width="match_parent" android:text="Show selected items" /> </LinearLayout>

2

เพิ่มโค้ดในเมธอด onCreate

ov is

โปรเจ็ค ListMultipleChoiceDemo, ไฟล MainActivity.java

io n

android:layout_height="wrap_content"

@Override

protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);

Pr

setContentView(R.layout.activity_main); ListView list = getListView();

list.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);

13

ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_checked, countries); setListAdapter(adapter);

//

20

Button button = (Button) findViewById(R.id.button);

ระบุการทํางานเมื่อปุมถูกคลิก

button.setOnClickListener(new View.OnClickListener() { @Override

ht

public void onClick(View v) { ListView list = getListView();

rig

String msg = "Selected items:";

Co

py

for (int i = 0; i < list.getCount(); i++) {

108

if (list.isItemChecked(i)) {

msg += "\n" + list.getItemAtPosition(i);

}

}

คู่มือเขียนแอพ Android ฉบับรวมโค้ด รายละเอียดเพิ่มเติม: bit.ly/10Bu0B7


27/7/2013

17:48

Lt d.

ch04.doc

Toast.makeText(MainActivity.this, msg, Toast.LENGTH_LONG) .show();

} });

Co .,

}

ov is

io n

เราเรียกเมธอด setContentView เพื่อกําหนด Layout ของหน้าจอ  เพราะก่อนหน้านี้เราไม่ได้ กําหนด Layout เอง แต่ใช้ Layout ที่ ListActivity เตรียมไว้ให้ ซึ่งทั้งหน้าจอจะมี ListView เพียงอย่างเดียว โค้ดส่วนที่เหลือที่เพิ่มเข้ามาคือการระบุการทํางานเมื่อปุ่มถูกคลิก โดยใช้เมธอด isItemChecked ตรวจสอบสถานะการเลือกของแต่ละไอเท็มใน ListView  ถ้าไอเท็มใดมีสถานะเป็น true (ถูกเลือก) ก็จะใช้เมธอด getItemAtPosition อ่านข้อมูลของไอเท็มนั้นมาเก็บลงตัวแปร msg  เพื่อแสดงเป็น Toast ออกมาในตอนท้าย 

ผลการรัน

คลิก

Co

py

rig

ht

20

13

Pr

ลองคลิกเลือกชื่อประเทศต่างๆ เสร็จแล้ว คลิกปุ่ม Show selected items ข้างล่าง

คู่มือเขียนแอพ Android ฉบับรวมโค้ด ListView, ListActivity และ Spinner รายละเอียดเพิ่มเติม: bit.ly/10Bu0B7

109


27/7/2013

17:48

การสราง ListView ที่เราออกแบบ Layout ของแตละขอมูลเอง

Lt d.

ch04.doc

Co .,

ที่ผ่านมาเรากําหนดรูปแบบการแสดงผลของไอเท็มใน ListView โดยใช้ Layout ที่แอนดรอยด์ เตรียมมาให้ ได้แก่ android.R.layout.simple_list_item_1 (TextView อันเดียว) และ android.R. layout.simple_list_item_checked (CheckedTextView อั น เดี ย ว) แต่ น อกจากนี้ แอนดรอยด์ ยั ง อนุญาตให้กําหนด Layout โดยใช้ Layout File ที่เราสร้างขึ้นเองได้ด้วย หรือเรียกว่า Custom ListView

ตัวอยางและคําอธิบาย โปรเจ็ค CustomListViewDemo, ไฟล res\layout\item.xml

io n

1

ตัวอย่างนี้จะแสดงชื่อประเทศใน ListView โดยมีรูปสัญลักษณ์ของอาเซียนอยู่หน้าชื่อทุกประเทศ กําหนด Layout สําหรับแต่ละไอเท็มใน ListView (ไฟล์ item.xml)

ov is

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"

android:layout_height="match_parent" android:gravity="center_vertical" > <ImageView

android:layout_width="wrap_content"

Pr

android:layout_height="wrap_content" android:layout_margin="5dp"

android:src="@drawable/asean_logo" />

13

<TextView

android:id="@+id/country_name" android:layout_width="0dp"

android:layout_height="wrap_content"

asean_logo.png

20

android:layout_marginLeft="5dp" android:layout_weight="1" android:textSize="20sp" />

ht

</LinearLayout>

TextView

Co

py

rig

ImageView

110

คู่มือเขียนแอพ Android ฉบับรวมโค้ด รายละเอียดเพิ่มเติม: bit.ly/10Bu0B7


27/7/2013

17:48

Lt d.

ch04.doc

แก้ไขคลาส MainActivity ให้สืบทอดจาก ListActivity แทนที่จะเป็น Activity และเพิ่มการ ประกาศอาร์เรย์ countries ภายในคลาส

2

public class MainActivity extends ListActivity { static final String[] countries = new String[] {

Co .,

โปรเจ็ค CustomListViewDemo, ไฟล MainActivity.java

"Brunei", "Cambodia", "Indonesia", "Laos", "Malaysia",

"Myanmar (Burma)", "Philippines", "Singapore", "Thailand", "Vietnam" };

io n

... }

ที่เมธอด onCreate ให้ลบบรรทัดที่เรียกเมธอด setContentView และเพิ่มโค้ดดังนี้

3

ov is

โปรเจ็ค CustomListViewDemo, ไฟล MainActivity.java @Override

protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);

//setContentView(R.layout.activity_main);

Pr

ArrayAdapter<String> adapter = new ArrayAdapter<String>( this, R.layout.item, R.id.country_name, countries); setListAdapter(adapter);

13

}

Co

py

rig

ht

20

เมื่อต้องการกําหนด Layout ของแต่ละไอเท็มเอง จะต้องสร้าง ArrayAdapter โดยระบุพารามิเตอร์ 4 ตัว ซึ่งพารามิเตอร์ตัวที่สองจะระบุถึง Layout File (ไฟล์ item.xml) และพารามิเตอร์ตัวที่สาม จะระบุถึงวิวใน Layout File นั้น ที่ใช้แสดงไอเท็มหนึ่งๆ ArrayAdapter จะอ่านข้อมูลจากอาร์เรย์ countries แล้วใส่ข้อมูลลงใน TextView (R.id.country_name) ภายใน Layout File ที่กําหนด (R.layout.item) ดังรูปหน้าถัดไป

คู่มือเขียนแอพ Android ฉบับรวมโค้ด ListView, ListActivity และ Spinner รายละเอียดเพิ่มเติม: bit.ly/10Bu0B7

111


27/7/2013

17:48

Layout ของแตละไอเท็มใน ListView กําหนดดวยไฟล item.xml (R.layout.item)

Brunei Cambodia Indonesia Loas ...

Thailand Vietnam

TextView (R.id.country_name)

อารเรย countries

io n

ListView

Co .,

Array Adapter

Lt d.

ch04.doc

NOTE

ov is

ความจริง ArrayAdapter จะตอง Inflate Layout สําหรับแตละไอเท็มขึ้นมาจากไฟล item.xml ดวย กอนที่ จะใสขอมูลลงใน TextView ที่เปนสวนหนึ่งของ Layout นั้น แลวสง Layout ให ListView นําไปแสดงผล ซึ่งในหัวขอถัดไปคุณจะไดเห็นการทํางานที่วานี้ เพราะเราจะสราง Adapter ในแบบของเราขึ้นมาเอง (Custom Adapter)

เพิ่มเมธอด onListItemClick ในแอคทิวิตี เพื่อระบุการทํางานเมื่อผู้ใช้คลิกไอเท็มใน ListView

4

Pr

โปรเจ็ค CustomListViewDemo, ไฟล MainActivity.java @Override

protected void onListItemClick(ListView l, View v, int position, long id) {

13

TextView tv = (TextView) v.findViewById(R.id.country_name); String msg = "You have selected " + tv.getText();

20

msg += " at position " + String.valueOf(position); Toast.makeText(this, msg, Toast.LENGTH_SHORT).show(); }

Co

py

rig

ht

วิธีเขียนโค้ดในเมธอด onListItemClick จะแตกต่างไปจากเดิมเล็กน้อย เนื่องจากค่าที่ส่งผ่านมายัง พารามิเตอร์ v ไม่ใช่ TextView หรือ CheckedTextView แต่เป็น LinearLayout ที่บรรจุ ImageView กับ TextView ไว้ตามที่เรากําหนดในไฟล์ item.xml ดังนั้นจึงต้องเรียกใช้เมธอด findViewById บนพารามิเตอร์ v นี้เพื่อเข้าถึง TextView ให้ได้ก่อน  แล้วค่อยใช้เมธอด getText อ่านชื่อประเทศมาอีกที 

112

คู่มือเขียนแอพ Android ฉบับรวมโค้ด รายละเอียดเพิ่มเติม: bit.ly/10Bu0B7


27/7/2013

17:48

Lt d.

ch04.doc

ov is

io n

คลิก

Co .,

ผลการรัน

Pr

การสราง Custom Adapter เพื่อใชงานกับ ListView

20

13

จากตั วอย่ างที่ ผ่ านมา มี คํ าถามว่าถ้ าหากต้ องการแสดงรู ปธงชาติ ของแต่ ละประเทศแทนรู ป สัญลักษณ์อาเซียนจะทําได้อย่างไร? ArrayAdapter มี ข้ อจํ ากั ดตรงที่ มั นจะอ่ านข้ อมู ลจากอาร์ เรย์ แล้ วใส่ ข้ อมู ลลงในวิ วหนึ่ งๆภายใน Layout เท่านั้น ดังนั้นถ้าหากมีข้อมูลมากกว่า 1 ชิ้นที่จะใส่ลงในวิวมากกว่า 1 วิวสําหรับแต่ละไอเท็ม เช่น การแสดงทั้งชื่อประเทศและรูปธงชาติของแต่ละประเทศดังที่กล่าวข้างต้น กรณีอย่างนี้ ArrayAdapter จะทําไม่ได้ ทางออกคือเราต้องสร้าง Adapter ในแบบของเราขึ้นมาเอง (Custom Adapter)

ตัวอยางและคําอธิบาย

Co

py

rig

ht

ตัวอย่างนี้จะสร้าง Custom Adapter โดยสืบทอดจาก ArrayAdapter เพื่อที่เราจะดัดแปลงการ ทํางานของมันให้มีการอ่านชื่อประเทศและรูปธงชาติจากอาร์เรย์ แล้วนํามากําหนดลงใน TextView และ ImageView ภายใน Layout ของแต่ละไอเท็ม ตามลําดับ ก่อนอื่นขอให้ดูภาพอธิบายการทํางานของตัวอย่างนี้ ซึ่งจะทําให้คุณเข้าใจโค้ดง่ายขึ้น

คู่มือเขียนแอพ Android ฉบับรวมโค้ด ListView, ListActivity และ Spinner รายละเอียดเพิ่มเติม: bit.ly/10Bu0B7

113


27/7/2013

17:48

Lt d.

ch04.doc

Layout ของแตละไอเท็มใน ListView กําหนดดวยไฟล item.xml (R.layout.item)

Co .,

TextView (R.id.country_name)

ออบเจ็ค Country ออบเจ็ค Country

อารเรย countries

io n

ImageView (R.id.flag_image)

ListView

...

Custom Adapter

ออบเจ็ค Country ออบเจ็ค Country ออบเจ็ค Country ออบเจ็ค Country

Pr

ov is

ออบเจ็ค Country จะเก็บชื่อและ ID ของรูปธงชาติของประเทศหนึ่งๆไว้ ซึ่งโค้ดภายนอกสามารถ อ่ านข้ อมู ลทั้ งสองจากออบเจ็ คมาใช้ งานได้ โดยเรี ยกเมธอด getCountryName และ getFlagImageId ตามลําดับ Custom Adapter จะ Inflate Layout ของแต่ ล ะไอเท็ ม ขึ้ น มาจากไฟล์ item.xml แล้ ว อ่ า น ข้ อ มู ล ทั้ ง สองจากออบเจ็ ค Country หนึ่ ง ๆมากํ า หนดลงใน TextView (R.id.country_name) และ ImageView (R.id.flag_image) ภายใน Layout นั้น ดังรูป

getCountryName

20

13

Array Adapter

ไอเท็มหนึ่งใน ListView

Thailand R.drawable.thailand

ออบเจ็ค Country หนึ่งๆ

กําหนด Layout สําหรับแต่ละไอเท็มใน ListView (ไฟล์ item.xml)

ht

1

getFlagImageId

โปรเจ็ค CustomAdapterDemo, ไฟล res\layout\item.xml

rig

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"

py

android:gravity="center_vertical" >

Co

<ImageView

114

android:id="@+id/flag_image" android:layout_width="wrap_content"

คู่มือเขียนแอพ Android ฉบับรวมโค้ด รายละเอียดเพิ่มเติม: bit.ly/10Bu0B7


27/7/2013

17:48

Lt d.

ch04.doc

android:layout_height="wrap_content" android:layout_margin="8dp" /> <TextView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginLeft="5dp" android:layout_weight="1" android:textSize="20sp" /> </LinearLayout>

Co .,

android:id="@+id/country_name"

โปรเจ็ค CustomAdapterDemo, ไฟล Country.java public class Country { private int m_flagImageId;

ov is

package com.example.customadapter;

คอนสตรัคเตอร

ของรูปธงชาติ ชื่อประเทศ

// ID

private String m_countryName; // //

io n

สร้างคลาสใหม่ชื่อ Country (คลิกขวาที่ชื่อโปรเจ็คNewClass) แล้วพิมพ์โค้ดดังนี้

2

Pr

public Country(int flagImageId, String countryName) { m_flagImageId = flagImageId; m_countryName = countryName; }

สําหรับ ID ของรูปธงชาติ

13

// Getter Method

public int getFlagImageId() { return m_flagImageId;

20

}

// Setter Method

สําหรับ ID ของรูปธงชาติ

public void setFlagImageId(int flagImageId) { m_flagImageId = flagImageId;

ht

}

// Getter Method

สําหรับชื่อประเทศ

public String getCountryName() {

rig

return m_countryName;

}

py

// Setter Method

สําหรับชื่อประเทศ

public void setCountryName(String countryName) { m_countryName = countryName; }

Co

}

คู่มือเขียนแอพ Android ฉบับรวมโค้ด ListView, ListActivity และ Spinner รายละเอียดเพิ่มเติม: bit.ly/10Bu0B7

115


27/7/2013

17:48

Lt d.

ch04.doc

Co .,

3

คลาส Country คือต้นแบบที่ใช้สร้างออบเจ็ค Country สําหรับเก็บชื่อและ ID ของรูปธงชาติของ ประเทศหนึ่งๆ การสร้างออบเจ็คของคลาสนี้จะต้องระบุพารามิเตอร์ให้คอนสตรัคเตอร์ 2 ตัวคือ ID ของรูปธงชาติและชื่อประเทศ ซึ่งคอนสตรัตเตอร์จะนําค่าของพารามิเตอร์ทั้งสองไปเก็บลงฟีลด์ m_flagImageId และ m_countryName ของคลาส ตามลําดับ ฟีลด์ทั้งสองเป็น private ดังนั้น ภายนอกจึงเข้าถึงโดยตรงไม่ได้ แต่จะต้องเข้าถึงผ่านทาง Getter Method และ Setter Method ที่คลาสเตรียมไว้เท่านั้น สร้างคลาสใหม่ชื่อ CountryAdapter แล้วพิมพ์โค้ดดังนี้ โปรเจ็ค CustomAdapterDemo, ไฟล CountryAdapter.java

io n

package com.example.customadapter; import android.app.Activity; import android.content.Context; import android.view.View; import android.view.ViewGroup;

ov is

import android.view.LayoutInflater;

import android.widget.ArrayAdapter; import android.widget.ImageView;

Pr

import android.widget.TextView;

public class CountryAdapter extends ArrayAdapter<Country> { private Context context;

13

private int itemLayoutId;

private Country countries[] = null; //

คอนสตรัคเตอร

20

public CountryAdapter(Context context, int itemLayoutId, Country[] countries) {

super(context, itemLayoutId, countries); this.itemLayoutId = itemLayoutId;

ht

this.context = context;

this.countries = countries;

rig

}

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

Co

py

LayoutInflater inflater = ((Activity) context).getLayoutInflater();

116

View item = inflater.inflate(itemLayoutId, parent, false);

คู่มือเขียนแอพ Android ฉบับรวมโค้ด รายละเอียดเพิ่มเติม: bit.ly/10Bu0B7


27/7/2013

17:48

ImageView imgFlag = (ImageView) item.findViewById(R.id.flag_image); TextView txtCountryName =

Lt d.

ch04.doc

Country country = countries[position];

Co .,

(TextView) item.findViewById(R.id.country_name);

imgFlag.setImageResource(country.getFlagImageId());

txtCountryName.setText(country.getCountryName()); return item;

io n

} }

4

ht

20

13

Pr

ov is

คลาส CountryAdapter นี้คือ Custom Adapter ของเรา ซึ่งสืบทอดจากคลาส ArrayAdapter ของแอนดรอยด์ และระบุว่า Adapter นี้จะทํางานกับข้อมูลชนิด Country (ออบเจ็ค Country)  เราออกแบบให้คอนสตรัคเตอร์ของ CountryAdapter มีพารามิเตอร์ 3 ตัวเช่นเดียวกับ ArrayAdapter นั่นคือ คอนเท็กซ์ของแอพ, ID ที่ระบุ Layout สําหรับไอเท็มหนึ่งๆ และอาร์เรย์ที่ เก็บข้อมูลทั้งหมดไว้ คอนสตรัคเตอร์จะเก็บค่าทั้งสามนี้ลงในฟีลด์แบบ private ของคลาส  ส่วนสําคัญที่สุดในคลาส CountryAdapter ก็คือการ Override เมธอด getView เพื่อให้ทํางานใน แบบที่เราต้องการ ซึ่ง ListView จะเรียกมายังเมธอดนี้เพื่อรับวิวที่มีข้อมูลเรียบร้อยแล้วสําหรับ แต่ละไอเท็มกลับไปแสดงผล และเรียกเมธอดนี้ซ้ําๆจนครบทุกไอเท็ม โดยพารามิเตอร์ position จะบอกให้รู้ว่าตอนนั้น ListView ต้องการไอเท็มที่ตําแหน่งใด ดังนั้นเราต้องเขียนโค้ดในเมธอด getView ให้สอดคล้องกับการทํางานดังกล่าว ในที่นี้เรา Inflate วิวหรือ Layout ของไอเท็มขึ้นมาจากไฟล์ item.xml  จากนั้นเข้าถึง ImageView และ TextView ภายในวิวนั้น  ก่อนจะอ่านข้อมูลจากออบเจ็ค Country หนึ่งๆใน อาร์เรย์ countries (ตาม position ที่ ListView ระบุมา)  มากําหนดให้กับวิวทั้งสอง  แล้วจึง return วิวของไอเท็มกลับไป  แก้ไขคลาส MainActivity ให้สืบทอดจาก ListActivity แทนที่จะเป็น Activity และเพิ่มโค้ด ดังนี้

rig

โปรเจ็ค CustomAdapterDemo, ไฟล MainActivity.java @Override protected void onCreate(Bundle savedInstanceState) {

Co

py

super.onCreate(savedInstanceState); // setContentView(R.layout.activity_main);

คู่มือเขียนแอพ Android ฉบับรวมโค้ด ListView, ListActivity และ Spinner รายละเอียดเพิ่มเติม: bit.ly/10Bu0B7

117


27/7/2013

//

17:48

สรางอารเรย countries ซึ่งมีสมาชิกเปนออบเจ็ค Country ที่เก็บขอมูลของแตละประเทศ

Country countries[] = new Country[] { new Country(R.drawable.cambodia, "Cambodia"),

Co .,

new Country(R.drawable.brunei, "Brunei"),

Lt d.

ch04.doc

new Country(R.drawable.indonesia, "Indonesia"), new Country(R.drawable.laos, "Laos"), new Country(R.drawable.malaysia, "Malaysia"),

new Country(R.drawable.myanmar, "Myanmar (Burma)"), new Country(R.drawable.philippines, "Philippines"), new Country(R.drawable.singapore, "Singapore"),

io n

new Country(R.drawable.thailand, "Thailand"),

new Country(R.drawable.vietnam, "Vietnam"), }; //

สราง Adapter

Object

และนําไปกําหนดให ListView

ov is

CountryAdapter adapter = new CountryAdapter(this, R.layout.item, countries);

setListAdapter(adapter); }

เพิ่มเมธอด onListItemClick ในแอคทิวิตี เพื่อระบุการทํางานเมื่อผู้ใช้คลิกไอเท็มใน ListView

5

Pr

โปรเจ็ค CustomAdapterDemo, ไฟล MainActivity.java @Override

protected void onListItemClick(ListView l, View v, int position, long id) {

13

TextView tv = (TextView) v.findViewById(R.id.country_name); String msg = "You have selected " + tv.getText();

20

msg += " at position " + String.valueOf(position); Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();

Co

py

rig

ht

}

118

คู่มือเขียนแอพ Android ฉบับรวมโค้ด รายละเอียดเพิ่มเติม: bit.ly/10Bu0B7


27/7/2013

17:48

Lt d.

ch04.doc

Co .,

ผลการรัน

Pr

ปรับปรุงประสิทธิภาพของ ListView

ov is

io n

คลิก

20

13

ตัวอย่างที่ผ่านมาถึงแม้จะทํางานได้สมบูรณ์ แต่ถ้าหาก ListView มีไอเท็มอยู่จํานวนมากจะทําให้ สิ้นเปลืองทรัพยากรของระบบและส่งผลต่อประสิทธิภาพของแอพ เนื่องจากจะมีการ Inflate วิวขึ้นมาจาก ไฟล์ item.xml สําหรับทุกๆไอเท็มใน ListView เช่นในที่นี้มี 10 ไอเท็ม (10 ประเทศ) ก็จะ Inflate ขึ้นมา 10 วิว ซึ่งหากมี 100 ไอเท็มก็จะ Inflate 100 วิว ทั้งที่มีไอเท็มแค่จํานวนหนึ่งเท่านั้นที่ถูกแสดงออกมา ในขณะหนึ่งๆ (ในตัวอย่างนี้คือ 7 ไอเท็ม) เพื่อแก้ปัญหานี้ แอนดรอยด์จึงมีวิธีให้เรานําวิวของไอเท็มที่เคยสร้างไว้แล้วกลับมาใช้ซ้ําได้ ในกรณี ที่ไอเท็มนั้นไม่ถูกแสดงออกมา ให้คุณแก้ไขเมธอด getView ในคลาส CountryAdapter รวมทั้งเพิ่มคลาส CountryHolder ไว้ภายในคลาส CountryAdapter ดังนี้

ht

โปรเจ็ค CustomAdapterDemo, ไฟล CountryAdapter.java @Override

rig

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

Co

py

CountryHolder holder = null; if (item == null) {

LayoutInflater inflater = ((Activity) context).getLayoutInflater(); item = inflater.inflate(itemLayoutId, parent, false);

คู่มือเขียนแอพ Android ฉบับรวมโค้ด ListView, ListActivity และ Spinner รายละเอียดเพิ่มเติม: bit.ly/10Bu0B7

119


27/7/2013

holder = new CountryHolder();

17:48

holder.imgFlag = (ImageView) item.findViewById(R.id.flag_image); holder.txtCountryName =

Lt d.

ch04.doc

item.setTag(holder);

} else { holder = (CountryHolder) item.getTag();

Country country = countries[position];

io n

}

Co .,

(TextView) item.findViewById(R.id.country_name);

holder.imgFlag.setImageResource(country.getFlagImageId()); holder.txtCountryName.setText(country.getCountryName());

// Inner Class

ov is

return item; }

สําหรับเก็บการอางอิงของ ImageView และ TextView

static class CountryHolder { ImageView imgFlag;

Pr

TextView txtCountryName; }

ht

20

13

เมื่อ ListView เรียกมายังเมธอด getView มันจะส่งวิวของไอเท็มที่เราสามารถใช้ซ้ําได้มาทาง พารามิเตอร์ convertView ดังนั้นก่อนอื่นเราจะตรวจสอบพารามิเตอร์นี้ ซึ่งถ้าเป็น null (ไม่มีวิว ที่ใช้ซ้ําได้)  เราก็จะ Inflate วิวจาก Layout File ตามปกติ  แล้วสร้าง Holder object (ออบเจ็ค CountryHolder)  เพื่ออ้างอิง ImageView และ TextView ภายในวิวที่เพิ่ง Inflate ขึ้นมา  แล้วแนบ Holder object ไปกับวิวนั้นโดยใช้เมธอด setTag  แต่ถ้าพารามิเตอร์ convertView ไม่เป็น null (มีวิวที่ใช้ซ้ําได้) เราจะใช้เมธอด getTag เข้าถึง Holder object ที่แนบมากับวิว  เพื่อกําหนดข้อมูลลงใน ImageView และ TextView ที่ Holder object นั้นเก็บไว้ แทนที่จะ Inflate ขึ้นมาใหม่จาก Layout File

Custom Adapter กับ Layout ที่ซับซอนยิ่งขึ้น

Co

py

rig

ด้วยหลักการที่อธิบายไปแล้ว การสร้าง ListView ที่มีความซับซ้อนดังรูปต่อไปนี้ก็ไม่ใช่เรื่องยาก อีกต่อไป สิ่งที่คุณต้องทําเพิ่มโดยหลักๆคือ ออกแบบ Layout ของไอเท็ม (ไฟล์ item.xml) ให้มีวิวสําหรับ แสดงข้อมูลที่เพิ่มเข้ามา (ในรูปเพิ่มชื่อที่เป็นทางการ กับชื่อเมืองหลวงของประเทศ), เพิ่มฟีลด์เก็บข้อมูล รวมถึ ง Setter/Getter Method ในคลาส Country และเพิ่ มโค้ ดใน CountryAdapter ที่ จะอ่ านข้ อมู ล จากออบเจ็ค Country มาใส่ลงในวิวที่เพิ่มมาใน Layout

120

คู่มือเขียนแอพ Android ฉบับรวมโค้ด รายละเอียดเพิ่มเติม: bit.ly/10Bu0B7


27/7/2013

17:48

ov is

io n

Co .,

Lt d.

ch04.doc

Pr

ขอฝากเป็นการบ้านให้ผู้อ่านลองทําดูครับ สําหรับโค้ดที่สมบูรณ์ของตัวอย่างตามรูปข้างบนนี้อยู่ใน โปรเจ็ค CustomAdapterDemo2 ในซอร์สโค้ด

13

การแสดงรายการขอมูลดวย Spinner

คือวิวที่เอาไว้แสดงรายการข้อมูลเช่นเดียวกับ ListView แต่จะใช้พื้นที่หน้าจอน้อยกว่า โดยในสถานะปกติจะแสดงเฉพาะไอเท็มที่ถูกเลือก แต่หากเราคลิกที่ตัว Spinner ก็จะแสดงไอเท็มทั้งหมด ออกมา (ถ้ าแสดงไม่ ห มดก็ ส ามารถเลื่ อ นดู ได้ เช่ น เดี ยวกั บ ListView) ลั ก ษณะของมั น จะเหมื อ นกั บ Drop-down Listbox ที่พบใน Windows และระบบปฏิบัติการต่างๆบนพีซี

คลิก

Co

py

rig

ht

20

Spinner

คู่มือเขียนแอพ Android ฉบับรวมโค้ด ListView, ListActivity และ Spinner รายละเอียดเพิ่มเติม: bit.ly/10Bu0B7

121


27/7/2013

17:48

Lt d.

ch04.doc

ตัวอยางและคําอธิบาย

Co .,

ถ้าหากมีข้อมูลอยู่ในอาร์เรย์ การแสดงข้อมูลเหล่านั้นออกมาใน Spinner จะใช้ ArrayAdapter เป็นตัวกลางเช่นเดียวกับการแสดงข้อมูลใน ListView ดังตัวอย่างนี้ 1 กําหนด Layout ของหน้าจอ โปรเจ็ค SpinnerDemo, ไฟล res\layout\activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="16dp" > <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content"

ov is

android:layout_marginBottom="8dp" >

io n

android:orientation="vertical"

<TextView

android:layout_width="wrap_content"

android:layout_height="wrap_content"

Pr

android:text="Select country: " /> <Spinner

android:id="@+id/list_of_countries" android:layout_width="0dp"

android:layout_height="wrap_content"

<Button

13

android:layout_weight="1" /> </LinearLayout>

20

android:id="@+id/show_selected_item_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center"

ht

android:layout_marginBottom="8dp" android:text="Show selected item" />

<TextView

rig

android:id="@+id/text" android:layout_width="match_parent" android:layout_height="wrap_content"

Co

py

android:background="#66ff99"

122

android:gravity="center"

คู่มือเขียนแอพ Android ฉบับรวมโค้ด รายละเอียดเพิ่มเติม: bit.ly/10Bu0B7


27/7/2013

17:48

Lt d.

ch04.doc

android:padding="5dp" android:text="@string/hello_world" /> </LinearLayout>

2

Co .,

เราใช้ TextView (ID: text) เป็นตัวแสดงข้อความที่บอกให้รู้ว่าไอเท็มใดถูกเลือก โดยข้อความนี้จะ มาจาก 2 อีเวนต์ คือ ตอนคลิกเลือกไอเท็มใน Spinner กับตอนคลิกปุ่ม (ซึ่งจะตรวจสอบว่าตอนนั้น ไอเท็มใดใน Spinner ถูกเลือก แล้วแสดงข้อความออกมา) เพิ่มการประกาศอาร์เรย์ countries ในแอคทิวิตี

io n

โปรเจ็ค SpinnerDemo, ไฟล MainActivity.java static final String[] countries = new String[] {

"Brunei", "Cambodia", "Indonesia", "Laos", "Malaysia", "Myanmar (Burma)", "Philippines", "Singapore", "Thailand",

ov is

"Vietnam" };

เพิ่มโค้ดในเมธอด onCreate ของแอคทิวิตี เพื่อสร้าง Adapter และผูกเข้ากับ Spinner รวมทั้งระบุ การทํางานเมื่อไอเท็มใน Spinner ถูกเลือก

3

โปรเจ็ค SpinnerDemo, ไฟล MainActivity.java

final TextView text = (TextView) findViewById(R.id.text);

//

Pr

final Spinner spinner = (Spinner) findViewById(R.id.list_of_countries);

สราง Adpater และนําไปกําหนดใหกับ Spinner

ArrayAdapter<String> adapter = new ArrayAdapter<String>(

13

this, android.R.layout.simple_spinner_item, countries); spinner.setAdapter(adapter); //

ระบุการทํางานเมื่อไอเท็มใน Spinner ถูกเลือก

20

spinner.setOnItemSelectedListener( new AdapterView.OnItemSelectedListener() { //

เมธอดที่จะถูกเรียกเมื่อไอเท็มหนึ่งๆถูกเลือก

@Override

ht

public void onItemSelected(AdapterView<?> av, View v, int position, long id) {

rig

String msg = "You have selected " + ((TextView) v).getText(); msg += " at position " + String.valueOf(position); text.setText(msg);

Co

py

} //

เมธอดที่จะถูกเรียกเมื่อไมมีไอเท็มถูกเลือกเลย ในที่นี้เรา return กลับไปทันทีโดยไมทําอะไร

@Override public void onNothingSelected(AdapterView<?> av) {

คู่มือเขียนแอพ Android ฉบับรวมโค้ด ListView, ListActivity และ Spinner รายละเอียดเพิ่มเติม: bit.ly/10Bu0B7

123


27/7/2013

17:48

Lt d.

ch04.doc

return; } });

Co .,

4

ให้สังเกตว่าเรากําหนด Layout ของแต่ละไอเท็มใน Spinner โดยใช้วิวที่แอนดรอยด์เตรียมมาให้ อยู่แล้ว (android.R.layout.simple_spinner_item) เพิ่มโค้ดในเมธอด onCreate ของแอคทิวิตี เพื่อระบุการทํางานเมื่อปุ่มถูกคลิก โปรเจ็ค SpinnerDemo, ไฟล MainActivity.java

Button button = (Button) findViewById(R.id.show_selected_item_button);

@Override public void onClick(View v) { String msg = "Selected item: ";

ใชเมธอด getSelectedItem อานขอมูลของไอเท็มที่ถูกเลือก

ov is

//

io n

button.setOnClickListener(new View.OnClickListener() {

msg += (String) spinner.getSelectedItem(); text.setText(msg); } });

Pr

โค้ดในตัวอย่างนี้นับว่าตรงไปตรงมา และใกล้เคียงกับตัวอย่าง ListView ก่อนหน้านี้ จึงไม่จําเป็น ต้องอธิบายอะไรเพิ่มเติม เรามาดูผลการรันเลยดีกว่า

ผลการรัน

13

เมื่อรันขึ้นมา ไอเท็มแรกของ Spinner จะถูก เลือกอัตโนมัติ ทําให้ปรากฏข้อความใน TextView ตั้งแต่ต้น

Co

py

rig

ht

20

1

124

คู่มือเขียนแอพ Android ฉบับรวมโค้ด รายละเอียดเพิ่มเติม: bit.ly/10Bu0B7


27/7/2013

17:48

Lt d.

ch04.doc

ต่อไปจะลองเลือก Philippines

คลิกปุ่ม Show selected item

คลิก

Co

py

rig

ht

20

13

Pr

3

ov is

คลิก

io n

Co .,

2

คู่มือเขียนแอพ Android ฉบับรวมโค้ด ListView, ListActivity และ Spinner รายละเอียดเพิ่มเติม: bit.ly/10Bu0B7

125


27/7/2013

17:48

การสราง Spinner ที่เราออกแบบ Layout ของแตละขอมูลเอง

Lt d.

ch04.doc

Co .,

เช่นเคย แอนดรอยด์อนุญาตให้กําหนด Layout ให้กับแต่ละไอเท็มใน Spinner โดยใช้ Layout File ที่เราออกแบบเองได้ หรือเรียกว่า Custom Spinner นั่นเอง

ตัวอยางและคําอธิบาย

io n

เราจะดัดแปลงตัวอย่างที่ผ่านมาให้แสดงรูปธงชาติของแต่ละประเทศใน Spinner ด้วย ดังนั้ น จึ งต้ อ งส ร้ างทั้ ง Custom Layout (ไฟ ล์ res\layout\item.xml) แ ล ะ Custom Adapter (ค ล าส CountryAdapter) เหมือนที่ทํากับ ListView มาแล้วก่อนหน้านี้ (โปรเจ็ค CustomAdapterDemo) 1 กําหนด Layout ของหน้าจอ โปรเจ็ค CustomSpinnerDemo, ไฟล res\layout\activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

ov is

android:layout_width="match_parent"

android:layout_height="match_parent" android:orientation="vertical" android:padding="16dp" > <LinearLayout

Pr

android:layout_width="match_parent"

android:layout_height="wrap_content" android:layout_marginBottom="8dp" > <TextView

13

android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center"

20

android:text="Select country: " /> <Spinner

android:id="@+id/list_of_countries" android:layout_width="0dp"

ht

android:layout_height="wrap_content" android:layout_weight="1" />

</LinearLayout>

rig

<Button

android:id="@+id/show_selected_item_button" android:layout_width="wrap_content"

Co

py

android:layout_height="wrap_content"

126

android:layout_gravity="center" android:layout_marginBottom="8dp" android:text="Show selected item" />

คู่มือเขียนแอพ Android ฉบับรวมโค้ด รายละเอียดเพิ่มเติม: bit.ly/10Bu0B7


27/7/2013

17:48

Lt d.

ch04.doc

<TextView android:id="@+id/text" android:layout_width="match_parent" android:background="#66ff99" android:gravity="center" android:padding="5dp" android:text="@string/hello_world" /> </LinearLayout>

io n

กําหนด Layout สําหรับแต่ละไอเท็มใน Spinner

2

Co .,

android:layout_height="wrap_content"

โปรเจ็ค CustomSpinnerDemo, ไฟล res\layout\item.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"

ov is

android:layout_height="match_parent" android:gravity="center_vertical" > <ImageView

android:id="@+id/flag_image"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

Pr

android:layout_margin="5dp" /> <TextView

android:id="@+id/country_name"

13

android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginLeft="3dp" android:layout_weight="1"

20

android:textSize="16sp" />

</LinearLayout>

ht

3

Layout นี้มีรูปธงชาติอยู่ทางซ้ายและชื่อประเทศอยู่ทางขวา เช่นเดียวกับตัวอย่าง ListView สร้างคลาสใหม่ชื่อ Country แล้วพิมพ์โค้ดดังนี้

โปรเจ็ค CustomSpinnerDemo, ไฟล Country.java

rig

package com.example.customspinnerdemo; public class Country {

Co

py

private int m_flagImageId; private String m_countryName; public Country(int flagImageId, String countryName) {

คู่มือเขียนแอพ Android ฉบับรวมโค้ด ListView, ListActivity และ Spinner รายละเอียดเพิ่มเติม: bit.ly/10Bu0B7

127


27/7/2013

17:48

Lt d.

ch04.doc

m_flagImageId = flagImageId; m_countryName = countryName; }

return m_flagImageId; } public void setFlagImageId(int flagImageId) { m_flagImageId = flagImageId;

public String getCountryName() { return m_countryName; }

io n

}

Co .,

public int getFlagImageId() {

public void setCountryName(String countryName) {

ov is

m_countryName = countryName; } }

Pr

4

คลาส Country ในตัวอย่างนี้เหมือนในตัวอย่าง ListView ทุกประการ แตกต่างแค่บรรทัดแรก เท่านั้น สร้างคลาสใหม่ชื่อ CountryAdapter แล้วพิมพ์โค้ดดังนี้ โปรเจ็ค CustomSpinnerDemo, ไฟล CountryAdapter.java

13

package com.example.customspinnerdemo; import android.app.Activity;

import android.content.Context;

20

import android.view.LayoutInflater; import android.view.View;

import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.ImageView;

ht

import android.widget.TextView;

rig

public class CountryAdapter extends ArrayAdapter<Country> { private Context context; private int itemLayoutId;

py

private Country countries[] = null;

Co

public CountryAdapter(Context context, int itemLayoutId,

128

Country[] countries) { super(context, itemLayoutId, countries);

คู่มือเขียนแอพ Android ฉบับรวมโค้ด รายละเอียดเพิ่มเติม: bit.ly/10Bu0B7


27/7/2013

17:48

Lt d.

ch04.doc

this.context = context; this.itemLayoutId = itemLayoutId; this.countries = countries;

Co .,

} @Override

public View getView(int position, View convertView, ViewGroup parent) { LayoutInflater inflater = ((Activity) context).getLayoutInflater(); View item = inflater.inflate(itemLayoutId, parent, false);

TextView txtCountryName =

io n

ImageView imgFlag = (ImageView) item.findViewById(R.id.flag_image); (TextView) item.findViewById(R.id.country_name);

ov is

Country country = countries[position];

imgFlag.setImageResource(country.getFlagImageId()); txtCountryName.setText(country.getCountryName()); return item;

Pr

} @Override

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

13

return getView(position, convertView, parent); } }

Co

py

rig

ht

20

คลาส CountryAdapter ในตัวอย่างนี้ก็เหมือนตัวอย่าง ListView ทุกประการ ยกเว้นมีการ Override เมธอด getDropDownView เพิ่มอีก 1 เมธอด ซึ่ง Spinner จะเรียกมายังเมธอดนี้เมื่อ ต้องการรับวิวของแต่ละไอเท็มไปแสดงผลใน drop-down (เมื่อผู้ใช้คลิกที่ตัว Spinner เพื่อดูไอเท็ม ทั้งหมด) ส่วนเมธอด getView จะถูกเรียกเมื่อ Spinner ต้องการรับวิวไปแสดงที่ตัวมันเพื่อสื่อว่า ไอเท็มใดถูกเลือกอยู่ตอนนั้น

คู่มือเขียนแอพ Android ฉบับรวมโค้ด ListView, ListActivity และ Spinner รายละเอียดเพิ่มเติม: bit.ly/10Bu0B7

129


27/7/2013

17:48

Co .,

ไดมาจากการเรียกเมธอด getView ของ Adapter

Lt d.

ch04.doc

ov is

io n

ไดมาจากการเรียกเมธอด getDropDownView ของ Adapter (1 ไอเท็มตอ การเรียกเมธอด 1 ครั้ง)

20

5

13

Pr

ในที่นี้เราเขียนโค้ดในเมธอด getDropDownView ให้เรียกเมธอด getView อีกที เพื่อทํางานทุกอย่าง แบบเดียวกับที่ getView ทํา ดังนั้นเมธอดทั้งสองจึง return วิวที่มี Layout แบบเดียวกันออกไป เราสามารถเขียนโค้ดให้แสดง Layout แบบหนึ่งในตัว Spinner แต่แสดง Layout อีกแบบหนึ่งใน drop-down ยกตัวอย่างเช่น ใน Spinner ให้แสดงเฉพาะชื่อประเทศ แต่ใน drop-down ให้แสดงรูปธงชาติและชื่อประเทศ ดังรูปถัดไป ทั้งหมดขึ้นอยู่กับเราว่าจะ return อะไร ออกไปจากเมธอด getView และ getDropDownView เพิ่มโค้ดในเมธอด onCreate ของแอคทิวิตี เพื่อเตรียมข้อมูลในอาร์เรย์ countries, สร้าง Adapter และผูกเข้ากับ Spinner โปรเจ็ค CustomSpinnerDemo, ไฟล MainActivity.java final TextView text = (TextView) findViewById(R.id.text);

ht

final Spinner spinner = (Spinner) findViewById(R.id.list_of_countries); Country countries[] = new Country[] { new Country(R.drawable.brunei, "Brunei"),

rig

new Country(R.drawable.cambodia, "Cambodia"), new Country(R.drawable.indonesia, "Indonesia"), new Country(R.drawable.laos, "Laos"), new Country(R.drawable.malaysia, "Malaysia"),

Co

py

new Country(R.drawable.myanmar, "Myanmar (Burma)"),

130

new Country(R.drawable.philippines, "Philippines"), new Country(R.drawable.singapore, "Singapore"), new Country(R.drawable.thailand, "Thailand"),

คู่มือเขียนแอพ Android ฉบับรวมโค้ด รายละเอียดเพิ่มเติม: bit.ly/10Bu0B7


27/7/2013

17:48

new Country(R.drawable.vietnam, "Vietnam"), }; CountryAdapter adapter = new CountryAdapter(this, R.layout.item,

Co .,

countries); spinner.setAdapter(adapter);

Lt d.

ch04.doc

เพิ่มโค้ดในเมธอด onCreate เพื่อระบุการทํางานเมื่อไอเท็มใน Spinner ถูกเลือก

6

โปรเจ็ค CustomSpinnerDemo, ไฟล MainActivity.java spinner.setOnItemSelectedListener( new AdapterView.OnItemSelectedListener() {

io n

@Override

public void onItemSelected(AdapterView<?> av, View v, int position, long id) {

ov is

TextView tv = (TextView) v.findViewById(R.id.country_name); String msg = "You have selected " + tv.getText(); msg += " at position " + String.valueOf(position); text.setText(msg);

@Override

Pr

}

public void onNothingSelected(AdapterView<?> av) { return;

13

} });

เพิ่มโค้ดในเมธอด onCreate เพื่อระบุการทํางานเมื่อปุ่มถูกคลิก

7

20

โปรเจ็ค CustomSpinnerDemo, ไฟล MainActivity.java Button button = (Button) findViewById(R.id.show_selected_item_button); button.setOnClickListener(new View.OnClickListener() { @Override

ht

public void onClick(View v) { String msg = "Selected item: ";

rig

/*

ใชเมธอด getSelectedItem เขาถึงขอมูลในไอเท็มที่ถูกเลือก ซึ่งขอมูลนี้คือออบเจ็ค Country */

Country selected = (Country) spinner.getSelectedItem(); msg += selected.getCountryName();

py

text.setText(msg);

}

Co

});

คู่มือเขียนแอพ Android ฉบับรวมโค้ด ListView, ListActivity และ Spinner รายละเอียดเพิ่มเติม: bit.ly/10Bu0B7

131


27/7/2013

17:48

Lt d.

ch04.doc

io n

Co .,

ผลการรัน

Co

py

rig

ht

20

13

Pr

ov is

คลิก

132

คู่มือเขียนแอพ Android ฉบับรวมโค้ด รายละเอียดเพิ่มเติม: bit.ly/10Bu0B7

บทที่ 4 คู่มือเขียนแอพ Android ฉบับรวมโค้ด  

เนื้อหาบทที่ 4 หนังสือคู่มือเขียนแอพ Android ฉบับรวมโค้ด โดยพร้อมเลิศ หล่อวิจิตร รายละเอียดเพิ่มเติม/สั่งซื้อ: http://bit.ly/17NmCrR

Advertisement