Flutter - ข้อมูลเบื้องต้นเกี่ยวกับเลย์เอาต์

ตั้งแต่แนวคิดหลักของการกระพือเป็นทุกสิ่งที่เป็นเครื่องมือ , Flutterรวมฟังก์ชันการทำงานรูปแบบส่วนติดต่อผู้ใช้เข้าไปในเครื่องมือของตัวเอง Flutterมีวิดเจ็ตที่ออกแบบมาเป็นพิเศษมากมายเช่นContainer, Center, Alignและอื่น ๆ เพื่อจุดประสงค์ในการจัดวางส่วนติดต่อผู้ใช้เท่านั้น วิดเจ็ตสร้างโดยการเขียนวิดเจ็ตอื่น ๆ โดยปกติจะใช้วิดเจ็ตเค้าโครง ให้ใช้เรียนรู้แนวคิดเค้าโครงFlutterในบทนี้

ประเภทของวิดเจ็ตเค้าโครง

วิดเจ็ตเลย์เอาต์สามารถแบ่งออกเป็นสองหมวดหมู่ที่แตกต่างกันโดยขึ้นอยู่กับลูก -

  • วิดเจ็ตรองรับลูกคนเดียว
  • วิดเจ็ตรองรับเด็กหลายคน

ให้เราเรียนรู้ทั้งประเภทของวิดเจ็ตและการทำงานของวิดเจ็ตในส่วนต่อไป

วิดเจ็ตลูกเดียว

ในหมวดหมู่นี้วิดเจ็ตจะมีเพียงวิดเจ็ตลูกเดียวและทุกวิดเจ็ตจะมีฟังก์ชันการจัดวางแบบพิเศษ

ตัวอย่างเช่นวิดเจ็ตCenterจะจัดให้วิดเจ็ตลูกเป็นศูนย์กลางในส่วนที่เกี่ยวกับวิดเจ็ตหลักและวิดเจ็ตคอนเทนเนอร์ให้ความยืดหยุ่นอย่างสมบูรณ์ในการวางลูกไว้ที่ใดก็ได้ภายในโดยใช้ตัวเลือกที่แตกต่างกันเช่นการขยายการตกแต่ง

วิดเจ็ตลูกเดียวเป็นตัวเลือกที่ยอดเยี่ยมในการสร้างวิดเจ็ตคุณภาพสูงที่มีฟังก์ชันเดียวเช่นปุ่มป้ายกำกับ ฯลฯ

รหัสสำหรับสร้างปุ่มง่ายๆโดยใช้วิดเจ็ตคอนเทนเนอร์มีดังนี้ -

class MyButton extends StatelessWidget {
   MyButton({Key key}) : super(key: key); 

   @override 
   Widget build(BuildContext context) {
      return Container(
         decoration: const BoxDecoration(
            border: Border(
               top: BorderSide(width: 1.0, color: Color(0xFFFFFFFFFF)),
               left: BorderSide(width: 1.0, color: Color(0xFFFFFFFFFF)),
               right: BorderSide(width: 1.0, color: Color(0xFFFF000000)),
               bottom: BorderSide(width: 1.0, color: Color(0xFFFF000000)),
            ),
         ),
         child: Container(
            padding: const
            EdgeInsets.symmetric(horizontal: 20.0, vertical: 2.0),
            decoration: const BoxDecoration(
               border: Border(
                  top: BorderSide(width: 1.0, color: Color(0xFFFFDFDFDF)),
                  left: BorderSide(width: 1.0, color: Color(0xFFFFDFDFDF)),
                  right: BorderSide(width: 1.0, color: Color(0xFFFF7F7F7F)),
                  bottom: BorderSide(width: 1.0, color: Color(0xFFFF7F7F7F)),
               ),
               color: Colors.grey,
            ),
            child: const Text(
               'OK',textAlign: TextAlign.center, style: TextStyle(color: Colors.black)
            ), 
         ), 
      ); 
   }
}

ที่นี่เราได้ใช้สองวิดเจ็ต - วิดเจ็ตคอนเทนเนอร์และวิดเจ็ตข้อความ ผลลัพธ์ของวิดเจ็ตเป็นปุ่มแบบกำหนดเองดังที่แสดงด้านล่าง -

ให้เราตรวจสอบวิดเจ็ตเลย์เอาต์ลูกคนเดียวที่สำคัญที่สุดที่จัดทำโดยFlutter -

  • Padding- ใช้เพื่อจัดเรียงวิดเจ็ตลูกตามช่องว่างที่กำหนด ที่นี่สามารถจัดหาช่องว่างภายในได้โดยคลาสEdgeInsets

  • Align- จัดตำแหน่งวิดเจ็ตลูกภายในตัวเองโดยใช้ค่าของคุณสมบัติการจัดตำแหน่ง ค่าสำหรับคุณสมบัติการจัดตำแหน่งสามารถระบุได้โดยคลาสFractionalOffset FractionalOffsetชั้นระบุชดเชยในแง่ของระยะทางจากซ้ายด้านบน

ค่าออฟเซ็ตที่เป็นไปได้บางค่ามีดังนี้ -

  • FractionalOffset (1.0, 0.0) แสดงด้านขวาบน

  • FractionalOffset (0.0, 1.0) แทนค่าล่างซ้าย

โค้ดตัวอย่างเกี่ยวกับการชดเชยแสดงอยู่ด้านล่าง -

Center(
   child: Container(
      height: 100.0, 
      width: 100.0, 
      color: Colors.yellow, child: Align(
         alignment: FractionalOffset(0.2, 0.6),
         child: Container( height: 40.0, width:
            40.0, color: Colors.red,
         ), 
      ), 
   ), 
)
  • FittedBox - ปรับขนาดวิดเจ็ตลูกแล้ววางตำแหน่งตามความพอดีที่ระบุ

  • AspectRatio - พยายามปรับขนาดวิดเจ็ตลูกตามอัตราส่วนภาพที่ระบุ

  • ConstrainedBox

  • Baseline

  • FractinallySizedBox

  • IntrinsicHeight

  • IntrinsicWidth

  • LiimitedBox

  • OffStage

  • OverflowBox

  • SizedBox

  • SizedOverflowBox

  • Transform

  • CustomSingleChildLayout

แอปพลิเคชัน hello world ของเราใช้วิดเจ็ตเค้าโครงตามวัสดุเพื่อออกแบบโฮมเพจ ให้เราปรับเปลี่ยนแอปพลิเคชัน hello world ของเราเพื่อสร้างโฮมเพจโดยใช้วิดเจ็ตเค้าโครงพื้นฐานตามที่ระบุด้านล่าง -

  • Container - วิดเจ็ตคอนเทนเนอร์แบบลูกเดียวแบบทั่วไปพร้อมการจัดตำแหน่งการขยายขอบและขอบพร้อมกับคุณสมบัติการจัดแต่งทรงผมที่หลากหลาย

  • Center - วิดเจ็ตคอนเทนเนอร์ลูกที่เรียบง่ายซึ่งเป็นศูนย์กลางของวิดเจ็ตลูก

โค้ดที่แก้ไขของวิดเจ็ตMyHomePageและMyAppมีดังต่อไปนี้ -

class MyApp extends StatelessWidget {
   @override
   Widget build(BuildContext context) {
      return MyHomePage(title: "Hello World demo app");
   }
}
class MyHomePage extends StatelessWidget {
   MyHomePage({Key key, this.title}) : super(key: key);
   final String title;
   @override
   Widget build(BuildContext context) {
      return Container(
         decoration: BoxDecoration(color: Colors.white,),
         padding: EdgeInsets.all(25), child: Center(
            child:Text(
               'Hello World', style: TextStyle(
                  color: Colors.black, letterSpacing: 0.5, fontSize: 20,
               ),
               textDirection: TextDirection.ltr,
            ),
         )
      );
   }
}

ที่นี่

  • วิดเจ็ตคอนเทนเนอร์คือวิดเจ็ตระดับบนสุดหรือรูท คอนเทนเนอร์ถูกกำหนดค่าโดยใช้คุณสมบัติการตกแต่งและช่องว่างภายในเพื่อจัดวางเนื้อหา

  • BoxDecorationมีคุณสมบัติมากมายเช่นสีเส้นขอบ ฯลฯ ในการตกแต่งวิดเจ็ตคอนเทนเนอร์และที่นี่สีจะใช้เพื่อกำหนดสีของคอนเทนเนอร์

  • paddingของวิดเจ็ตContainerถูกตั้งค่าโดยใช้คลาสdgeInsetsซึ่งมีอ็อพชันเพื่อระบุค่าการขยาย

  • Centerเป็นวิดเจ็ตลูกของวิดเจ็ตContainer อีกครั้งTextเป็นลูกของวิดเจ็ตCenter ข้อความที่ใช้ในการแสดงข้อความและศูนย์จะใช้ในการศูนย์ข้อความที่เกี่ยวกับแม่เครื่องมือตู้คอนเทนเนอร์

ผลลัพธ์สุดท้ายของโค้ดที่ระบุข้างต้นคือตัวอย่างโครงร่างดังที่แสดงด้านล่าง -

วิดเจ็ตเด็กหลายรายการ

ในหมวดหมู่นี้วิดเจ็ตที่กำหนดจะมีวิดเจ็ตลูกมากกว่าหนึ่งรายการและรูปแบบของแต่ละวิดเจ็ตจะไม่ซ้ำกัน

ตัวอย่างเช่นวิดเจ็ตRowอนุญาตให้จัดวางเด็ก ๆ ในแนวนอนในขณะที่วิดเจ็ตคอลัมน์อนุญาตให้วางลูกในแนวตั้ง ด้วยการเขียนRowและColumnวิดเจ็ตที่มีระดับความซับซ้อนสามารถสร้างขึ้นได้

ให้เราเรียนรู้บางส่วนของวิดเจ็ตที่ใช้บ่อยในส่วนนี้

  • Row - อนุญาตให้จัดเรียงลูกในแนวนอน

  • Column - อนุญาตให้จัดเรียงลูกในแนวตั้ง

  • ListView - อนุญาตให้จัดเรียงลูกตามรายการ

  • GridView - อนุญาตให้จัดเด็กเป็นแกลเลอรี

  • Expanded - ใช้เพื่อทำให้ลูก ๆ ของวิดเจ็ต Row และ Column ครอบครองพื้นที่สูงสุดที่เป็นไปได้

  • Table - วิดเจ็ตตามตาราง

  • Flow - วิดเจ็ตตามกระแส

  • Stack - วิดเจ็ตตามกอง

แอปพลิเคชั่นเค้าโครงขั้นสูง

ในส่วนนี้ให้เราเรียนรู้วิธีสร้างอินเทอร์เฟซผู้ใช้ที่ซับซ้อนของรายการผลิตภัณฑ์ด้วยการออกแบบที่กำหนดเองโดยใช้วิดเจ็ตเค้าโครงลูกเดียวและหลายรายการ

เพื่อจุดประสงค์นี้ให้ทำตามลำดับด้านล่าง -

  • สร้างใหม่Flutterการประยุกต์ใช้ในสตูดิโอของ Android, product_layout_app

  • แทนที่รหัสmain.dartด้วยรหัสต่อไปนี้ -

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: 'Flutter Demo', theme: ThemeData( 
         primarySwatch: Colors.blue,), 
         home: MyHomePage(title: 'Product layout demo home page'),
      ); 
   } 
} 
class MyHomePage extends StatelessWidget {
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 
      
   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(title: Text(this.title),), 
         body: Center(child: Text( 'Hello World', )), 
      ); 
   }
}
  • Here,

  • เราได้สร้างวิดเจ็ตMyHomePageโดยการขยายStatelessWidgetแทนค่าเริ่มต้นStatefulWidgetจากนั้นจึงลบโค้ดที่เกี่ยวข้องออก

  • ตอนนี้สร้างวิดเจ็ตใหม่ProductBoxตามการออกแบบที่ระบุดังที่แสดงด้านล่าง -

  • รหัสสำหรับProductBoxมีดังนี้

class ProductBox extends StatelessWidget {
   ProductBox({Key key, this.name, this.description, this.price, this.image}) 
      : super(key: key); 
   final String name; 
   final String description; 
   final int price; 
   final String image; 

   Widget build(BuildContext context) {
      return Container(
         padding: EdgeInsets.all(2), height: 120,  child: Card( 
            child: Row(
               mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: <Widget>[
                  Image.asset("assets/appimages/" +image), Expanded(
                     child: Container(
                        padding: EdgeInsets.all(5), child: Column(
                           mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
                              children: <Widget>[ 
                              
                              Text(this.name, style: TextStyle(fontWeight: 
                                 FontWeight.bold)), Text(this.description), 
                              Text("Price: " + this.price.toString()), 
                           ], 
                        )
                     )
                  )
               ]
            )
         )
      );
   }
}
  • โปรดสังเกตสิ่งต่อไปนี้ในรหัส -

  • ProductBoxใช้สี่อาร์กิวเมนต์ตามที่ระบุด้านล่าง -

    • ชื่อ - ชื่อผลิตภัณฑ์

    • description - รายละเอียดสินค้า

    • price - ราคาของผลิตภัณฑ์

    • รูปภาพ - รูปภาพของผลิตภัณฑ์

  • ProductBoxใช้เจ็ดวิดเจ็ตในตัวตามที่ระบุด้านล่าง -

    • Container
    • Expanded
    • Row
    • Column
    • Card
    • Text
    • Image
  • ProductBoxได้รับการออกแบบโดยใช้วิดเจ็ตที่กล่าวถึงข้างต้น การจัดเรียงหรือลำดับชั้นของวิดเจ็ตระบุไว้ในแผนภาพที่แสดงด้านล่าง -

  • ตอนนี้วางภาพจำลอง (ดูด้านล่าง) สำหรับข้อมูลผลิตภัณฑ์ในโฟลเดอร์ assets ของแอปพลิเคชันและกำหนดค่าโฟลเดอร์ assets ในไฟล์ pubspec.yaml ดังที่แสดงด้านล่าง -

assets: 
   - assets/appimages/floppy.png 
   - assets/appimages/iphone.png 
   - assets/appimages/laptop.png 
   - assets/appimages/pendrive.png 
   - assets/appimages/pixel.png 
   - assets/appimages/tablet.png

iPhone.png

Pixel.png

Laptop.png

Tablet.png

Pendrive.png

Floppy.png

สุดท้ายใช้วิดเจ็ตProductBoxในวิดเจ็ตMyHomePageตามที่ระบุด้านล่าง -

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

   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(title:Text("Product Listing")), 
         body: ListView(
            shrinkWrap: true, padding: const EdgeInsets.fromLTRB(2.0, 10.0, 2.0, 10.0), 
            children: <Widget> [
               ProductBox(
                  name: "iPhone", 
                  description: "iPhone is the stylist phone ever", 
                  price: 1000, 
                  image: "iphone.png"
               ), 
               ProductBox(
                  name: "Pixel", 
                  description: "Pixel is the most featureful phone ever", 
                  price: 800, 
                  image: "pixel.png"
               ), 
               ProductBox( 
                  name: "Laptop", 
                  description: "Laptop is most productive development tool", 
                  price: 2000, 
                  image: "laptop.png"
               ), 
               ProductBox( 
                  name: "Tablet", 
                  description: "Tablet is the most useful device ever for meeting", 
                  price: 1500, 
                  image: "tablet.png"
               ), 
               ProductBox(
                  name: "Pendrive", 
                  description: "Pendrive is useful storage medium", 
                  price: 100, 
                  image: "pendrive.png"
               ), 
               ProductBox(
                  name: "Floppy Drive", 
                  description: "Floppy drive is useful rescue storage medium", 
                  price: 20, 
                  image: "floppy.png"
               ), 
            ],
         )
      );
   }
}
  • ที่นี่เราใช้ProductBoxเป็นลูกของวิดเจ็ตListView

  • รหัสที่สมบูรณ์(main.dart)ของแอปพลิเคชันเค้าโครงผลิตภัณฑ์(product_layout_app)มีดังนี้ -

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: 'Flutter Demo', theme: ThemeData(
            primarySwatch: Colors.blue,
         ), 
         home: MyHomePage(title: 'Product layout demo home page'), 
      );
   }
}
class MyHomePage extends StatelessWidget { 
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 
   
   @override 
   Widget build(BuildContext context) { 
      return Scaffold( 
         appBar: AppBar(title: Text("Product Listing")), 
         body: ListView(
            shrinkWrap: true, 
            padding: const EdgeInsets.fromLTRB(2.0, 10.0, 2.0, 10.0), 
            children: <Widget>[ 
               ProductBox(
                  name: "iPhone", 
                  description: "iPhone is the stylist phone ever", 
                  price: 1000, 
                  image: "iphone.png"
               ), 
               ProductBox( 
                  name: "Pixel",    
                  description: "Pixel is the most featureful phone ever", 
                  price: 800, 
                  image: "pixel.png"
               ), 
               ProductBox( 
                  name: "Laptop", 
                  description: "Laptop is most productive development tool", 
                  price: 2000, 
                  image: "laptop.png"
               ), 
               ProductBox( 
                  name: "Tablet", 
                  description: "Tablet is the most useful device ever for meeting", 
                  price: 1500, 
                  image: "tablet.png"
               ), 
               ProductBox( 
                  name: "Pendrive", 
                  description: "Pendrive is useful storage medium", 
                  price: 100, 
                  image: "pendrive.png"
               ), 
               ProductBox(
                  name: "Floppy Drive", 
                  description: "Floppy drive is useful rescue storage medium", 
                  price: 20, 
                  image: "floppy.png"
               ), 
            ],
         )
      );
   }
}
class ProductBox extends StatelessWidget {
   ProductBox({Key key, this.name, this.description, this.price, this.image}) :
      super(key: key); 
   final String name; 
   final String description; 
   final int price; 
   final String image; 
   
   Widget build(BuildContext context) {
      return Container(
         padding: EdgeInsets.all(2), 
         height: 120, 
         child: Card(
            child: Row(
               mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
               children: <Widget>[ 
                  Image.asset("assets/appimages/" + image), 
                  Expanded( 
                     child: Container( 
                        padding: EdgeInsets.all(5), 
                        child: Column(    
                           mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
                           children: <Widget>[ 
                              Text(
                                 this.name, style: TextStyle(
                                    fontWeight: FontWeight.bold
                                 )
                              ),
                              Text(this.description), Text(
                                 "Price: " + this.price.toString()
                              ), 
                           ], 
                        )
                     )
                  )
               ]
            )
         )
      );
   }
}

ผลลัพธ์สุดท้ายของแอปพลิเคชันมีดังนี้ -