เนื้อหาในตอนนี้ต่อจากตอนที่แล้วยังเกี่ยวกับการใช้งาน fragment
การสร้าง UI ให้มีชีวิตชีวา ด้วย Fragments เบื้องต้น ตอนที่ 1
https://www.ninenik.com/content.php?arti_id=628 via @ninenik
เมื่อเราตัดสินใจที่จะสร้าง app ให้รองรับหน้าจอในช่วงขนาดที่กว้าง เราสามารถนำ fragment มาใช้
ในการออกแบบ layout ต่างๆ เพื่อปรับให้เหมาะกับการใช้งาน ตามขนาดพื้นที่ใช้สอยของหน้าจอ
อย่างเช่น สำหรับมือถืออาจเหมาะที่จะใช้เพียง fragment เดียวเพื่อแสดงหน้าต่างส่วนติดต่อใช้งานกับระบบ
และตรงกันข้ามสำหรับ tablet ซึ่งมีขนาดพื้นที่หน้าจอที่กว้างกว่า เราอาจจะใช้ fragment
แบบแสดงคู่กันสองข้าง เพื่อแสดงรายละเอียดเพิ่มเติมได้มากขึ้น
จากรูป ใน activity เดียวกัน fragment ทั้งสอง แสดงการจัดเรียงโครงสร้างแตกต่างบนหน้าจอขนาดต่างกัน
บนหน้าจอขนาดใหญ่จะจัดเรียงคู่กันติดกันเต็มทั้งซ้ายขวา แต่บนมือถือจะมีเพียง fagment เดียวที่แสดงเต็มใน
การเรียกใช้งานแต่ละครั้ง ดังนั้นกรณีมือถือ fragment จำเป็นต้องถูกแทนที่ด้วย fragment อื่นตามที่ผู้ใช้กำหนด
การเพิ่ม fragment ในขั้นตอนการทำงานของ activity
เราควรเพิ่ม fragment เข้าไปใน activity ในขณะเรียกใช้งาน มากกว่าการกำหนดลงไปใน layout xml ไฟล์
(ตามแบบเนื้อหาตอนที่ 1 ซึ่งเรากำหนดโดยใช้ <fragment>) ซึ่งจำเป็นถ้าเราวางแผนให้มีการ
เปลี่ยน fragment ในระหว่างที่ใช้ activity อยู่
ในการโอนถ่ายเปลี่ยนแปลง fragment เช่น การเพิ่ม หรือ ลบ fragment เราต้องใช้ getFragmentManager() เพื่อทำ
การสร้างการโอนถ่าย fragment (FragmentTransaction)
เมื่อ activity อนุญาตให้ ทำการลบหรือแทนที่ fragment ได้แล้ว เราจึงควรที่จะเพิ่ม fragment เริ่มต้นเข้าไปใน activity
ในขณะที่มีการเรียกใช้งาน onCreate() method
กฎเกณฑ์สำคัญในการใช้งาน fragment (โดยเฉพาะเวลาที่ทำการเพิ่ม fragment ในขั้นตอนการทำงานของ activity) ในไฟล์
activity layout เราต้องเพิ่ม container View เพื่อที่จะใส่ fragment เข้าไปได้
และนี่คือ fragment container ที่เราจะใช้งาน
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/fragment_container" android:layout_width="match_parent" android:layout_height="match_parent" />
ดังนั้นเราจะมาดัดแปลงทดสอบจากเนื้อหาตอนที่แล้ว
1. ตามหลักเกณฑ์สำคัญ ก่อนที่เราจะเพิ่ม fragment ลงใน activity เราต้องกำหนด fragment container
ลงใน layout หลักก่อน โดยจากเดิมไฟล์ activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" > <fragment android:name="com.example.ninenik.study003.myFragment" android:id="@+id/my_fragment" android:layout_weight="1" android:layout_width="0dp" android:layout_height="match_parent" /> </LinearLayout>
ให้เราเปลี่ยนเป็นเรียกใช้ FrameLayout ที่ไม่มี view อื่นด้านใน
มาทำหน้าที่เป็น fragment container แทนดังนี้ (อย่าลืมกำหนด id ตามโค้ดในที่นี้เราใช้เป็น
fragment_container ไว้เรียกใช้ใน code java)
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/fragment_container" android:layout_width="match_parent" android:layout_height="match_parent" />
2. มาที่ไฟล์ activity ที่ชื่อ MainActivity
ให้เราแทรกโค้ดต่อไปนี้ไว้ใน onCreate() method
// ตรวจสอบว่า activity มีการเรียกใช้งาน layout ที่มีการกำหนด // FrameLayout เป็น fragment container จาก id ชื่อ fragment_container if (findViewById(R.id.fragment_container) != null) { // ถ้ามีการกำหนด // กรณีถ้า, ถ้ามีการกู้คืนค่าจาก state ก่อนหน้า, // แล้วเราไม่ต้องทำอะไร และให้ return ค่า if (savedInstanceState != null) { return; } // สร้าง fragment เพื่อใส่เข้าไปใน activity layout // myFragment คือชื่อ fragment activity ที่เราสร้างในตอนที่แล้ว // เราตั้งชื่อ instance ของ fragment ใหม่ชื่อ FragmentA myFragment FragmentA = new myFragment(); // ในกรณีที่ activity นี้ มีการการรับค่าจาก intent // ให้ส่งค่าจาก intent ไปยัง fragment ด้วยการกำหนด arguments FragmentA.setArguments(getIntent().getExtras()); // เพิ่ม fragment ไปใน 'fragment_container' FrameLayout getFragmentManager().beginTransaction() .add(R.id.fragment_container, FragmentA).commit(); }
ใน activity เราจะเห็นว่ามีการเรียกใช้งาน getFragmentManager() จากนั้นก็เรียกใช้งาน
beginTransaction() เพื่อทำการถ่ายโอน fragment และใช้คำสั่ง add()
เพื่อเพิ่ม fragment โดยเพิ่ม FragmentA เข้าไปใน fragment container
เราสามารถทำการถ่ายโอน fragment หลายอันใน activity ด้วยการใช้การถ่ายโอน fragment เดียวกันได้
โดยเมื่อ พร้อมที่จะเปลี่ยนแปลงแล้ว ต้องเรียกใช้งานคำสั่ง commit()
เป็นอันเสร็จในขั้นตอนการกำหนด การเรียกใช้งาน fragment มาแสดง ในขั้นตอนการทำงานของ activity
3. ก่อนทดสอบผลลัพธ์ เรามากำหนดการแสดง fragment_my.xml กันก่อน ซึ่งจาก code ดังกล่าวด้านบน
fragmentA จะถูกสร้างจาก myFragment activity โดยไปดึง fragment_my.xml มาใช้
แล้วก็นำ fragmentA ไปเพิ่มเข้าไปใน fragment_container เพื่อแสดงอีกที
เดิม fragment_my.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.example.ninenik.study003.myFragment"> <!-- TODO: Update blank fragment layout --> <TextView android:layout_width="match_parent" android:layout_height="match_parent" android:text="I am a Fragment" /> </FrameLayout>
ให้เรากำหนดเหลือแค่ TextView อย่างเดียว และกำหนดข้อความที่ต้องการแสดงเป็น Dynamic Fragment
เป็น จะได้เป็น
<TextView android:layout_width="match_parent" android:layout_height="match_parent" android:text="Dynamic Fragment" xmlns:android="http://schemas.android.com/apk/res/android" />
4. จากนั้นทดสอบ run app หากไม่มีอะไรผิดพลาด app จะมีการเรียกใช้งาน fragment แบบ dynamic
ตามรูปด้านล่าง
การแทนที่ fragment ด้วย fragment อื่น
ขั้นตอนการแทนที่ fragment จะคล้ายกับ การเพิ่ม เพียงแค่เปลี่ยนจาก add() เป็น replace()
จำไว้ว่าเมื่อเราทำการถ่ายโอน fragment เช่นการแทนที่ หรือลบอันใดอันหนึ่งออก เราควรจจะอนุญาตให้ผู้ใช้
สามารถย้อนกลับ หรือเลิกทำการเปลี่ยนแปลงได้ โดยต้องเรียกใช้ addToBackStack() ก่อน ทำการถ่ายโอน fragment
หมายเหตุ:: เมื่อเราลบหรือแทนที่ fragment และใส่กลับไปใหม่ fragment ที่ถูกลบไปนั้นจะหยุดลง (แต่ไม่ถูกทำลาย)
ถ้าผู้ใช้ย้อนกลับมาเพื่อกู้คืน fragment fragment นั้นจะเริ่มทำงานใหม่ ถ้าเราไม่ได้เพิ่มการถ่ายโอน fragment
กลับ แล้ว fragment นั้นจะถูกทำลายเมื่อถูกลบหรือแทนที่
ตัวอย่าง การแทนที่ fragment ด้วย fragment อื่น
// ตรวจสอบว่า activity มีการเรียกใช้งาน layout ที่มีการกำหนด // FrameLayout เป็น fragment container จาก id ชื่อ fragment_container if (findViewById(R.id.fragment_container) != null) { // ถ้ามีการกำหนด // กรณีถ้า, ถ้ามีการกู้คืนค่าจาก state ก่อนหน้า, // แล้วเราไม่ต้องทำอะไร และให้ return ค่า if (savedInstanceState != null) { return; } // สร้าง fragment เพื่อใส่เข้าไปใน activity layout // myFragment คือชื่อ fragment activity ที่เราสร้างในตอนที่แล้ว // เราตั้งชื่อ instance ของ fragment ใหม่ชื่อ FragmentA myFragment FragmentA = new myFragment(); // ในกรณีที่ activity นี้ มีการการรับค่าจาก intent // ให้ส่งค่าจาก intent ไปยัง fragment ด้วยการกำหนด arguments FragmentA.setArguments(getIntent().getExtras()); // แทนที่ fragment ไปใน 'fragment_container' FrameLayout getFragmentManager().beginTransaction() .replace(R.id.fragment_container,FragmentA) .addToBackStack(null) .commit(); }