web analytics

Flutter Project : สร้างแอปเครื่องคิดเลขง่ายๆด้วย Flutter

cove

สวัสดีครับ บล็อกนี้เป็นบล็อกที่ทำค้างไว้นาน เป็นเรื่องเกี่ยกวับการทำแอปเครื่องคิดเลขแบบง่ายๆ ผมเขียนไว้ตอนหัดเขียน Flutter ใหม่ๆ แต่ไหนๆก็เขียนแล้วก็เลยมาต่อให้จบ ซึ่งแอปเครื่องคิดเลขมักจะเป็นโจทย์ classic สำหรับตอนเราหัดเขียนโปรแรกม จะว่าไปแล้วผมเองก็เขียนแอปเครื่องคิดเลขนี้มาหลายครั้งอยู่เหมือนกัน เขียนใน Windows Form , Windows 10 App , Android แล้วก็มา Flutter

 

เริ่มต้น

ประเด็นหลักคือ เรียนรู้เกี่ยวกับการทำ layout ใน Flutter เลยจะไม่เน้นเรื่องของฟังชันก์นะ
โดยจะลอกหน้าตา แอปเครื่องคิดเลขใน Windows 10 แบบนี้

1

 

New Flutter Project กันเลย

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Calculator',
      theme: ThemeData(
        primarySwatch: Colors.blueGrey,
      ),
      home: MyCalculatorPage(title: 'Calculator'),
    );
  }
}

class MyCalculatorPage extends StatefulWidget {
  MyCalculatorPage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyCalculatorPageState createState() => _MyCalculatorPageState();
}

class _MyCalculatorPageState extends State<MyCalculatorPage> {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'Calculator',style: TextStyle(fontSize: 28),
            ),
            Text(
              'Hello',style: TextStyle(fontSize: 18),
            ),
          ],
        ),
      )
    );
  }
}

 

ทำส่วนแสดงคำตอบ เป็นช่องว่างด้านบน

class _MyCalculatorPageState extends State<MyCalculatorPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Column(
        children: <Widget>[
          buildAnswerWidget(),
        ],
      ),
    );
  }

  Widget buildAnswerWidget() {
    return Container(
        padding: EdgeInsets.all(16),
        constraints: BoxConstraints.expand(height: 180),
        color: Color(0xffecf0f1),
        child: Align(
            alignment: Alignment.bottomRight,
            child: Column(mainAxisSize: MainAxisSize.min, children: <Widget>[
              Text("12 +", style: TextStyle(fontSize: 18)),
              Text("8",
                  style: TextStyle(fontSize: 48, fontWeight: FontWeight.bold))
            ])));
  }
}

3

 

ทำส่วนปุ่มตัวเลข ลองทำแค่แถวเดียวก่อน

  Widget buildNumPadWidget() {
    return Container(
        color: Color(0xffecf0f1),
        child: Column(
          children: <Widget>[
            Row(children: <Widget>[
              Expanded(
                  child: Container(
                      color: Colors.white,
                      height: 100,
                      child: Center(
                          child: Text("1",
                              style: TextStyle(
                                  fontSize: 24,
                                  fontWeight: FontWeight.bold))))),
              Expanded(
                  child: Container(
                      color: Colors.white,
                      height: 100,
                      child: Center(
                          child: Text("2",
                              style: TextStyle(
                                  fontSize: 24,
                                  fontWeight: FontWeight.bold))))),
              Expanded(
                  child: Container(
                      color: Colors.white,
                      height: 100,
                      child: Center(
                          child: Text("3",
                              style: TextStyle(
                                  fontSize: 24,
                                  fontWeight: FontWeight.bold))))),
            ])
          ],
        ));
  }

 

เพิ่ม NumPad ต่อจากช่องคำตอบ

  @override
  Widget build(BuildContext context) {
      ...
      body: Column(
        children: <Widget>[
        buildAnswerWidget(),
        buildNumPadWidget()
      ],
      ),
    );
  }

4

 

ทำแถวของปุ่มตัวเลขเพิ่ม

  Widget buildNumPadWidget() {
    return Container(
        color: Color(0xffecf0f1),
        child: Column(
          mainAxisSize: MainAxisSize.max,
          children: <Widget>[
            Row(children: <Widget>[
              buildNumberButton("7"),
              buildNumberButton("8"),
              buildNumberButton("9"),
            ]),
            Row(children: <Widget>[
              buildNumberButton("4"),
              buildNumberButton("5"),
              buildNumberButton("6"),
            ]),
            Row(children: <Widget>[
              buildNumberButton("1"),
              buildNumberButton("2"),
              buildNumberButton("3"),
            ]),
          ],
        ));
  }

  Expanded buildNumberButton(String str) {
    return Expanded(
        child: Container(
            color: Colors.white,
            height: 100,
            child: Center(
                child: Text(str,
                    style: TextStyle(
                        fontSize: 24, fontWeight: FontWeight.bold)))));
  }

5

 

เพิ่มปุ่ม บวกลบคูณหารและปุ่มสัญลักษณ์พิเศษต่างๆ

  Widget buildNumPadWidget() {
    return Container(
        color: Color(0xffecf0f1),
        child: Column(
          mainAxisSize: MainAxisSize.max,
          children: <Widget>[
            Row(children: <Widget>[
              buildNumberButton("CE"),
              buildNumberButton("C"),
              buildNumberButton("⌫"),
              buildNumberButton("÷"),
            ]),
            Row(children: <Widget>[
              buildNumberButton("7"),
              buildNumberButton("8"),
              buildNumberButton("9"),
              buildNumberButton("×"),
            ]),
            Row(children: <Widget>[
              buildNumberButton("4"),
              buildNumberButton("5"),
              buildNumberButton("6"),
              buildNumberButton("-"),
            ]),
            Row(children: <Widget>[
              buildNumberButton("1"),
              buildNumberButton("2"),
              buildNumberButton("3"),
              buildNumberButton("+"),
            ]),
            Row(children: <Widget>[
              buildNumberButton("±"),
              buildNumberButton("0"),
              buildNumberButton("."),
              buildNumberButton("="),
            ]),
          ],
        ));
  }

  Expanded buildNumberButton(String str) {
    return Expanded(
        child: Container(
          margin: EdgeInsets.all(2),
            color: Colors.white,
            height: 70,
            child: Center(
                child: Text(str,
                    style: TextStyle(
                        fontSize: 32, fontWeight: FontWeight.bold)))));
  }

b1

 

ใส่สีของปุ่มให้แตกต่างกัน ถ้าเป้นปุ่มตัวเลขจะพืนหลังต่างจากปุ่มอื่นๆ

  Expanded buildNumberButton(String str, {bool numberButton = true}) {
    if (numberButton) {
      return Expanded(
          child: Container(
              margin: EdgeInsets.all(1),
              color: Colors.white,
              height: 70,
              child: Center(
                  child: Text(str,
                      style: TextStyle(
                          fontSize: 32, fontWeight: FontWeight.bold)))));
    } else {
      return Expanded(
          child: Container(
              margin: EdgeInsets.all(1),
              color: Color(0xffecf0f1),
              height: 70,
              child: Center(
                  child: Text(str,
                      style: TextStyle(
                          fontSize: 28)))));
    }
  }

b2

 

ต่อมาทำให้ปุ่มสามารถกดตัวเลขแล้วไปแสดงที่หน้าจอคำตอบได้
ก็ประกาศตัวแปรใน state

  String answer;

  @override
  void initState() {
    answer = "0";
    super.initState();
  }

 

เอาค่าไปใส่ที่ Text

  Widget buildAnswerWidget() {
    ...
              Text(answer,
                  style: TextStyle(fontSize: 48, fontWeight: FontWeight.bold))
            ]))));
  }

 

ที่ปุ่มตัวเลข เพิ่ม parameter เพื่อรับ function ว่ากดแล้วให้ทำอะไร

  Widget buildNumberButton(String str, { @required Function()onTap, bool numberButton = true}) {
    Widget widget;
    if (numberButton) {
      widget = GestureDetector(onTap: onTap,
          ...
      );
    } else {
      widget = GestureDetector(onTap: onTap,
          ...
      );
    }

    return Expanded(child: widget);
  }

 

เพิ่ม onTap ให้ปุ่ม ปุ่มกดแล้วให้เพิ่มเลขที่ไปช่องคำตอบ

Widget buildNumPadWidget() { 
            ...
            Row(children: <Widget>[
              buildNumberButton("1", onTap: () {
                addNumberToAnswer(1);}),
              buildNumberButton("2", onTap: () {
                addNumberToAnswer(2);}),
              buildNumberButton("3", onTap: () {
                addNumberToAnswer(3);}),
              buildNumberButton("+", numberButton: false, onTap: () {}),
            ]),
            ...
}

 

ที่ method สำหรับกดตัวเลขก็เช็คเงื่อนไขเล็กน้อย เช่น ถ้ามีค่าเป็น 0 จะ 0 ซ้อนกันไม่ได้

  void addNumberToAnswer(int number) {
    setState(() {
      if(number == 0 && answer == "0"){
       // Not do anything.
      }
      else if(number != 0 && answer == "0"){
        answer = number.toString();
      }
      else{
        answer += number.toString();
      }
    });
  }

a2

 

จากนั้นก็เพิ่ม method อื่นๆ ให้ครบ ซึ่งไม่น่าจะแยกแล้ว เช่น ปุ่ม backspace ลบตัวเลขตัวสุดท้ายออก

  void removeAnswerLast() {
    if (answer == "0") {
      // Not do anything.
    } else {
      setState(() {
        if(answer.length > 1) {
          answer = answer.substring(0, answer.length - 1);
        }else{
          answer = "0";
        }
      });
    }
  }

 

              buildNumberButton("⌫", numberButton: false, onTap: () {  
                removeAnswerLast();
              }),

a3

 

ปรับแต่งให้สวยงาม

b3

 

โค้ดแบบเต็มๆ ดูกันที่ Github เลย

https://github.com/benznest/calculator-app-flutter