แนะนำ Basic Widget ที่ควรรู้สำหรับใช้งาน Flutter เบื้องต้น

เขียนเมื่อ 4 ปีก่อน โดย Ninenik Narkdee
basic widget flutter widget scaffold

คำสั่ง การ กำหนด รูปแบบ ตัวอย่าง เทคนิค ลูกเล่น การประยุกต์ การใช้งาน เกี่ยวกับ basic widget flutter widget scaffold

ดูแล้ว 24,428 ครั้ง




เนื้อหาตอนที่แล้ว เราได้ทำความเข้าใจเบื้องต้นเกี่ยวกับ
การใช้งาน Stateless และ Stateful widget รวมถึงการจัดการ
package โดยแยกส่วนของ widget ออกมาเป็น ไฟล์ย่อย
และ import มาใช้งานอีกที สามารถทบทวนได้ที่บทความ
    การใช้งาน Stateless และ Stateful Widget ใน Flutter เบื้องต้น
 
เราจะใช้เนื้อหาจากโค้ดในตอนที่แล้ว มาประกอบการอธิบายสำหรับแนะนำการใช้งาน 
Basic wdget หรือ widget เบื้องต้นที่ควรรู้ โดยจะสนใจเฉพาะส่วนของไฟล์ first_screen.dart 
ซึ่งมีการใช้งาน Scaffold widget ที่เป็น StatefulWidget  เราจะทำความเข้าใจเกี่ยวกับ
การออกแบบหน้าตา UI โดยใช้งาน widget เบื้องต้น และ Scaffold ก็เป็นส่วนหนึ่งด้วย
ติดตาม รายละเอียดตามลำดับ
 

 

การใช้งาน Flutter Hot Reload

    ก่อนไปดูเรื่องการใช้งาน widget พื้นฐาน สิ่งที่ขาดไม่ได้คือ เครื่องมือ ที่จะทำให้เราสามารถดูผลลัพธ์จากการปรับแต่งโค้ด ได้ในทันที
ที่มีการเปลี่ยนแปลงเกิดขึ้น โดยเฉพาะภายใน widget ที่อยู่ใน Scaffold ซึ่งเป็น stateful widget โดยไฟล์ first_screen.dart เริ่มต้นใน
Android Studio ของเราเมื่อเปิดมาจะเป็นดังนี้
 
import 'package:flutter/material.dart';

// ส่วนของ Stateful widget
class FirstScreen extends StatefulWidget{
    @override
    State<StatefulWidget> createState() {
        return _FirstScreen();
    }
}
class _FirstScreen extends State<FirstScreen>{
    @override
    Widget build(BuildContext context) {
        return Scaffold(
            appBar: AppBar(
                title: Text('Welcome to Flutter'),
                backgroundColor: Colors.green
            ),
            body: Material(
                color: Colors.lightGreen,
                child: Center(
                    child: Text(
                        'Hello World',
                        style: TextStyle(
                            color: Colors.white,
                            fontSize: 20.0
                        )
                    )
                )
            )
        );
    }
}
    ซึ่งเราจะสนใจเฉพาะ ส่วนของ _FirstScreen State ที่จะมีการเปลี่บนแปลง เมื่อทำการปรับแต่ง widget ภายใน เบื้องต้นให้เราทำการ 
รัน App ปกติ โดยกดปุ่ม Run ตามรูปด้านล่าง
 
 

 
 
    เมื่อ App รันขึ้นมาและขึ้นข้อความคำว่า "Hello World" สีขาว แสดงตรงกลางหน้าจอ ตามรูปในผลลัพธ์ในตอนที่ผ่านมา รูปด้านล่าง
แสดงเฉพาะส่วนของข้อความ
 
 

 
 
    ที่แถบเครื่องมือ ให้เราคลิกที่ปุ่มสายฟ้าสีเหลือง หรือปุ่ม Flutter Hot Reload 
 
 

 
 
    แล้วสังเกตการทำงานในส่วนของ console ในแท็บ run
 
 

 
 
    ตอนนี้โหมดการทำงานแบบ hot reload เริ่มทำงานแล้ว ถ้าเราทำการแก้ไข ข้อมูล หรือ ปรับแต่ง ค่าต่างๆ ของ widget แล้วทำการกดปุ่ม
Ctrl + S เพื่อบันทึก ผลลัพธ์ในส่วนของ Emulator ก็จะเปลี่ยนตามรูปแบบที่กำหนดในทันที ทำให้เราทำการพัฒนา App ได้เร็วขึ้น แทนที่จะ
ต้องมากด Run เพื่อ rebuild ทั้งหมดใหม่ทุกครั้ง  โดย hot reload จะทำการอัพเดทส่วนของ stateful ที่เราใช้งาน ตัวอย่างเราปรับข้อความ
เป็นสีดำ และกำหนดเป็นตัวหนา พื้นหลังสีขาว ก็จะได้เป็น
 
 

 
 
    สามารถหยุดการใช้งาน hot reload โดยคลิกที่ปุ่ม stop ที่เครื่องมือ แล้ว กด Run เพื่อทำงาน App ใหม่ปกติ
 

 
 

การใช้งาน Text Widget

    Text widget เป็น widget พื้นฐาน ใช้สำหรับแสดงข้อความ โดยใช้รูปแบบ Text() เช่น Text('Hello World') 
เมื่อทำการจัดรูปแบบ ข้อความ "Hello World" ก็จเป็นการกำหนดรูปแบบให้กับข้อความทั้งหมด ไม่สามารถแยกกำหนด
ให้กับคำว่า "Hello" และ "World" แยกรูปแบบกันไม่ได้ ยกตัวอย่างเช่น การกำหนดค่าจากผลลัพธ์ด้านบน ที่ผ่านมา ก็ได้เป็น
 
 
child: Text(
    'Hello World',
    style: TextStyle(
        color: Colors.black,
        backgroundColor: Colors.white,
        fontWeight: FontWeight.bold,
        fontSize: 20.0
    )
)
 
    หากข้อความมีความยาวมากๆ ก็จะทำการตัดบรรทัดให้อัตโนมัติตามความกว้างหรือขนาดของหน้าจอ หรือไม่ก็แสดงอยู่ในบรรทัดเดียว
ถ้าความยาวของข้อความ ยังไม่เกินขอบเขตความกว้างของหน้าจอ ดูตัวอย่าง เมื่อกำหนดข้อความให้ยาวขึ้น
 
 

 
 
    ใช้การจัดรูปแบบให้ตัดคำเมื่อยาวเกินขอบเขตของความกว้างหน้าจอ โดยไม่ต้องขึ้นบรรทัดใหม่

 
 
child: Text(
    'ทดสอบข้อความ กำหนดให้ยาวกว่าความกว้างหน้าจอ',
    overflow: TextOverflow.ellipsis,
    style: TextStyle(
        color: Colors.black,
        backgroundColor: Colors.white,
        fontWeight: FontWeight.bold,
        fontSize: 20.0
    )
)
 

 
 
    ผลลัพธ์ที่ได้

 

 
 
    ข้างต้นเป็นการใช้งานรูปแบบทั่วไป เราสามารถใช้รูปแบบที่กำหนด style ให้กับแต่ละคำในข้อความหรือในประโยคโดยใช้ Text.rich()
ซึ่งเป็นการใช้งาน name constructor ตามตัวอย่างดังนี้
 
 
child: const Text.rich(
  TextSpan(
    text:'Hello',
    children: <TextSpan>[
      TextSpan(
        text:'beautiful',
        style: TextStyle(
          color:Colors.pink,
          fontStyle:FontStyle.italic
        )
      ),
      TextSpan(
        text:'world',
        style: TextStyle(
          color:Colors.yellow,
          fontWeight: FontWeight.bold
        )
      ),      
    ]
  )
)
 

 
 
    ผลลัพธ์ที่ได้
 
 

 
 
    ในตัวอย่างพยายามแยกเป็นบรรทัด ให้เห็นแต่ละส่วนของค่า widget และการกำหนดค่าง่ายขึ้น แต่ในการใช้งานจริง เราอาจะลดบรรทัดลง
เช่นบางส่วนสามารถ เขียนรวมไว้ในบรรทัดเดียวได้
 
    สำหรับการใช้งาน Text widget เราคงไม่อธิบายทุกคำสั่ง ทุกการใช้งาน แต่จะให้แนวทาง ดังนี้คือ ให้ดูส่วนของ API ประกอบ โดยเปิด
ไปที่ Text Widget API
 
    โดยแนวทางคือ ข้อความที่ใช้การจัดรูปแบบเดียวทั้งประโยค ให้เราใช้ Text() contrtutor และสามารถกำหนด property เพิ่มเติม โดยดู
จาก parameter ที่เป็น options ส่วนข้อความที่ต้องการกำหนด style หรือจัดรูปแบบเป็นคำๆ หรือบางส่วนไม่รวมทั้งประโยค ให้ใช้เป็น 
const Text.rich() แทนตามตัวอย่างด้านบน
 


 

การใช้งาน Icon Widget

    เราน่าจะคุ้นเคยกับคำว่า icon อยู่แล้ว ซึ่งก็คือรูปกราฟิคที่แสดงหรือสือ่ความหมายถึงบางสิ่ง โดยส่วนใหญ่แล้ว ทั้งชื่อและภาพสัญลักษณฺ์
ก็จะสือความหมายอยู่ในตัวอยู่แล้ว ปกติ icon จะไม่รองรับการกระทำหรือคำสั่งจากผู้ใช้โดยตรง แต่ก็มักถูกนำไปประกอบหรือใช้ร่วมกับปุ่ม
ต่างๆ เพื่อให้ผู้ใช้ตัดสันใจหรือเลือกทำคำสั่งตามต้องการ
    Icon widget มีรูปแบบการกำหนดการใช้งานที่ง่าย และปรับค่าไม่มากนัก หลักๆ คือกำหนดชื่อของ icon ที่ต้องการ โดยใช้จากรายการ
ตามลิ้งค์ https://api.flutter.dev/flutter/material/Icons-class.html โดยแต่ละ icon เป็น ค่าคงที่
    รูปแบบการใช้งาน เช่น icon โน๊ตตัวเขบ็ต 1 ชั้น สีเขียว ขนาด 30 pixels
 
 
Icon(Icons.audiotrack,color: Colors.green,size: 30.0)
 
    audiotrack คือชื่อ icon อ้างอิงข้อมูล IconData ที่ต้องการใช้งาน
    ตัวอย่างเรากำหนด icon favorite ในโค้ดของเรา 
 
 
child: Center(
  child: Icon(
    Icons.favorite,
    color: Colors.pink,
    size: 24.0
  ),
),
 

 
 
    ผลลัพธ์ที่ได้
 
 

 
 
    Icon มีรูปแบบการใช้งานไม่ซับซ้อน สามารถใช้ร่วมกับส่วนอื่นๆ ได้ ดู property ต่างๆ เพิ่มเติมได้ที่ Icon Widget API
    
 
 
 

การใช้งาน Image Widget

    Image Widget เป็น widget ที่ใช้สำหรับแสดงรูปภาพ โดยสามารถรูปแบบการเรียกใช้งานผ่านการกำหนด constructor ต่างๆ 
ตามชนิด ประเภท หรือแหล่งข้อมูลของรูปที่ต้องการใช้งาน รองรับไฟล์รูป JPEG, PNG, GIF, Animation GIF, WebP, Animation WebP,
BMP และ WBMP 
    รูปแบบการเรียกใช้งาน สามารถใช้งาน Default constructor ซึ่งสามารถลือกแหล่งข้อมูลรูปภาพใดๆ ก็ได้ ยกตัวอย่างเช่น ใช้รูปภาพ
จาก NetworkImage เพื่อใช้งานรูปภาพจากอินเตอร์เน็ตผ่านการกำหนด url ของ ภาพนั้นๆ ตัวอย่างเช่น
 
 
child: Center(
  child: const Image(
      image:NetworkImage('https://flutter.github.io/assets-for-api-docs/assets/widgets/owl.jpg'),
      height: 200,
    )
),
 

 
    ผลลัพธ์ที่ได้
 
 

 
 
    หรือจะใช้ named constructror เฉพาะสำหรับรูปที่ใช้จาก url โดยใช้งาน Image.network() ตามตัวอย่างด้านล่างก็ได้

 
 
child: Center(
  child: Image.network(
    'https://flutter.github.io/assets-for-api-docs/assets/widgets/owl.jpg',
    height: 200,
  )
),
 

 
    กรณีเราต้องการใช้งานรูปภาพพิเศษ หรือรูปภาพที่ใช้ใน App ของเราโดยเฉพาะ โดยจะถูกรวมเข้ามากับไฟล์ App ของเรา สามารถทำได้
ดังนี้ เริ่มต้นให้เราเตรียมไฟล์รูปภาพที่ต้องการ สมมติเราได้ป็นไฟล์ png 2 รูปคือ avatar.png และ logo.png ต่อไปให้เราคลิกขวาที่โฟลเดอร์
โปรเจ็ค เพื่อทำการสร้าง โฟลเดอร์สำหรับเก็บรูปภาพ โดยเลือกเมนู "New" > "Directory" ดังรูป
 
 

 
 
    ในที่นี้เราจะสร้างโฟลเดอร์ "assets" และสร้างโฟลเดอร์ "images" ไว้ด้านในอีกที จากนั้นทำการ copy รูปภาพ แล้วนำมาวางในโฟลเดอร์
ที่ได้สร้างไว้ จะได้ดังนี้
 
 

 
 
    ตอนนี้เมื่อเราเรียกใช้งาน Image.asset('assets/images/avatar.png') รูปจะยังไม่แสดง เราต้องทำการเพิ่มรูปเข้าไปในไฟล์ 
pubspec.yaml เพื่อลงทะเบียนหรือบอกกับ App ให้รู้จักรูปที่จะมีการใช้งานใน App โดยดูในส่วนของ การกำหนด assets หาก comment ไว้
ให้เอาออก และเพิ่ม รูปที่จะใช้งานเข้าไปดังนี้
 
 

 
 
    การแก้ไขไฟล์ pubspect.yaml กรณีนี้ เราจำเป็นต้องทำการรัน App ใหม่อีกครั้งก่อนใช้งาน ระวังในเรื่อง ช่องว่าง ระยะห่าง tab ระหว่าง
คำว่า "assets" ต้องให้อยู่ในแนวที่ถูกต้อง ตามรูปด้านบน เรียกใช้งาน ใหม่อีกครั้ง
 
 
child: Center(
  child: Image.asset(
    'assets/images/logo.jpg',
    height: 100,
  )
),
 

 
 
    ผลลัพธ์ที่ได้
 
 

 
 
    การปรับแต่ง และกำหนด property ต่างๆ เพิ่มเติม สามารถดูได้ที่ Image Widget API
    
 
 
 

การใช้งาน Container Widget

    เป็น widget ที่ใช้กำหนดพื้นที่จัดการที่สามารถจัดตำแหน่ง ขนาด รวมถึงการตกแต่งวาดลวดลาย หรือลงสีให้สวยงามได้
    การใช้งาน container ปกติแล้วขนาดจะขยายเต็มพื้นที่ ถ้าไม่มี child หรือถ้าไม่มีการจำกัดขอบเขต หรือขนาดจาก parent อีกที
สังเกตตัวอย่างโค้ดด้านล่าง ประกอบทำความเข้าใจ 
 
 
child: Center(
  child: Container(
    color: Colors.red[600],
    child: Container(
      margin: const EdgeInsets.all(20.0),
      padding: const EdgeInsets.all(10.0),
      color: Colors.blue[600],
      child: Image.asset(
        'assets/images/logo.jpg',
      ),
    ),
  )
),
 

 
 
    จากโค้ดเราใช้งาน container 2 ตัวซ้อนกัน ตัวแรกกำหนดสีเป็น สีแดง ตัวที่สองเป็นสีน้ำเงิน โดยตัวสีน้ำเงินเรากำหนด padding
เท่ากับ 10 px (pixels) นั่นคือ child ของมันจะขยับจากขอบ 10 px หรือก็คือ รูปภาพที่เป็น Image Widget ห่างจากขอบทุกด้าน
เท่ากัน 10 px นากจากนั้น เรากำหนด margin ให้กับ สีน้ำเงิน นั้นคือ สีน้ำเงินขยับห่างจากขอบของสีแดงที่เป็น parent 20 px
    เนื่องจากรูปภาพด้านใน เราไม่ได้กำหนดขนาด ดังนั้น container จึงขยายขนาดเต็มสุด นั่นคือตัว container นอกสุดหรือสีแดง
ขนายขนาดเต็มหน้าจอ ในขณะสีน้ำเงิน container ตัวที่แสดง ขนาดลดลงจาก margin ด้านละ 20 px 
 
    ผลลัพธ์ที่ได้
 
 

 
 
    แต่เมื่อเรากำหนดขนาดรูปที่อยู่ด้านในสูงเท่ากับ 100 px ขนาดของ container ที่ไม่ได้กำหนดความกว้าง ความสูง ก็จะมีขนาด
ลดลงตามขอบเขตของ child  โดยสีน้ำเงิน จะมีขนาดความสูง 120 px คือมาจากขนาดของรูป 100 px บวก padding บน-ล่าง
อย่างละ 10 รวมทั้งหมดเป็น 120 px ในขณะที่ สีแดงจะสูงเท่าขนาดสีนำเงิน บวก margin บน-ล่าง หรือก็คือ 160 px
 
 
child: Center(
  child: Container(
    color: Colors.red[600],
    child: Container(
      margin: const EdgeInsets.all(20.0),
      padding: const EdgeInsets.all(10.0),
      color: Colors.blue[600],
      child: Image.asset(
        'assets/images/logo.jpg',
        height: 100,
      ),
    ),
  )
),
 

 
 
    ผลลัพธ์ที่ได้

 

 
 
    ต่อมา ถ้าเราลองจำกัดพื้นที่ของสีน้ำเงิน โดยให้ความสูงเท่ากับ 100 px โดยการกำหนดความสูง จะเป็นการรวมถึงว่า รวม padding
แล้ว จะไม่เหมือนกรณีที่ไม่ได้จำกัดขนาด ซึ่งเมื่อกำหนดจำกัดที่ 100 px ซึ่งรวม padding จะทำให้ขนาดของรูปลดลง และการกำหนด
ขนาดความสูงของรูปเท่ากับ 100 จึงไม่มีผลใดๆ เพราะถูกจำกัดอยู่ในพื้นที่ container สีน้ำเงินแล้ว
 
 
child: Center(
  child: Container(
    color: Colors.red[600],
    child: Container(
      margin: const EdgeInsets.all(20.0),
      padding: const EdgeInsets.all(10.0),
      color: Colors.blue[600],
      height: 100,
      child: Image.asset(
        'assets/images/logo.jpg',
        height: 100,
      ),
    ),
  )
),
 

 
 
    ผลลัพธ์ที่ได้
 
 

 
 
    ดูคำสั่งการใช้งาน และ property เพิ่มเติมได้ที่ Container Widget API
    
 
 
 

การใช้งาน ElevatedButton Widget

    เป็น widget หนึ่งจาก Material design ลักษณะเป็นปุ่มที่มีการยกขึ้นมาเล็กน้อย โดยเมื่อทำการกด ก็จะมี effect คล้ายเงาบุ๋ม
กระจายตัวจากบริเวณที่กด เป็นวงออกมา แล้วจางหายไป
    ถ้ากำหนด onPressed เป็น null หรือไม่มีการทำคำสั่งใดๆ เมื่อกด ปุ่มก็จะแสดงในลักษณะเป็น Disable ราบเรียบไม่มีการยกขึ้นมา
สังเกตตัวอย่างปุ่ม ที่กำหนด onPressed: null, และ onPressed: () {}, จะได้เป็นดังนี้
 
 

 

 
 
    ตัวอย่างการกำหนดปุ่ม
 
 
child: Center(
  child: ElevatedButton(
    onPressed: (){},
    child: Text(
      'Button Test',
      style: TextStyle(fontSize: 20),
    ),
  )
),
 
    สังเกตว่ามีการใช้งาน Text widget กำหนดเป็น child สำหรับแสดงข้อความของปุ่ม เป็นรูปแบบการใช้งานอย่างง่าย เพราะเรายังสามารถ
ปรับ child จาก text widget เป็นการประยุกต์รวมกับ widget อื่นๆ เพื่อแต่งปุ่มให้สวยงามได้ เช่น ใช้งาน Container widget เพื่อสร้าง
ปุ่มแบบ Gradient ตัวอย่างการใช้งาน Container และยังไม่ได้ตกแต่งเป็น Gradient 
 
 
child: Center(
  child: ElevatedButton(
    onPressed: (){},
    child:Container(
      padding: const EdgeInsets.all(10.0),
      child: Text(
        'Button Test',
        style: TextStyle(fontSize: 20),
      ),
    ),   
  )
),
 
    สังเกตว่าปุ่มมีส่วนของ padding เพิ่มเข้ามา
 
 

 
 
    ต่อไป เราปรับแต่ง container widget ด้วย decoration กำหนดการแสดงป็นแบบ gradient และใช้ข้อความปุ่ม เป็นสีขาว
 
 
child: Center(
  child: ElevatedButton(
    onPressed: (){},
    style: ElevatedButton.styleFrom(
      padding: EdgeInsets.all(0)
    ),
    child:Container(
      decoration: BoxDecoration(
        gradient: LinearGradient(
          colors:<Color>[
            Color(0xFF0D47A1),
            Color(0xFF1976D2),
            Color(0xFF42A5F5),
          ],
          begin: Alignment.topLeft, // Start gradient from top left
          end: Alignment.bottomRight, // End gradient at bottom right                
        ),
        borderRadius:  BorderRadius.circular(20.0), 
      ),
      padding: const EdgeInsets.symmetric(
        vertical: 10.0,
        horizontal: 30.0,
      ),
      child: Text(
        'Button Test',
        style: TextStyle(
          color: Colors.white,
          fontSize: 20,
        ),
      ),
    ),
  ),
),
 
    ผลลัพธ์ที่ได้
 
 

 
 
    นอกจากการกำหนดเป็นข้อความ แล้วเรายังสามารถกำหนดใช้งาน Icon widget เพื่อสร้างเป็นปุ่มที่มี icon ประกอบด้วย โดยใช้
ElevatedButton.icon() contructor ดังนี้
 
 
child: Center(
  child: ElevatedButton.icon(
    onPressed: (){},
    icon: Icon(
      Icons.add_a_photo,
      color: Colors.white, 
    ),
    style: ElevatedButton.styleFrom(
      backgroundColor: Colors.blue, // Optional: Set background color
    ),    
    label: const Text(
        'Button Test',
        style: TextStyle(
          color: Colors.white,
          fontSize: 20,
        ),
      ),
  ),
),
 
    ผลลัพธ์ที่ได้
 
 

 
 
    ดูคำสั่งการใช้งาน และ property เพิ่มเติมได้ที่ ElevatedButton Widget API
    
 
 
 

การใช้งาน Placeholder Widget

    เป็น widget ที่สร้างกล่องกันพื้นที่ที่จะมีการเพิ่ม widget อื่นเข้ามาในอนาคตหรือ กันพื้นที่สำหรับ widget ที่ยังสร้างไม่เสร็จ เหมือน
กันจองขอบเขตพื้นที่ ไว้ใช้งาน มีรูปการเรียกใช้ อย่างง่ายด้วย Placeholder() หรือจะกำหนดสีขอเส้นด้วยก็ได้ เช่น 
    Placeholder(color: Colors.amberAccent) โดยขนาดเริ่มต้นจะเต็มพื้นที่ของ container หรือ parent widget ที่ใช้งาน ดูตัวอย่าง
การใช้งาน เมื่อกำหนดไว้ใน Container Widget ดังนี้
 
 
child: Center(
  child: Container(
    color: Colors.red[600],
    width: 200,
    child: Container(
      margin: const EdgeInsets.all(20.0),
      padding: const EdgeInsets.all(10.0),
      color: Colors.blue[600],
      height: 100,
      child: Placeholder(
        color: Colors.amberAccent,
      ),
    ),
  ),
),
 

 
 
    ผลลัพธ์ที่ได้
 
 

 
 
    ดูคำสั่งการใช้งาน และ property เพิ่มเติมได้ที่ Placeholder Widget API  

 
 
 

การใช้งาน Column Widget

    เป็น widget สำหรับแสดง widget ย่อยในแนวตั้ง
    Column widget ไม่รองรับการ scroll เลื่อน และไม่ควรมี child หรือ widget ย่อย จำนวนมากๆ  กรณีต้องการใช้งาน widget เรียงกัน
หลายๆ บรรทัด ให้ใช้เป็น ListVView widget (จะได้แนะนำต่อไปทีหลัง) ซึ่งรองรับการ scroll และเหมาะสมกว่า 
    ในกรณีที่ใน column มี child เดียว อาจจะใช้ Align หรือ Center widget สำหรับกำหนดตำแหน่งเพิ่มเติมได้
    ดูตัวอย่างการใช้งาน Column ที่มี 3 widget ย่อยด้านใน ในที่นี้เราคลุมด้วย Center widget อีกที
 
 
child: Center(
  child: Column(
    children: <Widget>[
      Text('Text1 in First Child'),
      Text('Text2 in Second Child'),
      Image.asset(
        'assets/images/logo.jpg',
        height: 100,
      )
    ],
  ),
),
 
 
    ผลลัพธ์ที่ได้
 
 

 
 
    Child จะเรียงจากบนลงล่างตามลำดับ ที่ตำแหน่งบนสุดติดขอบ AppBar (ถ้ามี) เนื่องจากเราใช้ Center จัดตำแหน่ง รายการจึงแสดง
กึงกลางในแนวนอน หากไม่มีการจำกัดความสูง  Column จะสูงเต็มพื้นที่หน้าจอ ส่วน Child จะสูงตามสัดส่่วน หรือการกำหนดของ Child
นั้น เช่น รูปเรากำหนดที่ 100 px ดังนั้น ความสูงของทั้ง 3 Child รวมกันก็จะไม่สูงเต็มพื้นที่ของ Column
    เราสามารถใช้ Expanded widget ขยายความสูงของ Child ที่ต้องการได้ โดยเป็นรูปแบบการใช้งานแบบ Flex นั่นคือจะดูจากพี้นที่ว่าง
ที่เหลือ แล้วจัดสัดส่วนพื้นที่ ให้เต็มความสูงของ Column หรือเต็มหน้าจอกรณีไม่ได้จำกัดความสูง สมมติเช่น เราใช้ Expanded ให้กับ
ข้อความที่สอง
 
 
child: Center(
  child: Column(
    children: <Widget>[
      Text('Text1 in First Child'),
      Expanded(
        child: Text('Text2 in Second Child'),
      ),
      Image.asset(
        'assets/images/logo.jpg',
        height: 100,
      )
    ],
  ),
),
 
    ผลลัพธ์ที่ได้
 
 

 
 
    Child ที่ 1 และ 3 จะมีขนาดความสูงเท่าเดิม แต่ Child ที่เรากำหนด Expanded เพื่อใช้งาน Flex จะขยายเต็มพื้นที่เหลืออยู่  ในลักษณะ
เดียวกัน ถ้าใช้ Expanded กับ Child ทั้ง 3 พื้นที่ความสูงของแต่ละ Child ก็จะเป็นพื้นที่ความสูงทั้งหมด หาร 3 เพื่อเฉลี่ยความสูงแต่ละ Child
ให้มีขนาดเท่าๆ กัน 
    ความกว้างของ Column จะมีขนาดเท่ากับความกว้างของ Child ที่กว้างที่สุด เราลองเอา Center ที่คลุม Column ออก ก็จะเห็นความ
กว้างของ Column สอดคล้องตามที่อธิบาย คือมีขนาดเท่าความกว้างของข้อความที่ 2 ที่กว้างที่สุด
 
 

 
 
    เมื่อไม่มีการใช้งาน Center และไม่มีการกำหนดให้ขยายให้เต็มที่ว่างโดยใช้ Expanded ความสูงค่าเริ่มต้นจะมีขนาดเต็มหน้าจอ หรือมีค่า
mainAxisSize: MainAxisSize.max ถ้ากำหนด หากต้องการให้ความสูงเท่ากับความสองของ Child สามารถกำหนดเป็น min โด้ ดังนี้
 
 
child: Column(
  mainAxisSize: MainAxisSize.min,
  children: <Widget>[
    Text('Text1 in First Child'),
    Text('Text2 in Second Child'),      
    Image.asset(
      'assets/images/logo.jpg',
      height: 100,
    )
  ],
),
 
    ผลลัพธ์ที่ได้
 
 

 
 
    เราสามารถใช้ crossAxisAlignment สำหรับจัดตำแหน่ง Child ในแนวนอน และใช้ mainAxisAlignment จัดตำแหน่ง Child ในแนวตั้ง
ดูตัวอย่างต่อไปนี้ เราจัดตำแหน่ง Child ทั้งหมด ให้อยู่ล่างสุด หรือกองอยู่ด้านล่างของ Column ด้วย MainAxisAlignment.end และ
จัดตำแหน่งในแนวนอนของ Child ให้ชิดซ้าย ด้วย CrossAxisAlignment.start
 
 
child: Column(
  crossAxisAlignment: CrossAxisAlignment.start,
  mainAxisAlignment: MainAxisAlignment.end,
  mainAxisSize: MainAxisSize.max,
  children: <Widget>[
    Text('Text1 in First Child'),
    Text('Text2 in Second Child'),      
    Image.asset(
      'assets/images/logo.jpg',
      height: 100,
    )
  ],
),
 
    ผลลัพธ์ที่ได้
 
 

 
 
    ดูคำสั่งการใช้งาน และ property เพิ่มเติมได้ที่ Column Widget API    

 
 
 

การใช้งาน Row Widget

    เป็น widget สำหรับแสดง widget ย่อยในแนวนอน
    Row widget ไม่รองรับการ scroll เลื่อน และไม่ควรมี child หรือ widget ย่อย จำนวนมากๆ  กรณีต้องการใช้งาน widget เรียงกัน
หลายๆ บรรทัด ให้ใช้เป็น ListVView widget (จะได้แนะนำต่อไปทีหลัง) ซึ่งรองรับการ scroll และเหมาะสมกว่า 
    ในกรณีที่ใน Row มี child เดียว อาจจะใช้ Align หรือ Center widget สำหรับกำหนดตำแหน่งเพิ่มเติมได้
    ดูตัวอย่างการใช้งาน Row ที่มี 3 widget ย่อยด้านใน ในที่นี้เราคลุมด้วย Center widget อีกที
 
 
child: Row(
  crossAxisAlignment: CrossAxisAlignment.center,
  mainAxisAlignment: MainAxisAlignment.start,
  mainAxisSize: MainAxisSize.max,
  children: <Widget>[
    Text('Text1 in First Child'),
    Text('Text2 in Second Child'),      
    Image.asset(
      'assets/images/logo.jpg',
      height: 100,
    )
  ],
),
 
    ผลลัพธ์ที่ได้
 
 

 
 
    ในการใช้งาน Row ใจความสำคัญแทบจะเหมือนกับรูปแบบของ Column แต่มองคนละมุมหรือมองในมุมตรงข้าม คือ ที่ความกว้างของ
Row ให้มองเทียบกับที่ความสูงของ Column และที่ความสูงของ Row ให้มองเทียบกับความกว้างของ Column รวมถึง CrossAxis และ
MainAxis ก็มองสลับกัน โดยใน Row เทียบ MainAxis เหมือนแนวนอน และ CrossAxis เหมือนแนวตั้ง อย่างในตัวอย่าง เรากำหนดให้ 
Child ในแนวนอนให้ชิดซ้ายด้วย mainAxisAlignment: MainAxisAlignment.start และกำหนดให้ Child ในแนวตั้งให้อยู่กึ่งกลางด้วย
crossAxisAlignment: CrossAxisAlignment.center จะเห็นชัดสำหรับกรณีข้อความที่แสดงตรงกลางในแนวตั้ง
    ดังนั้นจะไม่ขอยกตัวอย่างเพิ่มเติม สามารถใช้งานคล้ายกับ Column 
 
    ดูคำสั่งการใช้งาน และ property เพิ่มเติมได้ที่ Row Widget API    
 

 
 

การใช้งาน AppBar Widget

    AppBar เป็น widget ที่ประกอบไปด้วยเครื่องมือต่างๆ และอาจจะมี wiget อื่นๆ เพิ่มเติมได้ ยกตัวอย่างเช่น TabBar, FlexibleSpacBar
ถ้าเราคุ้นเคยกับการใช้งาน App เราจะพบว่า App bar จะมีปุ่มสำหรับรับคำสั่งเพื่อทำงานบางอย่าง อาจจะเป็นปุ่ม IconButtons ที่เมื่อกด
แล้วมี PopupMenuButton เพิ่มเติมให้เลือกอีกที
    AppBar เป็น property หนึ่งของ Scaffold widget ซึ่งจะเป็น widget ตัวสุดท้ายที่เราจะพูดถึงในบทความนี้  AppBar จะถูกกำหนด
ความสูงมาแบบตายตัว แสดงด้านบนสุดของหน้าจอ โดยมี widget เครื่องมือต่างๆ แสดงด้านในอีกที เช่น leading, title, และ action
และ อาจจะมี bottom กรณีมีการใช้งาน TabBar ดูส่วนของการกำหนดการใช้งาน AppBar และผลลัพธ์ที่ได้
 
 
appBar: AppBar(
  iconTheme: IconThemeData(
    color: Colors.white,
  ),
  leading: IconButton(
    onPressed: (){},
    icon: const Icon(Icons.menu)
  ),
  title: Text(
    'AppBar Demo',
    style: TextStyle(
      color: Colors.white,
    ),
  ),
  backgroundColor: Colors.green,
  actions: <Widget>[
    IconButton(
      onPressed: (){}, 
      icon: const Icon(Icons.markunread),
      tooltip: 'Mark as Unread',
    ),
    IconButton(
      onPressed: (){}, 
      icon: const Icon(Icons.more_vert),
      tooltip: 'More Setting',
    ),
  ],
),
 
    ผลลัพธ์ที่ได้
 
 

 
 
    ในตัวอย่างส่วนของ AppBar เรียงจากซ้ายไปขวา ประกอบด้วย leading, title และ action อีกสองปุ่ม
    รายละเอียดเกี่ยวกับ App bar น่าจะมีเสริมเรื่อยๆ ดังนั้น จะไม่ด้ลงรายละเอียดทั้งหมดในตอนนี้
 
    ดูคำสั่งการใช้งาน และ property เพิ่มเติมได้ที่ AppBar Widget API    

 
 
 

การใช้งาน Scaffold Widget

    มาถึง widget ตัวสุดท้ายของเนื้อหา widget เบื้องต้นที่ควรรู้  อย่างที่เกริ่นไปแล้ว ถ้าเราต้องการใช้งาน AppBar จำเป็นจะต้องกำหนด
หรือใช้งาน Scaffold widget ซึ่งมี appBar ให้ใช้งาน เข้าใจอย่างง่าย scaffold widget เป็นเครื่องมือสำหรับออกแบบโครงสร้างสำหรับ
Material App ที่ไม่เพียงจะมี AppBar ที่เป็นเมนูด้านบนให้ใช้งานแล้ว ยังมีสามารถกำหนด Drawers หรือเมนูด้านข้างเมื่อถูกเรียกใช้งาน
รวมถึงเมนูด้านล่าง หรือแม้แต่ปุ่ม floatingActionButton ซึ่งเป็นสิ่งที่เราสามารถนำมาประยุกต์ หรือใช้งานร่วมกับ App ของเราได้
    มาดูโค้ดตัวอย่างเต็มของไฟล์ first_screen.dart และการปรับแต่ง scaffold แบบเต็ม จะได้เป็นดังนี้
 
import 'package:flutter/material.dart';
 
// ส่วนของ Stateful widget
class FirstScreen extends StatefulWidget{
    @override
    State<StatefulWidget> createState() {
        return _FirstScreen();
    }
}
class _FirstScreen extends State<FirstScreen>{

    @override
    Widget build(BuildContext context) {
        return Scaffold(
            appBar: AppBar(
              iconTheme: IconThemeData(
                color: Colors.white,
              ),
              // leading: IconButton(
              //   onPressed: (){},
              //   icon: const Icon(Icons.menu)
              // ),
              title: Text(
                'AppBar Demo',
                style: TextStyle(
                  color: Colors.white,
                ),
              ),
              backgroundColor: Colors.green,
              actions: <Widget>[
                IconButton(
                  onPressed: (){}, 
                  icon: const Icon(Icons.markunread),
                  tooltip: 'Mark as Unread',
                ),
                IconButton(
                  onPressed: (){}, 
                  icon: const Icon(Icons.more_vert),
                  tooltip: 'More Setting',
                ),
              ],
            ),
             body: Material(
                color: Colors.lightGreen,
                child: Center(
                    child: Text(
                        'Hello World',
                        style: TextStyle(
                            color: Colors.white,
                            fontSize: 20.0
                        )
                    )
                )
            ),
            drawer: Drawer(
                  child: ListView(
                      padding: EdgeInsets.zero,
                      children: <Widget>[
                          DrawerHeader(
                              child: Text('Drawer Header'),
                              decoration: BoxDecoration(
                                  color: Colors.green,
                              ),
                          ),
                          ListTile(
                              title: Text('Item 1'),
                              onTap: () {}
                              ),
                          ListTile(
                              title: Text('Item 2'),
                              onTap: () {},
                          ),
                      ],
                  ),
            ),
          extendBody: true,
          bottomNavigationBar: BottomAppBar(
            color: Colors.green,
            shape: const CircularNotchedRectangle(),
            child: Container(height: 50.0),
          ),
          floatingActionButton: FloatingActionButton(
              backgroundColor: Colors.black,
              onPressed: () {},
              child: Icon(Icons.add,color: Colors.white,),
          ),
          floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,          
        );
    }
}
    ผลลัพธ์ที่ได้ และเมื่อปัดเลื่อนไปด้านขวา เพื่อแสดงส่วนของ Drawer
 
 
    
 
 
    ดูคำสั่งการใช้งาน และ property เพิ่มเติมได้ที่ Scaffold Widget API
    
 
 
    Widget ที่ควรรู้เบื้องต้นเหล่านี้ ทำให้เรามองภาพการออกแบบหน้าตาของ App เบื้องต้นได้มากขึ้น และเข้าใจการใช้งาน ขอบเขต
และการประยุกต์ ซึ่งเป็นเพียงบางส่วนเท่านั้น ยังมีเครื่องมืออีกมาก รวมถึง widget ที่กล่าวถึงไปแล้วข้างต้น ก็ยังมีรายละเอียด
การนำไปปรับใช้งานเพิ่มเติม ซึ่งอาจจะได้นำมาเสริมในลำดับต่อๆ ไป


กด Like หรือ Share เป็นกำลังใจ ให้มีบทความใหม่ๆ เรื่อยๆ น่ะครับ



อ่านต่อที่บทความ



ทบทวนบทความที่แล้ว









เนื้อหาที่เกี่ยวข้อง









URL สำหรับอ้างอิง





คำแนะนำ และการใช้งาน

สมาชิก กรุณา ล็อกอินเข้าระบบ เพื่อตั้งคำถามใหม่ หรือ ตอบคำถาม สมาชิกใหม่ สมัครสมาชิกได้ที่ สมัครสมาชิก


  • ถาม-ตอบ กรุณา ล็อกอินเข้าระบบ
  • เปลี่ยน


    ( หรือ เข้าใช้งานผ่าน Social Login )







เว็บไซต์ของเราให้บริการเนื้อหาบทความสำหรับนักพัฒนา โดยพึ่งพารายได้เล็กน้อยจากการแสดงโฆษณา โปรดสนับสนุนเว็บไซต์ของเราด้วยการปิดการใช้งานตัวปิดกั้นโฆษณา (Disable Ads Blocker) ขอบคุณครับ