Flutter | มาลองทำแอป Icon Showcase || Part Extra Bloc+Animation
กลับมาอีกรอบกับ Icon Showcase โดยรอบนี้เราจะมาลองเพิ่มการจัดการข้อมูลแบบ BloC กับ อนิเมชั่น เข้ามาในแอปของเรา จึงตั้งโจทย์ไว้ว่า เราจะสามารถเพิ่มลด Icon ใน List ของเราได้ โดยจัดการข้อมูลเหล่านี้ด้วย BloC และเมื่อเพิ่มหรือลบ Icon ออกไปจะมีอนิเมชั่นการเพิ่มหรือลบออกไปด้วย เป็น Scale กับ Fade แบบง่ายๆ นอกเหนือจากนั้นแอปเรายังสามารถทำงานได้เหมือนก่อนหน้า
ในงานนี้ เราก็จะมาแนะนำ ให้รู้จัก 2 อย่าง
- Flutter Bloc
- AnimatedList
เราจะเอาโค๊ดเก่ามาต่อยอด สามารถโหลดได้จากข้างล่างเลย
หรืออยากกลับไปอ่านในพาร์ทก่อนหน้าก็กดลิงค์ข้างล่างได้
ถ้าพร้อมแล้วก็ไปกันต่อเลย
⚠️⚠️⚠️ (อัพเดท 8/7/2020) ถ้าใครใช้ flutter_bloc เวอร์ชั่นตั้งแต่ 1.0.0 ขึ้นไป จะมีการเปลี่ยนชื่อ Api บางส่วนดังนี้
bloc.state.listen -> bloc.listen
bloc.currentState -> bloc.state
bloc.dispatch -> bloc.add
bloc.dispose -> bloc.close
สามารถอ่านเพิ่มเติมได้จาก https://link.medium.com/qnfMcEcW00
ดังนั้นตอนทำตาม อาจใช้เวอร์ชั่นที่ระบุไว้ไปก่อนได้ หลักการทำงานของ flutter_bloc ยังเหมือนเดิม
เรามาดูในส่วนของ Bloc ก่อน
หรือว่าอีกอย่างคือ มาสร้างวิธีจัดการกับข้อมูล
สร้างโฟลเดอร์ใหม่ชื่อ bloc
Event
สร้างไฟล์ไว้จัดการ event bloc/iconlist_event.dart
event ของเรามีเพียง 3 อย่าง คือ โหลดค่าตั้งต้น(LoadDefaultIcon) เพิ่ม item(AddIcon) และ ลบ item(RemoveIcon)
LoadDefaultIcon กับ AddIcon เราไม่จำเป็นต้องรับพารามีเตอร์เข้ามาเพราะเราจะสุ่มเอา ส่วน RemoveIcon จะรับตำแหน่งที่จะลบออก(เพื่อความไม่ซับซ้อน ตำแหน่งที่จะลบ จะลบอันสุดท้ายเสมอ)
State
สร้างไฟล์ไว้จัดการ state ที่จะใช้ส่งไปโชว์ในแอป bloc/iconlist_state.dart
state เราจะมี 2 สถานะ คือ กำลังโหลด(IconListLoaded) กับ โหลดเสร็จแล้ว(IconListLoading)
IconListLoaded จะสามารถส่งข้อมูล Icon List ได้ ส่วน IconListLoading ไม่จำเป็นต้องส่งข้อมูล ใช้เพื่อบอกสถานะว่ากำลังโหลดข้อมูล
Bloc
เรามาทางเชื่อมระหว่าง event ไป state ด้วย bloc
สร้างไฟล์ใหม่ bloc/iconlist_bloc.dart
เนื่องจากเรามี event 3 อัน เราเลยมีฟังก์ชั่น 3 อันที่จะเชื่อมไป State ทั้ง 2
ฟังก์ชั่นทั้ง 3 อัน ได้แก่
- _mapAddIconToState() จะทำหน้าที่ สุ่มไอคอนแล้วเพิ่มเข้าไปใน Icon List
- _mapRemoveIconToState(RemoveIcon event) จะรับตำแหน่งที่จะลบ แล้วลบออกไปจาก Icon List
- _mapLoadDefaultIconToState() จะโหลดค่าตั้งต้นของ Icon List
รวบไฟล์ export
ตอนนี้ bloc เราครบแล้ว ตั้งแต่ event state bloc เพื่อความง่ายในการเรียกใช้ ก็รวบลง อีกไฟล์นึง แล้ว export เอา จะได้ import เข้ามาไฟล์เดียวได้
สร้างไฟล์ใหม่ชื่อ bloc/iconlist.dart
มาทำส่วนดีไซน์กับอนิเมชั่นต่อ
จากโค๊ดเก่า เราเพิ่มมา 2 ปุ่ม เป็น FloatingActionButton ที่มีปุ่ม + กับ ปุ่ม -
เราไปดูโค๊ดใหม่ที่แก้ไขทุกอย่างแล้วเลยดีกว่า
มาค่อยๆดูไปทีละส่วนกัน
ตรงนี้เพราะเราใช้ Bloc เลยหุ้ม Widget ที่อยู่นอกสุดด้วย BlocProvider แล้วส่ง builder เป็น IconlistBloc() หรือ Bloc ที่เราพึ่งสร้างไป และเมื่อรันครั้งแรกที่เปิดแอป เราก็จะสั่งให้มันโหลดค่าตั้งต้น dispatch(LoadDefaultIcon())
เราเพิ่ม _listKey ไว้ใช้กับ AnimatedList
เราเพิ่มตัวแปร iconListBloc ไว้เรียก Bloc ของเรา แล้วตอนจะสร้าง Widget เราก็หุ้มไว้ด้วย BlocBuilder ที่ bloc ส่ง iconListBloc ส่วนที่ builder จะส่งฟังก์ชั่นที่สร้าง Widget ในนั้นเราก็เช็คได้ว่า เป็น State ไหน ถ้าเป็น IconListLoading เราจะโชว์ Container() เปล่าๆ (ถ้าใครจะทำจริงจัง ก็เปลี่ยนเป็นไอคอน Loading ได้) แต่ถ้าเป็น IconListLoaded จะโชว์แอปที่เราสร้างมาก่อนหน้า
เปลี่ยนจาก ListView.builder ไปใช้ AnimatedList แทน
เพื่อความเรียบร้อย และจะได้เรียกใช้ซ้ำได้ เราเอา card ของเราไปสร้างเป็นฟังก์ชั่น buildCard ซึ่งจะทำหน้าที่ return Card แล้วได้ผลลัพธ์เหมือนเดิม
ฟังก์ชั่น buildCard
เนื่องจากเป็นอนิเมชั่น เราก็เพิ่ม FadeTransition และ SizeTransition เข้าไปด้วย
ในส่วนนี้เราเพิ่มปุ่ม + และ - วางตรงกลางล่างของแอปตอนกด เราก็จะเรียก event ที่ bloc และ อัพเดท _listKey สำหรับ + _listKey เราจะเพิ่มแค่ตำแหน่งที่จะแทรกเข้า ส่วน - _listKey เราจะลบออกตามตำแหน่งที่ต้องการ นอกจากนั้นต้องส่งฟังก์ชั่นที่สร้าง Card ด้วย (buildCard) นอกจากนี้อย่าลืมตั้ง heroTag ของ FloatingActionButton ให้ต่างกันด้วย เพราะค่าตั้งต้นจะถูกตั้งให้เหมือนกัน
เพียงเท่านี้ แอปก็ออกมาเรียบร้อยแล้ว
ใครมีคำถามสงสัย ก็ส่งทิ้งไว้ข้างล่างได้เช่นเคย ไว้เจอกันใหม่ในครั้งหน้า