Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> ระบบ >> Android

สร้างแอปคำนวณค่าทิปด้วย Flutter: คู่มือขั้นตอนต่อขั้นตอน

เมื่อเฟรมเวิร์กพัฒนาแอปมือถือ Flutter ได้รับความนิยมมากขึ้น ธุรกิจหลายแห่งจึงเลือกใช้สำหรับโปรเจกต์ของพวกเขา

นักพัฒนาหลายคนชื่นชมความสามารถในการพัฒนาแอปด้วย UI ที่สวยงามแบบ Pixel-perfect ด้วยโครงสร้าง Widget ที่เรียบง่าย ผมเชื่อว่า Flutter เป็นอนาคตของการพัฒนาแอปมือถือ เพราะความเรียบง่ายในการพัฒนา UI และความสามารถในการจัดการ Logic ด้วยภาษา Dart

บทเรียนนี้เน้นสอนพื้นฐาน Flutter ผ่านการสร้างแอปคำนวณค่าทิปง่ายๆ จะครอบคลุมรูปแบบเขียนโค้ดมาตรฐาน รวมถึง Stateful และ Stateless Widget รวมถึง Widget ที่ใช้บ่อยที่สุดในการพัฒนาแอป Flutter

แนวคิดคือเริ่มจากการตั้งค่าโปรเจกต์ Flutter เริ่มต้น จากนั้นนำไปสู่การสร้าง UI และฟังก์ชันพื้นฐาน

มาเริ่มกันเลย!

วิธีตั้งค่าโปรเจกต์ Flutter

เพื่อสร้างโปรเจกต์ Flutter ใหม่ คุณต้องติดตั้ง Flutter SDK บนระบบ สำหรับการติดตั้งที่ง่ายและรวดเร็ว สามารถทำตามเอกสารอย่างเป็นทางการของ Flutter

จำไว้ว่ายังต้องการ Android Studio และ Android SDK หากพัฒนาแอปสำหรับแพลตฟอร์ม Android

หลังตั้งค่าเสร็จแล้ว ตามเอกสาร ให้รันคำสั่ง Flutter ต่อไปนี้ในเทอร์มินัล:

flutter create tipCalculator

คำสั่งนี้จะดาวน์โหลดและตั้งค่าโปรเจกต์ Flutter เริ่มต้นให้อัตโนมัติ ตอนนี้คุณสามารถเปิดโปรเจกต์ใน IDE Visual Studio Code ได้

หากมีอุปกรณ์จำลองหรือสมาร์ทโฟนจริงเชื่อมต่ออยู่ สามารถรันคำสั่งต่อไปนี้เพื่อเปิดแอป:

flutter run

อีกวิธีหนือคือกด F5 บนคีย์บอร์ด จะแสดงเมนูใน VSCode ให้เลือกอุปกรณ์ที่ต้องการเปิดแอป

หมายเหตุ: ต้องอยู่ในไฟล์ที่มีนามสกุล .dart จึงจะรันคำสั่งนี้ได้สำเร็จ

Build และรันด้วยคำสั่งข้างต้นหรือ F5 จะได้เทมเพลตเริ่มต้นใน Emulator/อุปกรณ์จริง:

สร้างแอปคำนวณค่าทิปด้วย Flutter: คู่มือขั้นตอนต่อขั้นตอน

ตอนนี้คุณควรมีแอป Flutter ทำงานได้แล้ว

มาดูรายละเอียดไฟล์โปรเจกต์หลัก main.dart

ในไฟล์ main.dart มีออบเจ็กต์คลาส 2 ตัว หนึ่ง extends Stateful Widget อีกตัว extends Stateless Widget หมายความว่าอะไร?

  • Stateful Widget: คลาสที่เก็บ State ของแอป State สามารถเปลี่ยนแปลงและกระตุ้นการ Render Widget ในคลาสนี้ มีส่วนทำให้เกิดการเปลี่ยนแปลง State แบบไดนามิก
  • Stateless Widget: คลาสที่ไม่เก็บ State ใดๆ แสดง Widget View ที่ไม่เปลี่ยนแปลง ไม่มีส่วนทำให้เกิดการเปลี่ยนแปลง State แบบไดนามิก

ไฟล์ main.dart ยังมีฟังก์ชัน main() ที่เรียกคลาส MyApp ภายในเมธอด runApp เพื่อเริ่มต้นแอป Flutter บนอุปกรณ์

วิธีสร้าง UI ของแอปคำนวณค่าทิป

เพื่อเริ่มสร้าง UI เราต้องลบทุกอย่างภายในคลาส MyHomePageState ที่มาด้วยค่าเริ่มต้น

หลังลบเสร็จ เราจะคืนค่า Widget Scaffold เรียบง่ายจากฟังก์ชัน build

Widget Scaffold ให้ Property เพื่อเพิ่ม appBar และ body ตอนนี้เพิ่ม App Bar เรียบง่าย ดูโค้ดด้านล่าง:

class _MyHomePageState extends State<MyHomePage> { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title:Text('Tip Calculator', style: TextStyle(color: Colors.black87),), ), body: Container() ); } }

Build และรันหลังเพิ่ม appBar ด้วย Widget AppBar และ Property title จะได้ผลลัพธ์ใน Emulator:

สร้างแอปคำนวณค่าทิปด้วย Flutter: คู่มือขั้นตอนต่อขั้นตอน
หมายเหตุ: Flutter มี Hot Reload เมื่อบันทึกไฟล์ Dart การเปลี่ยนแปลงจะสะท้อนใน Emulator ทันที

ขั้นตอนที่ 1: ออกแบบ App Bar

เราจะปรับแต่ง Widget AppBar ด้วย Property ต่างๆ ดูโค้ดที่ปรับแล้ว:

appBar: AppBar( title: Text('Tip Calculator', style: TextStyle(color: Colors.black87),), centerTitle: true, elevation: 0.0, backgroundColor: Colors.white70, ),

Build และรัน จะได้ผลลัพธ์ใน Emulator:

สร้างแอปคำนวณค่าทิปด้วย Flutter: คู่มือขั้นตอนต่อขั้นตอน

เราใช้ Property พื้นฐานของ Widget AppBar ได้แก่

  • elevation ควบคุมเอฟเฟกต์เงาใน App Bar คล้าย z-index
  • centerTitle จัดตำแหน่ง Title ให้อยู่กึ่งกลาง
  • เปลี่ยนสีพื้นหลังเป็นสีขาว

ขั้นตอนที่ 2: ออกแบบ Scaffold Body

จนถึงตอนนี้มีแค่ Widget Container ว่างใน Property body ตอนนี้จะเพิ่ม Property และ Child Widget ให้ Container ตามโค้ดด้านล่าง:

body: Container( color: Colors.white70, padding: const EdgeInsets.all(16.0), child: Center( child: Form( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ ], ), ), ),

Build และรัน จะได้ผลลัพธ์ใน Emulator:

สร้างแอปคำนวณค่าทิปด้วย Flutter: คู่มือขั้นตอนต่อขั้นตอน

เห็นได้ว่าพื้นหลัง Body เปลี่ยนเป็นสีขาว เพิ่ม padding พร้อม Widget Center เป็น Child เพื่อจัด UI ให้อยู่กึ่งกลาง

Widget Center มี Child เป็น Widget Form สำหรับสร้างฟอร์มพร้อม Text Field

สำคัญคือ Widget Column เป็น Child ของ Form ให้ Property children เป็น Array ของ Widget ที่จะแสดงแนวตั้งบนหน้าจอ

ขั้นตอนที่ 3: กำหนดค่าคงที่และตัวแปร

ก่อนสร้าง Element ของฟอร์ม (รวม Text Field) ต้องกำหนดค่าคงที่เพื่อจัดการ Input จากช่องกรอกข้อมูล

ดูค่าคงที่และตัวแปรที่ต้องการในโค้ดด้านล่าง:

// จำนวนเงินบิลเริ่มต้น static const defaultBillAmount = 0.0; // เปอร์เซ็นต์ทิปเริ่มต้น static const defaultTipPercentage = 15; // TextEditingController ติดตามการเปลี่ยนแปลงจำนวนเงินบิล final _billAmountController = TextEditingController(text: defaultBillAmount.toString()); // TextEditingController ติดตามการเปลี่ยนแปลงเปอร์เซ็นต์ทิป final _tipPercentageController = TextEditingController(text: defaultTipPercentage.toString()); // เก็บค่าล่าสุดของจำนวนเงินบิลที่คำนวณได้ double _billAmount = defaultBillAmount; // เก็บค่าล่าสุดของเปอร์เซ็นต์ทิปที่คำนวณได้ int _tipPercentage = defaultTipPercentage;

ในโค้ดข้างต้นใช้เมธอด TextEditingController ซึ่งช่วยจัดการ Text Input ใน Widget TextFormField ที่จะสร้างต่อไป ซึ่ง Initialize ด้วยค่าเริ่มต้น

ขั้นตอนที่ 4: เพิ่มช่องกรอกข้อมูลฟอร์ม

ตอนนี้จะเพิ่มช่องกรอกข้อมูล 2 ช่องด้วย Widget TextFormField

ขณะใช้ Widget นี้ ต้องกำหนด Property controller ให้ตรงกับตัวแปร Controller ที่กำหนดไว้ ดูโค้ดด้านล่าง:

body: Container( color: Colors.white70, padding: const EdgeInsets.all(16.0), child: Center( child: Form( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ TextFormField( key: Key("billAmount"), controller: _billAmountController, keyboardType: TextInputType.numberWithOptions(decimal: true), decoration: InputDecoration( hintText: 'Enter the Bill Amount', labelText: 'Bill Amount', labelStyle: TextStyle( fontSize: 25, letterSpacing: 1, fontWeight: FontWeight.bold ), fillColor: Colors.white, border: new OutlineInputBorder( borderRadius: new BorderRadius.circular(20.0), ), ), ), SizedBox(height: 25,), TextFormField( key: Key("tipPercentage"), controller: _tipPercentageController, keyboardType: TextInputType.number, decoration: InputDecoration( hintText: 'Enter the Tip Percentage', labelText: 'Tip Percentage', labelStyle: TextStyle( fontSize: 25, letterSpacing: 1, fontWeight: FontWeight.bold ), fillColor: Colors.white, border: new OutlineInputBorder( borderRadius: new BorderRadius.circular(20.0), ), ), ), ], ), ), ), ),

เรากำหนด Property keyboardType เพื่อแสดงคีย์บอร์ดประเภทที่ต้องการเมื่อผู้ใช้กดที่ช่องกรอก

ยังมี Property decoration สำหรับจัดสไตล์ช่องกรอกด้วย Widget InputDecoration

ใน Widget InputDecoration มี Property หลายอย่างช่วยแสดง Placeholder Text และ Label เหนือช่องกรอก ยังใช้ Property border แสดงขอบโค้งมน

Build และรัน จะได้ผลลัพธ์ใน Emulator:

สร้างแอปคำนวณค่าทิปด้วย Flutter: คู่มือขั้นตอนต่อขั้นตอน

ขั้นตอนที่ 5: เพิ่ม Event Listener และ Function

เนื่องจากจะคำนวณค่าทิปทันทีที่ผู้ใช้กรอกจำนวนเงินบิลหรือเปอร์เซ็นต์ จึงต้องฟังการเปลี่ยนแปลงในช่องกรอกข้อความ

เพิ่ม Event Listener ให้ Controller ด้วยเมธอด addListener

เมื่อมีการเปลี่ยนแปลงในช่องกรอก ต้องการ Trigger Function เพื่ออัปเดตจำนวนเงินบิลและเปอร์เซ็นต์ทิป

ใช้ Function ที่จำเป็นร่วมกับเมธอด setState ช่วย Render UI ใหม่ทันทีที่มีการเปลี่ยนแปลง

หมายเหตุ: เมธอด setState กระตุ้นการรันเมธอด build ใหม่

ดูโค้ดด้านล่าง:

@override void initState() { super.initState(); _billAmountController.addListener(_onBillAmountChanged); _tipPercentageController.addListener(_onTipAmountChanged); } _onBillAmountChanged() { setState(() { _billAmount = double.tryParse(_billAmountController.text) ?? 0.0; }); } _onTipAmountChanged() { setState(() { _tipPercentage = int.tryParse(_tipPercentageController.text) ?? 0; }); }

ที่นี่มีเมธอด initState ซึ่งรันทันทีที่เข้าสู่หน้าจอนี้ของแอป จึงเพิ่ม Event Listener ทันทีที่เข้าหน้าจอ

ขั้นตอนที่ 6: เพิ่มส่วนแสดงจำนวนเงิน

กลับไปที่ UI Widget จะเพิ่มส่วน Amounts ใต้ช่องกรอกข้อมูล ภายใน Widget Column

ใช้ Widget SizedBox สร้างระยะห่างระหว่าง Widget ดูโค้ดด้านล่าง:

), SizedBox(height: 20,), Container( margin: EdgeInsets.all(15), padding: EdgeInsets.all(15), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.all( Radius.circular(15), ), border: Border.all(color: Colors.white), boxShadow: [ BoxShadow( color: Colors.black12, offset: Offset(2, 2), spreadRadius: 2, blurRadius: 1, ), ], ), child: Column( children: [ Text("Tip Amount"), Text("Total Amount") ], ), ),

ที่นี่มี Container พร้อมการตกแต่ง Style Child Property มี Widget Column อีกตัวหนึ่ง จัด Widget Text 2 ตัวแนวตั้ง

Build และรัน จะได้ผลลัพธ์ใน Emulator:

สร้างแอปคำนวณค่าทิปด้วย Flutter: คู่มือขั้นตอนต่อขั้นตอน

ขั้นตอนที่ 7: สร้าง Stateless Widget แยกต่างหากเพื่อแสดงจำนวนเงิน

เนื่องจากต้องการแสดง Tip Amount และ Total Amount พร้อมสไตล์เล็กน้อย จะไม่มี State แต่ขึ้นอยู่กับค่าที่ส่งมาจาก Stateful Widget

ดูโค้ดคลาส Stateless Widget AmountText ด้านล่าง:

class AmountText extends StatelessWidget { final String text; const AmountText( this.text, { Key key, }) : super(key: key); @override Widget build(BuildContext context) { return Container( padding: EdgeInsets.all(8), child: Text(text.toUpperCase(), style: TextStyle(fontWeight: FontWeight.bold, color: Colors.blueAccent, fontSize: 20)), ); } }

ใช้ Constructor Class รับค่า Text ที่จะแสดง เมธอด build คืนค่า Widget Container พร้อม padding และ Widget Text เป็น Child

พร้อม Widget AmountText แล้ว ตอนเรียกใช้ใน Stateful Widget

เพิ่ม Widget ภายใน Widget Column ที่กำหนดไว้ก่อนหน้านี้แทน Widget Text ธรรมดา ส่งค่า Text ที่ต้องการ

ดูโค้ดด้านล่าง:

Container( margin: EdgeInsets.all(15), padding: EdgeInsets.all(15), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.all( Radius.circular(15), ), border: Border.all(color: Colors.white), boxShadow: [ BoxShadow( color: Colors.black12, offset: Offset(2, 2), spreadRadius: 2, blurRadius: 1, ), ], ), child: Column( children: [ AmountText( 'Tip Amount: ${_getTipAmount()}', key: Key('tipAmount'), ), AmountText( 'Total Amount: ${_getTotalAmount()}', key: Key('totalAmount'), ), ], ), ),

ส่ง Function ไปใน Widget AmountText Function คืนค่า Tip Amount และ Total Amount ตามโค้ดด้านล่าง:

_getTipAmount() => _billAmount * _tipPercentage / 100; _getTotalAmount() => _billAmount + _getTipAmount();

สุดท้าย ต้องยกเลิก Controller เมื่อออกจาก View ใช้ฟังก์ชัน dispose ในตัว ซึ่งรันขณะออกจากหน้าจอปัจจุบัน

ในเมธอดนี้ เรียก Controller ด้วยเมธอด dispose เพื่อยกเลิก Text Input Controller จะหยุดฟังการเปลี่ยนแปลงในช่องกรอก

ดูฟังก์ชัน dispose ด้านล่าง:

@override void dispose() { // ทำให้แน่ใจว่าไม่รั่วไหล ยกเลิก TextEditingController ที่ใช้ // เมื่อ Widget ถูกลบออกจากหน่วยความจำ _billAmountController.dispose(); _tipPercentageController.dispose(); super.dispose(); }

Build และรัน เพื่อดูผลลัพธ์สุดท้ายของแอปคำนวณค่าทิปใน Demo ด้านล่าง:

สร้างแอปคำนวณค่าทิปด้วย Flutter: คู่มือขั้นตอนต่อขั้นตอน

สังเกตว่าค่าทั้งสองจำนวนเปลี่ยนไปตาม Input ในช่องกรอก

จบบทเรียนนี้แล้ว คุณสร้างแอปคำนวณค่าทิปง่ายๆ ด้วยเฟรมเวิร์ก Flutter และ Dart เรียบร้อยแล้ว

ขั้นตอนต่อไป

จุดประสงค์หลักคือสอนรูปแบบการเขียนโปรแกรมพื้นฐานในเฟรมเวิร์ก Flutter ผ่านการสร้างแอปคำนวณค่าทิปง่ายๆ

ยังมี Widget และฟีเจอร์น่าสนใจอีกมากมายให้สำรวจ สามารถเปลี่ยน UI ของแอปได้ พร้อมรักษา Component ฟังก์ชันเดิมไว้

โดยรวม Flutter ทำให้การออกแบบ UI ที่ซับซ้อนกลายง่ายด้วยรูปแบบ Widget สร้าง UI ที่ยอดเยี่ยมได้เพียงแค่ซ้อน Widget ผ่าน Property Child

ขั้นตอนต่อไปอาจใช้ Mechanism การนำทางของ Flutter ไปหน้าจออื่น Flutter ยังทำให้การเพิ่ม Custom Drawer Menu และ Bottom Tabs ง่ายขึ้น

นี่คือจุดเริ่มต้นของการพัฒนา Flutter ยังมีอะไรอีกมาก เราต้องสำรวจและเขียนโค้ดต่อไป

Demo ของโปรเจกต์ทั้งหมดมีบน Codepen

สามารถหาแรงบันดาลใจสำหรับแอป Flutter ของคุณจากแอปที่มีอยู่แล้ว

Happy Coding!