本文主要介紹Flutter項目的簡單界面構(gòu)建,以及布局
一.創(chuàng)建新的Flutter工程
- 使用終端進行創(chuàng)建
不支持大寫字母,可以加下劃線flutter create 項目名
創(chuàng)建成功后,可以使用VSCode或者Android studio打開 - 工程內(nèi)容
lib文件夾:存放編寫的代碼,main.dart即為啟動入口 - 項目啟動
打開iOS或者安卓模擬器, 在工具欄找到啟動調(diào)試,點擊進行啟動
二、flutter項目編寫
- flutter項目的幾個特性
熱重載 hot reload 、 熱重啟 hot restart
運行一個flutter項目有三種方式: 冷啟動:(從0啟動)、 熱重載 (最主要是執(zhí)行build方法,其他方法不受影響)、 熱重啟(重新運行整個項目)
使用熱重載可以快速預(yù)覽布局變化,但是只有build方法會重置 - 簡單編寫啟動內(nèi)容
導入頭文件(package:flutter/material.dart), 然后調(diào)用runApp函數(shù)import 'package:flutter/material.dart'; main(List<String> args) { runApp(Text("Hello world", textDirection: TextDirection.ltr)); } - 具體內(nèi)容設(shè)置
textDirection 傳入文字方向
style 設(shè)置樣式,字體顏色等
Center 也是一個Widget,實現(xiàn)居中操作runApp(Center( child: Text("Hello world", textDirection: TextDirection.ltr, style: TextStyle(fontSize: 30, color: Colors.red))));
三、Material設(shè)計風格
- Widget 即組件
萬物皆是Widget, 通過嵌套Widget來實現(xiàn)布局功能- 有狀態(tài)的Widget:
StatefulWedget 在運行過程中有一些狀態(tài)(data數(shù)據(jù))需要改變 - 無狀態(tài)的Widget:
StatelessWidget 內(nèi)容是確定的,沒有狀態(tài)(data數(shù)據(jù))的改變
- 有狀態(tài)的Widget:
- 幾種Widget
- MaterialApp 會自動添加某些默認配置,不需要手動進行設(shè)置,比如文字方向等
runApp(MaterialApp( home: Center( child: Text("Hello World", style: TextStyle(fontSize: 30, color: Colors.orange))))); - Scaffold 腳手架 用于快速搭建頁面 創(chuàng)建導航欄、Tabbar等
主要參數(shù)有 appBar(導航欄或者Tabbar),body(界面內(nèi)容)
debugShowCheckedModeBanner 控制右上角debug標簽的顯示runApp(MaterialApp( debugShowCheckedModeBanner: false, home: Scaffold( appBar: AppBar( title: Text( "第一個項目", style: TextStyle(fontSize: 20, color: Colors.white), )), body: Center( child: Text("Hello world", textDirection: TextDirection.ltr, style: TextStyle(fontSize: 30, color: Colors.red))))));
- 自定義Widget子類
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { // TODO: implement build return Text("hello World"); } }
build方法: 在創(chuàng)建自定義Widget子類時,會執(zhí)行它的build方法,返回一個希望渲染的Widget元素,例如上例所示的Text Widget
StatelessWidget沒辦法去主動執(zhí)行build方法,當我們的數(shù)據(jù)發(fā)生改變的時候,build方法會被重新執(zhí)行
- build方法在什么情況下會執(zhí)行?
1)當對應(yīng)的StatelessWidget第一次被插入到Widget樹中時,即第一次創(chuàng)建時
2) 當對應(yīng)的父Widget發(fā)生改變時,子Widget會被重新構(gòu)建
3) 如果對應(yīng)的Widget依賴inheritedWidget的一些數(shù)據(jù),inheritedWidget數(shù)據(jù)發(fā)生改變時
將需要構(gòu)造的Widget放到build方法中返回,然后直接調(diào)用編寫的Widget子類,即可得到想要的界面```
main(List<String> args) {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(
title: Text(
"第一個項目",
style: TextStyle(fontSize: 20, color: Colors.white),
)),
body: Center(
child: Text("Hello world",
textDirection: TextDirection.ltr,
style: TextStyle(fontSize: 30, color: Colors.red)))));
}
}
- 代碼拆分抽取
將各個Widget包裝成一個個自定義Widget子類,再進行組合,完成代碼的拆分重組
main(List<String> args) {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(debugShowCheckedModeBanner: false, home: HomePageView());
}
}
class HomePageView extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
"第一個項目",
style: TextStyle(fontSize: 20, color: Colors.white),
)),
body: ContentBody());
}
}
class ContentBody extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: Text("Hello world",
textDirection: TextDirection.ltr,
style: TextStyle(fontSize: 30, color: Colors.orange)));
}
}
- 一行寫入多個控件
橫向?qū)懭攵鄠€控件 Row
豎向?qū)懭攵鄠€控件 Column
class ContentBody extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: Row(mainAxisAlignment: MainAxisAlignment.center, children: [
Text("111"),
Text("Hello world",
textDirection: TextDirection.ltr,
style: TextStyle(fontSize: 30, color: Colors.orange))
]));
}
}
默認從每行的最左端開始布局,使用mainAxisAlignment參數(shù)可以改變行內(nèi)的布局位置
- @immutable
- 使用@immutable 注解標明的類及其子類均為不可變類,其中的屬性均不可變,使用final修飾,不可定義狀態(tài)
Widget類使用@immutable標記,所有的Widget都不可以直接定義狀態(tài) - StatelessWidget即是不可更改的類,不可定義狀態(tài)
- StatefulWidget內(nèi)部有一個抽象方法createState,此方法返回一個State類
- 在自定義的State子類中通過重寫build方法實現(xiàn)控件
- StatefulWidget內(nèi)部不可直接定義狀態(tài),但是可以在自定義的State子類中可以定義狀態(tài)
class ContentBody extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return ContentBodyState();
}
}
class _ContentBodyState extends State<ContentBody> {
var flag = true;
@override
Widget build(BuildContext context) {
// TODO: implement build
return Center(
child: Row(mainAxisAlignment: MainAxisAlignment.center, children: [
Checkbox(
value: flag,
onChanged: (value) {
setState(() {
flag = value ?? false;
});
}),
Text("Hello world",
textDirection: TextDirection.ltr,
style: TextStyle(fontSize: 30, color: Colors.orange))
]));
}
}
總結(jié):
繼承自StatefulWidget的類負責實現(xiàn)createState方法,返回一個State類
State類負責實現(xiàn)Build方法,以及狀態(tài)的創(chuàng)建,來實現(xiàn)功能
另外需要注意的幾點:
- 狀態(tài)的改變需要在setState回調(diào)中進行,否則不生效
- State類一般使用下劃線_開頭,如_ContentBodyState,下劃線開頭的類在別的文件無法訪問,保證安全,而繼承自StatefulWidget的類不加下劃線
問題1:上述示例中,ContentBody返回的State類一定要定義為ContentBody泛型嗎?可以改成別的StatefulWidget類嗎?
可以,但沒必要。
語法上無問題,但是,定義成此泛型,才可以使用系統(tǒng)提供的一個widget屬性來構(gòu)建出橋梁,連通對應(yīng)的StatefulWidget子類,所以一般會這么寫
問題2:繼承自StatefulWidget的類,具體的作用?
1). 生成返回State類
2). 可以接收父Widget傳過來的數(shù)據(jù)