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()
),
],
)
)
)
]
)
)
);
}
}
ผลลัพธ์สุดท้ายของแอปพลิเคชันมีดังนี้ -