Drat語(yǔ)法
1、基本語(yǔ)法
返回修飾詞 main (){}
void main(){
//程序的主入口
}
2舍悯、基本數(shù)據(jù)類型
Drat是強(qiáng)類型語(yǔ)言
var
代表不確定類型 當(dāng)變量第一次被賦值時(shí)航棱,那么該變量就是當(dāng)前類型,重新賦值不能改變類型
int
整數(shù)型
double
浮點(diǎn)型
bool
布爾型
String
字符串類型
num
數(shù)字類型不區(qū)分浮點(diǎn)與整數(shù)型
void main(){
int a = 10;
a = 10.1;//會(huì)報(bào)錯(cuò)
String b = "this is Drat";
bool flag = true;
double c = 10.2;
var d = 123;
d = "123";//報(bào)錯(cuò)
}
3萌衬、final 與const
final
要求變量只能初始化一次饮醇,并不要求賦的值一定是編譯時(shí)常量,可以是常量也可以不是秕豫。而const
要求在聲明時(shí)初始化朴艰,并且賦值必需為編譯時(shí)常量。
void main(){
}
List集合
List類似前端的數(shù)組,注意的是
add()
增加元素
List a = new List();
a.add(456)
類
class Person{
String name;
int age;
Person(String name,int age){
this.name = name;
this.age = age;
}//構(gòu)造函數(shù)一種寫法
Person(this.name,this.age){}//構(gòu)造函數(shù)一種寫法
void printInfo(){
print("${this.name} --- ${this.age}");
}
}
Flutter
1、區(qū)分StatefullWidget
和StatelessWidget
的區(qū)別
StatefullWidget
:為動(dòng)態(tài)組件,狀態(tài)會(huì)發(fā)生改變的,例如進(jìn)度條等赞咙。
StatelessWidget
:靜態(tài)組件俱饿,例如文本框。
2沮脖、Hello Word
import 'package:flutter/material.dart';
void main()=>runApp(MyApp());
class MyApp extends StatelessWidget{
@override
Widget build(BuildContext context){
return MaterialApp(
title : "歡迎學(xué)習(xí),Flutter",
home : Scaffold(
appBar : AppBar(title:Text("Hello Wrod")),
body : Center(child:Text("Hello Wrod",style:TextStyle(color:Colors.blue,fontSize:50)))
)
);
}
}
3金矛、MaterialApp組件
MaterialApp
組件一般是我們的根組件他可以定義我們的APP的主題顏色,已經(jīng)背景等
查看MaterialApp源文件
MaterialApp({
Key key,
this.title = '', // 設(shè)備用于為用戶識(shí)別應(yīng)用程序的單行描述
this.home, // 應(yīng)用程序默認(rèn)路由的小部件,用來(lái)定義當(dāng)前應(yīng)用打開(kāi)的時(shí)候勺届,所顯示的界面
this.color, // 在操作系統(tǒng)界面中應(yīng)用程序使用的主色驶俊。
this.theme, // 應(yīng)用程序小部件使用的顏色。
this.routes = const <String, WidgetBuilder>{}, // 應(yīng)用程序的頂級(jí)路由表
this.navigatorKey, // 在構(gòu)建導(dǎo)航器時(shí)使用的鍵免姿。
this.initialRoute, // 如果構(gòu)建了導(dǎo)航器饼酿,則顯示的第一個(gè)路由的名稱
this.onGenerateRoute, // 應(yīng)用程序?qū)Ш降街付酚蓵r(shí)使用的路由生成器回調(diào)
this.onUnknownRoute, // 當(dāng) onGenerateRoute 無(wú)法生成路由(initialRoute除外)時(shí)調(diào)用
this.navigatorObservers = const <NavigatorObserver>[], // 為該應(yīng)用程序創(chuàng)建的導(dǎo)航器的觀察者列表
this.builder, // 用于在導(dǎo)航器上面插入小部件,但在由WidgetsApp小部件創(chuàng)建的其他小部件下面插入小部件胚膊,或用于完全替換導(dǎo)航器
this.onGenerateTitle, // 如果非空故俐,則調(diào)用此回調(diào)函數(shù)來(lái)生成應(yīng)用程序的標(biāo)題字符串,否則使用標(biāo)題紊婉。
this.locale, // 此應(yīng)用程序本地化小部件的初始區(qū)域設(shè)置基于此值药版。
this.localizationsDelegates, // 這個(gè)應(yīng)用程序本地化小部件的委托。
this.localeListResolutionCallback, // 這個(gè)回調(diào)負(fù)責(zé)在應(yīng)用程序啟動(dòng)時(shí)以及用戶更改設(shè)備的區(qū)域設(shè)置時(shí)選擇應(yīng)用程序的區(qū)域設(shè)置喻犁。
this.localeResolutionCallback, //
this.supportedLocales = const <Locale>[Locale('en', 'US')], // 此應(yīng)用程序已本地化的地區(qū)列表
this.debugShowMaterialGrid = false, // 打開(kāi)繪制基線網(wǎng)格材質(zhì)應(yīng)用程序的網(wǎng)格紙覆蓋
this.showPerformanceOverlay = false, // 打開(kāi)性能疊加
this.checkerboardRasterCacheImages = false, // 打開(kāi)柵格緩存圖像的棋盤格
this.checkerboardOffscreenLayers = false, // 打開(kāi)渲染到屏幕外位圖的圖層的棋盤格
this.showSemanticsDebugger = false, // 打開(kāi)顯示框架報(bào)告的可訪問(wèn)性信息的覆蓋
this.debugShowCheckedModeBanner = true, // 在選中模式下打開(kāi)一個(gè)小的“DEBUG”橫幅槽片,表示應(yīng)用程序處于選中模式
})
利用MaterialApp修改我們App的主題
return MaterialApp(title: "MaterialApp",
home:Scaffold(
appBar : AppBar(title:Text("Flutter MaterialApp"))
),
theme:ThemeData(
primaryColor: Colors.yellow,//appbar為黃色
scaffoldBackgroundColor:Colors.pink//設(shè)置底層背景為粉紅色
)
);
4、Container組件的屬性
Container
類似前端的div元素
屬性 | 描述 | 用法 |
---|---|---|
child |
Container容器中包含的子組件 | child: Text("這是Container的子組件") |
alignment |
將子組件對(duì)齊方式 | alignment:Alignment.bottomRight |
width |
Container容器的寬度 | width:300.0 |
height |
Container容器的高度 | height:300.0 |
padding |
Container容器的內(nèi)邊距 |
padding: EdgeInsets.all(20.0) 或者 padding: EddgeInsets.fromLTRB(double left, double top, double right, double bottom)
|
margin |
Container容器的外邊距 |
margin: EdgeInsets.all(20.0) 或者 margin: EddgeInsets.fromLTRB(double left, double top, double right, double bottom)
|
color |
Container容器的背景色 |
Colors.yellow 或者 color:Color.fromRGBO(r, g, b, opacity)
|
decoration |
裝飾器肢础,可以設(shè)置邊框还栓、圓角、背景圖片传轰,背景色:注意此屬性不能與color屬性同時(shí)使用
|
具體可看代碼 |
transform |
變換旋轉(zhuǎn) | transform: Matrix4.rotationZ(0.3) |
@override
Widget build(BuildContext context) {
return Container(
child:Text("這是包裹在Container組件內(nèi)的Text組件蝙云。"),
alignment : Alignment.bottomRight,
width: 300.0,
height: 300.0,
padding: EdgeInsets.fromLTRB(20.0, 40.0, 60.0, 40.0),
margin: EdgeInsets.all(40.0),
//color: Colors.yellow,//背景色不能與decoration同時(shí)使用,
decoration:BoxDecoration(
color: Colors.yellow,//背景色
border: Border.all(//線條樣式
color: Colors.black,//邊框顏色
width: 3.0,//線框
style: BorderStyle.solid,//實(shí)現(xiàn)
),
image: DecorationImage(//背景圖片 注意使用https地址圖片
image: NetworkImage('https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=2606284972,2670724825&fm=26&gp=0.jpg'),
alignment: Alignment.topCenter,//對(duì)齊方式
),
)
);
}
4-1使用Container制造圓形且?guī)ш幱?/h3>
Container(
width:50.0,
height:50.0,
decoration:BoxDecoration(
color:Colors.yellow,//背景圖片
shape:BoxShape.circle,//圓形
boxShadow:[BoxShadow(color: Colors.black, offset: Offset(0, 0),blurRadius: 2.0, spreadRadius: 0.0)]//陰影
)
)
5、TextWidget常用屬性
Container(
width:50.0,
height:50.0,
decoration:BoxDecoration(
color:Colors.yellow,//背景圖片
shape:BoxShape.circle,//圓形
boxShadow:[BoxShadow(color: Colors.black, offset: Offset(0, 0),blurRadius: 2.0, spreadRadius: 0.0)]//陰影
)
)
屬性 | 描述 | 用法 |
---|---|---|
textAlign |
文本對(duì)齊方式 | textAlign:TextAlign.right |
overflow |
文本超出樣式 | overflow:TextOverflow.ellipsis, |
maxLines |
最大顯示的行數(shù) | maxLines:2 |
style |
設(shè)置文本樣式 | style:TextStyle(color:Color.fromRGBO(25, 201, 124, 1),) |
style_color |
屬于style屬性下路召,設(shè)置文本顏色 | style:TextStyle(color:Color.fromRGBO(25, 201, 124, 1),) |
style_fontSize |
屬于style屬性下勃刨,設(shè)置文本字體大小 | style:TextStyle(fontSize: 20.0,) |
style_fontWeight |
屬于style屬性下,設(shè)置文本字體加粗 | style:TextStyle(fontWeight: FontWeight.w800,) |
style_fontStyle |
屬于style屬性下股淡,設(shè)置文本字體斜體 | style:TextStyle(fontStyle: FontStyle.italic,) |
style_decoration |
屬于style屬性下身隐,設(shè)置文本中間的橫線 | style: TextStyle(decoration: TextDecoration.lineThrough) |
Text("這是包裹在Container組件中的Text子組件",
style:TextStyle(
color:Color.fromRGBO(30, 201, 124, 1),
fontSize: 20.0,
fontWeight: FontWeight.w800,
fontStyle: FontStyle.italic
),
textAlign:TextAlign.right,
overflow:TextOverflow.ellipsis,
maxLines:2
)
6、Image組件
Image
一種是網(wǎng)絡(luò)圖片唯灵、一種是本地圖片
Image.network()
贾铝、Image.asset()
屬性 | 描述 | 用法 |
---|---|---|
默認(rèn)值 | 圖片應(yīng)用的地址 | - |
color |
圖片的顏色,直接使用會(huì)覆蓋掉圖片 | color:Colors.pink |
colorBlendMode |
混合模式,類似在圖片上弄個(gè)遮罩需要與color一起使用 | colorBlendMode: BlendMode.screen |
fit |
圖片裁剪 | fit:BoxFit.cover |
repeat |
平鋪 | repeat: ImageRepeat.repeat, |
BoxFit.cover
:可能拉伸,裁切垢揩,充滿玖绿,但是不會(huì)是圖片變形
BoxFit.fill
:圖片充滿整個(gè)容器,會(huì)被拉伸
BoxFit.contain
:全圖顯示(不是充滿容器)叁巨,保留原寬高比例斑匪,會(huì)有空隙
BoxFit.cover
BoxFit.fill
BoxFit.contain
Container(
width:300.0,
height:300.0,
child: Image.network(//設(shè)置遠(yuǎn)程圖片
"https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=2606284972,2670724825&fm=26&gp=0.jpg",
fit: BoxFit.cover,
repeat: ImageRepeat.repeat,
color:Colors.green,
colorBlendMode: BlendMode.screen,
),
decoration: BoxDecoration(
//color:Colors.lime
border: Border.all(
color:pink,
width: 4,
style: BorderStyle.solid
),
),
)
6-1、 實(shí)現(xiàn)圓角锋勺、以及實(shí)現(xiàn)圓形圖片
第一種:使用container背景圖片實(shí)現(xiàn)圓形圖片
Container(
width: 300.0,
height: 300.0,
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage("https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=2606284972,2670724825&fm=26&gp=0.jpg"),
fit:BoxFit.cover//填充背景圖片
),
border:Border.all(
width:3,
color:Colors.black,
style: BorderStyle.solid
),
borderRadius:BorderRadius.circular(150.0)//圓角
),
)
第二種利用
ClipOval
組件實(shí)現(xiàn)圓形圖片 推薦使用這個(gè)
return Center(
child:Container(
child:ClipOval(
child:Image.network("圖片地址",width:100.0,height:100.0,fit:BoxFit.cover)
)
)
);
第三種利用
CircleAvatar
CircleAvatar(
radius: 25.0,
backgroundImage: NetworkImage("https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=2611652800,2596506430&fm=26&gp=0.jpg")
);
6-3蚀瘸、image組件之引入本地圖片
1、在項(xiàng)目根目錄創(chuàng)建靜態(tài)資源文件夾
創(chuàng)建images文件夾其次在這個(gè)文件夾下創(chuàng)建
2.0x和3.0x文件夾
庶橱,然后把靜態(tài)資源考進(jìn)去,images文件夾下也得拷一份
- images
-- 2.0x
-- 3.0x
2贮勃、在配置文件夾中寫入剛剛的路徑
pubspec.yaml
,注意:格式需要對(duì)齊苏章,不要保留空格
assets:
- images/1.jpg
- images/3.0x/1.jpg
- images/2.0x/1.jpg
3寂嘉、使用圖片
Container(
child: ClipOval(
child: Image.asset("images/1.jpg",width: 200.0,height: 200.0,fit: BoxFit.fill,),
),
)
7、 Icon組件
圖標(biāo)組件
屬性 | 描述 | 用法 |
---|---|---|
size |
圖標(biāo)大小 | size: 30.0, |
color |
圖標(biāo)顏色 | color: Colors.blue, |
基礎(chǔ)值 |
具體的圖標(biāo) | Icons.sentiment_neutral |
Icon(Icons.sentiment_neutral,
size: 30.0,
color: Colors.blue
)
8枫绅、 ListView組件
ListView
:基礎(chǔ)列表組件垫释、水平列表組件、圖標(biāo)組件撑瞧,相當(dāng)于父容器棵譬,里面很多子元素
屬性 | 描述 | 使用 |
---|---|---|
scrollDirection |
定義水平列表還是垂直列表 |
scrollDirection:Axis.horizontal 水平列表scrollDirection:Axis.vertical 垂直列表 |
padding |
外邊距 | padding: EdgeInsets.all(20.0) 或者 padding: EddgeInsets.fromLTRB(double left, double top, double right, double bottom) |
children |
子元素,并且它的子元素不是一個(gè)预伺,數(shù)組類型 | children:[Container(width: 100.0,height: 100.0,color: Colors.red,),Container(width: 100.0,height: 100.0,color: Colors.blue,),Container(width: 100.0,height: 100.0,color: Colors.pink,),Container(width: 100.0,height: 100.0,color: Colors.yellow,)] |
ListView(
scrollDirection:Axis.vertical,
children: <Widget>[
Image.asset("images/1.jpg",width: 200.0,height: 300.0,fit: BoxFit.fill,),
Text("這是列表組件"),
Container(width: 200.0,height: 200.0,color: Colors.red,)
],
),
8-1订咸、我們可以配合ListTitle一起使用
ListTitle
組件,類似于新聞頁(yè)主標(biāo)題酬诀,副標(biāo)題
屬性 | 描述 | 使用 |
---|---|---|
leading |
前面的圖標(biāo) |
leading:ICon(Icons.sentiment_neutral) 也可以圖片 |
trailing |
后面的圖標(biāo) | trailing:ICon(Icons.sentiment_neutral) |
title |
一級(jí)標(biāo)題 | title:Text("阿斯達(dá)四大") |
title |
一級(jí)標(biāo)題 | title:Text("阿斯達(dá)四大") |
subtitle |
二級(jí)標(biāo)題/文本/描述 | subtitle:Text("阿斯達(dá)四大") |
這是listTtile的效果
ListView(
scrollDirection:Axis.vertical,
padding: EdgeInsets.all(10.0),
children: <Widget>[
Container(
margin: EdgeInsets.fromLTRB(0, 0, 0, 10.0),
child: ListTile(
leading:Image.asset("images/1.jpg",width: 100.0,height: 200.0,fit: BoxFit.fill,),
trailing:Icon(Icons.sentiment_neutral,
size: 30.0,
color: Colors.blue
),
title:Container(
child:Text(
"黃山旅游董事長(zhǎng)章德輝:景區(qū)停擺每天損失450萬(wàn) 關(guān)注“兩只票”",
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w900
),
),
),
subtitle: Text("1月13日-23日脏嚷,每日經(jīng)濟(jì)新聞推出《專訪董事長(zhǎng)·第一季》,華誼兄弟董事長(zhǎng)王中軍瞒御、工業(yè)富聯(lián)董事長(zhǎng)李軍旗父叙、通威集團(tuán)董事局主席劉漢元等多位重磅嘉賓接受采訪,暢談行業(yè)現(xiàn)狀肴裙、直陳公司利弊趾唱、展望未來(lái)前景,在業(yè)界引發(fā)強(qiáng)烈反響蜻懦。時(shí)值全國(guó)“兩會(huì)”即將召開(kāi)之際甜癞,又是抗擊新冠肺炎疫情之后,行業(yè)宛乃、企業(yè)復(fù)蘇的關(guān)鍵時(shí)刻悠咱,作為知名上市公司的領(lǐng)頭人蒸辆,他們?cè)鯓涌创咔閷?duì)行業(yè)、企業(yè)的影響析既?又如何帶領(lǐng)企業(yè)走出困境躬贡?")
),
),
Container(
margin: EdgeInsets.fromLTRB(0, 0, 0, 10.0),
child: ListTile(
leading:Image.asset("images/1.jpg",width: 100.0,height: 200.0,fit: BoxFit.fill,),
trailing:Icon(Icons.sentiment_neutral,
size: 30.0,
color: Colors.blue
),
title:Container(
child:Text(
"黃山旅游董事長(zhǎng)章德輝:景區(qū)停擺每天損失450萬(wàn) 關(guān)注“兩只票”",
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w900
),
),
),
subtitle: Text("1月13日-23日,每日經(jīng)濟(jì)新聞推出《專訪董事長(zhǎng)·第一季》眼坏,華誼兄弟董事長(zhǎng)王中軍拂玻、工業(yè)富聯(lián)董事長(zhǎng)李軍旗、通威集團(tuán)董事局主席劉漢元等多位重磅嘉賓接受采訪,暢談行業(yè)現(xiàn)狀逢渔、直陳公司利弊铣鹏、展望未來(lái)前景,在業(yè)界引發(fā)強(qiáng)烈反響哀蘑。時(shí)值全國(guó)“兩會(huì)”即將召開(kāi)之際诚卸,又是抗擊新冠肺炎疫情之后,行業(yè)绘迁、企業(yè)復(fù)蘇的關(guān)鍵時(shí)刻合溺,作為知名上市公司的領(lǐng)頭人,他們?cè)鯓涌创咔閷?duì)行業(yè)缀台、企業(yè)的影響棠赛?又如何帶領(lǐng)企業(yè)走出困境?")
),
)
],
),
9膛腐、動(dòng)態(tài)組件
動(dòng)態(tài)組件:顧名思義會(huì)改變組件狀態(tài)的睛约,例如進(jìn)度條,或者我們拿到數(shù)據(jù)循環(huán)出組件(
類似v-for
);
我們看個(gè)簡(jiǎn)單的例子
我們要知道 任何的組件他都是一個(gè)類哲身,只不過(guò)繼承了
StatelessWidget痰腮、StatefulWidget
這兩個(gè)接口,只要是類律罢,他就有變量成員膀值,方法
class MyBody extends StatelessWidget{
List<Widget> _getData(){ //重點(diǎn)
List<Widget> MyList = new List();
for(int i = 0 ;i<20;i++){
MyList.add(
Container(
padding: EdgeInsets.all(10.0),
child: ListTile(
leading: Icon(Icons.smartphone,size: 38,color: Colors.pink,),
title: Text("美藥企跳過(guò)疫苗研發(fā)關(guān)鍵實(shí)驗(yàn)環(huán)節(jié) 美股還會(huì)暴跌嗎",style: TextStyle(fontSize: 22,fontWeight: FontWeight.w900),),
subtitle: Text("據(jù)報(bào)道棍丐,美藥企跳過(guò)疫苗研發(fā)關(guān)鍵實(shí)驗(yàn)環(huán)節(jié),直接進(jìn)行人體臨床試驗(yàn)沧踏,而該做法備受一些專家質(zhì)疑歌逢。美國(guó)總統(tǒng)特朗普此前稱,爭(zhēng)取2020年年底前實(shí)現(xiàn)疫苗的量產(chǎn)和分發(fā)翘狱。值得一提的是秘案,對(duì)于加速疫苗的研發(fā),一些美國(guó)網(wǎng)友也不認(rèn)同上述做法潦匈。",maxLines:3,overflow:TextOverflow.ellipsis),
),
)
);
}
return MyList;
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return ListView(
children: this._getData()
);
}
}
mock
拿取服務(wù)端數(shù)據(jù)渲染
//服務(wù)端數(shù)據(jù)
var ListData = [
{
"title":"北京一單位33人集中發(fā)熱 初判與使用中央空調(diào)有關(guān)",
"pubtime":2,
"reply":255,
"imageUrl" : "https://cms-bucket.ws.126.net/2020/0518/f55c820fp00qaitd8006qc000s600e3c.png"
},
{
"title":'蓬佩奧"警告"中國(guó)不要干涉美記者在港工作 中方回應(yīng)',
"pubtime":4,
"reply":0,
"imageUrl" : "https://cms-bucket.ws.126.net/2020/0518/b76b3832j00qaiq2u004tc000s600e3c.jpg"
},
{
"title":"失聯(lián)6天的翼裝女飛行員遇難:遺體最先被村民發(fā)現(xiàn)",
"pubtime":5,
"reply":"4.2萬(wàn)",
"imageUrl" : "https://cms-bucket.ws.126.net/2020/0518/4689114ep00qail4e00e9c000s600e3c.png"
}]
List<Widget> _getData(){
var result = ListData.map((item){
return ListTile(
leading: Image.network(item["imageUrl"],width: 90.0,height:60.0,fit: BoxFit.fill,),
title:Text(item["title"],style: TextStyle(fontSize:18,fontWeight: FontWeight.w900),),
subtitle: Row(
children: <Widget>[
Container(child: Text(item['pubtime'].toString() + "小時(shí)前"),margin: EdgeInsets.fromLTRB(0, 10, 10.0, 0),),
Container(child: Text(item['reply'].toString() + "萬(wàn)人查看"),margin: EdgeInsets.fromLTRB(0, 10, 10.0, 0),)
],
)
);
});
return result.toList();
}
9-1阱高、ListView.builder方法
itemCount
必填參數(shù):循環(huán)的次數(shù)
itemBuilder
:循環(huán)主體
@override
Widget build(BuildContext context) {
return ListView.builder(//兩個(gè)必填參數(shù)itemCount循環(huán)次數(shù)
itemCount: ListData.length,
itemBuilder: (ctx,index){//itemBuilder循環(huán)體
return ListTile(
leading: Image.network(ListData[index]["imageUrl"],width: 90.0,height: 70.0,fit: BoxFit.fill,),
title: Text(ListData[index]["title"],style: TextStyle(fontSize: 20,fontWeight: FontWeight.w900),),
);
}
);
10、GridView組件
柵格布局:
常用有兩種方法:
1茬缩、GridView.builder()
2赤惊、GridView.count()
請(qǐng)注意當(dāng)GridView被放在Cloumn或者Row里面使用那么一定要指定GridView的高度,即在GridView外面包裹一層Container并設(shè)置高度
屬性 | 描述 | 用法 |
---|---|---|
scrollDirection |
橫向還是縱向 | scrollDirection:Axis.vertical |
padding |
內(nèi)邊距 | 同上面幾個(gè)例子 |
resolve |
組件反向排序 | resolve:true |
crossAxisSpacing |
一行子元素的間距 | crossAxisSpacing:20.0 |
mainAxisSpacing |
垂直方向的子元素的間距 | mainAxisSpacing:20.0 |
crossAxisCount |
一行子元素的個(gè)數(shù) | crossAxisCount:3 |
childAspectRatio |
子元素的寬高比例 | childAspectRatio:1.0 |
chidren |
子元素集合 | chidren:<Widget>[] |
gridDelegate |
該屬性是GridView.builder中使用 | gridDelegate:SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount:3,mainAxisSpacing : 20.0,crossAxisSpacing :20.0,childAspectRatio:0.6) |
physics |
禁止?jié)L動(dòng) | physics:NeverScrollableScrollPhysics() |
10-1凰锡、簡(jiǎn)單的例子
GridView.count
List<Widget> _getData(){
var list = ListData.map((i){
return Container(
decoration: BoxDecoration(
border: Border.all(width:0.3,style: BorderStyle.solid,color: Colors.pink)
),
child: Column(
children: <Widget>[
Image.network(i["imageUrl"],height: 50.0,fit: BoxFit.cover,),
Container(height: 10.0,),
Text(i["title"],style: TextStyle(fontSize: 13.0),maxLines: 2,overflow: TextOverflow.ellipsis)
],
),
);
});
return list.toList();
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return GridView.count(
crossAxisCount: 3,//一行三個(gè)
crossAxisSpacing:20.0,//一行之間的間距
mainAxisSpacing:20.0,//垂直之間的間距
padding: EdgeInsets.all(10.0),//內(nèi)邊距
children:this._getData(),//子元素
childAspectRatio:0.6,//設(shè)置寬高比例不能直接設(shè)置寬高的
);
}
10-2未舟、GridView.builder
Widget _getData(ctx,i){
return Container(
decoration: BoxDecoration(
border: Border.all(width:0.3,style: BorderStyle.solid,color: Colors.pink)
),
padding: EdgeInsets.fromLTRB(15, 5, 15, 10),
child: Column(
children: <Widget>[
Image.network(ListData[i]["imageUrl"],height: 120.0,fit: BoxFit.fitWidth,),
SizedBox(height: 6.0,),//撐開(kāi)間距
Text(ListData[i]["title"],style: TextStyle(fontSize: 16.0,fontWeight: FontWeight.w900),maxLines: 2,overflow: TextOverflow.ellipsis)
],
),
);
}
@override
Widget build(BuildContext context) {
return GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount:3,
mainAxisSpacing : 20.0,
crossAxisSpacing :20.0,
childAspectRatio:0.6
),
padding: EdgeInsets.all(10.0),
itemCount: ListData.length,
itemBuilder: this._getData//注意這個(gè)地方不是調(diào)用哦
);
}
11、Padding掂为、Row裕膀、Colum、Expanded組件
11-1勇哗、Padding組件
在Flutter中有許多組件是沒(méi)有padding屬性昼扛,我們之前都是包裹在Container中使用
屬性 | 描述 | 使用 |
---|---|---|
padding |
內(nèi)邊距 | padding:EdgeInsets.all(10.0) |
child |
子元素 | child:Text() |
ListView(
children:[
Padding(padding:padding:EdgeInsets.all(10.0),child:Text("121313")),
Padding(padding:padding:EdgeInsets.all(10.0),child:Text("121313")),
]
)
11-2、Row組件
水平列表組件
mainAxisAlignment欲诺、crossAxisAlignment
是相對(duì)于父元素的位置起值的野揪,如果父元素沒(méi)有那么默認(rèn)就是內(nèi)容的高度
屬性 | 描述 | 使用 |
---|---|---|
crossAxisAlignment |
縱軸對(duì)齊方式 | crossAxisAlignment:CrossAxisAlignment.spaceEvenly |
mainAxisAlignment |
橫軸對(duì)齊方式 | mainAxisAlignment:MainAxisAlignment.center |
children |
子元素集合 | children:[] |
測(cè)試下mainAxisAlignment、crossAxisAlignment
return Container(
width: 800.0,
height: 600.0,
color: Colors.lightBlue,
child: Row(
children: <Widget>[
Container(width: 100.0,height: 100.0,color: Colors.red,),
Container(width: 100.0,height: 100.0,color: Colors.orange,),
Container(width: 100.0,height: 100.0,color: Colors.green,)
],
)
);
默認(rèn)情況
MainAxisAlignment.spaceEvenly均勻分配橫軸方向
縱軸相對(duì)于父元素瞧栗,如果父元素沒(méi)有斯稳,那么無(wú)效
CrossAxisAlignment.start
11-2、Colum組件
用法屬性和Row一致
mainAxisAlignment:MainAxisAlignment.spaceEvenly,
crossAxisAlignment:CrossAxisAlignment.start,
11-3迹恐、Expanded組件
Expanded
組件類似于前端的display:flex;
注意一點(diǎn):在Row中使用Expanded的時(shí)候挣惰,無(wú)法指定Expanded中的子組件的寬度width,但可以指定其高度height殴边。同理憎茂,在Column中使用Expanded的時(shí)候,無(wú)法指定Expanded中的子組件的高度height锤岸,可以指定寬度width竖幔。
屬性 | 描述 | 使用 |
---|---|---|
flex |
占用多少格 |
flex:1 整數(shù)型 |
child |
子元素 | child:Text() |
和Row組件一起使用
@override
Widget build(BuildContext context) {
return Row(
children: <Widget>[
Expanded(child: Container(height:200.0,color: Colors.blue,),flex: 1),
Expanded(child: Container(height:200.0,color: Colors.pink),flex: 2),
],
);
}
和Cloumn一起使用
return Column(
children: <Widget>[
Expanded(child: Container(height:200.0,color: Colors.blue,),flex: 1),
Expanded(child: Container(height:200.0,color: Colors.pink),flex: 2),
],
);
12、布局小結(jié)
實(shí)現(xiàn)下面的布局
@override
Widget build(BuildContext context) {
return Padding(padding: EdgeInsets.all(10.0),
child: Column(
children: <Widget>[
Container(height: 180.0,color: Colors.black,),
Padding(
padding: EdgeInsets.fromLTRB(0, 10.0, 0, 0),
child: Row(
children: <Widget>[
Expanded(
child: Padding(padding: EdgeInsets.fromLTRB(0, 0, 10.0, 0),child: Image.network("https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=1809168321,2277139267&fm=26&gp=0.jpg"),),
flex: 2,
),
Expanded(
child:Column(
children: <Widget>[
Image.network("https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=2484090652,3266104108&fm=26&gp=0.jpg",fit: BoxFit.fill,),
SizedBox(height: 10.0,),
Image.network("https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=2382576479,3688530667&fm=26&gp=0.jpg",fit: BoxFit.fill)
],
),
flex: 1,
)
],
),
)
],
),
);
}
13是偷、Stack拳氢、Align募逞、Positioned組件
Stack、Align馋评、Positioned
是用來(lái)定位布局使用的放接。
Stack
只能單一的組件進(jìn)行定位
Stack
與其他兩個(gè)組件同時(shí)使用就可以對(duì)多個(gè)組件進(jìn)行定位
13-1、Stack堆疊組件
屬性 | 描述 | 用法 |
---|---|---|
alignment |
配置所有子元素顯示的位置 | alignment:AlignmentDirectional.topStart |
children |
子元素集合 | children:[] |
Stack(
children: <Widget>[
Container(width: 300.0,height: 400.0,color: Colors.red,),
Container(width: 100.0,height: 100.0,color: Colors.black,),
Text("測(cè)試測(cè)試測(cè)試測(cè)試測(cè)試測(cè)試",style: TextStyle(color: Colors.white),)
],
);
結(jié)果發(fā)現(xiàn)子組件都堆疊在一起了
alignment: Alignment.center
Alignment.center
會(huì)把所有的組件居中堆疊在一起``
Alignment
自帶很多方位留特,當(dāng)自帶的方位不滿足我們的需求纠脾,我們可以自定義方位
Alignment()
他有兩個(gè)參數(shù)X、Y 分別是0蜕青、1苟蹈、-1之間的值
Alignment(-1,-1)
最左上角
Alignment(-1,0)
貼近左側(cè)垂直居中
Alignment(-1,1)
貼近左側(cè)垂直靠底部(左下角)
Alignment(0,-1)
橫軸居中貼近頂部
Alignment(0,0)
居中
Alignment(0,1)
橫軸居中貼近底部
Alignment(1,-1)
右上角
當(dāng)然也可以小數(shù)位
單一使用Stack的缺點(diǎn)我們也知道了,沒(méi)辦法對(duì)子組件一一定位
13-2右核、Stack與Align組件一起使用
這樣就可以實(shí)現(xiàn)我們類似前端的定位了
Center(
child: Container(//給了個(gè)最大的容器
width: 400.0,
height: 400.0,
color: Colors.yellow,
child: Stack(//然后使用Stack
children: <Widget>[
Align(//使用Align對(duì)子組件定位
alignment:Alignment.topRight,
child: Icon(Icons.home,size:40.0,color: Colors.red,)
),
Align(
alignment:Alignment.bottomRight,
child: Icon(Icons.settings,size:40.0,color: Colors.blue,),
),
Align(
alignment:Alignment(0,0),//我們使用實(shí)例化alignment:Alignment類
child: Icon(Icons.slow_motion_video,size:40.0,color: Colors.black,),
),
],
),
),
);
13-3慧脱、Stack與Position一起使用(推薦使用這個(gè))
Position
組件就比Align好用多了,他有left蒙兰、top磷瘤、bottom芒篷、right
四個(gè)值
Center(
child: Container(
width: 400.0,
height: 400.0,
color: Colors.yellow,
child: Stack(
children: <Widget>[
Positioned(
left:50,
child: Icon(Icons.home,size:40.0,color: Colors.red,)
),
Positioned(
left:150,
top: 100,
bottom: 20,
child: Icon(Icons.settings,size:40.0,color: Colors.blue,),
),
Positioned(
left:250,
child: Icon(Icons.slow_motion_video,size:40.0,color: Colors.black,),
),
],
),
),
);
14搜变、AspectRatio組件
AspectRatio
定義子元素相對(duì)于父元素的寬高比例
屬性 | 描述 | 用法 |
---|---|---|
aspectRatio |
定義子元素相對(duì)父元素的寬高比 | aspectRatio:2.0/1.0 |
child |
子元素 | child:Widget |
Container(
width: 300.0,
child: AspectRatio(
aspectRatio: 2.0/1.0,
child: Container(
color:Colors.yellow
),
),
);
黃色區(qū)域的寬高比例是2/1
15、Card
類似于前端中ElementUI中的Card差不多针炉,我們可以給想要加陰影的容器套一層Card就有陰影效果了
屬性 | 描述 | 用法 |
---|---|---|
margin |
外邊距 | margin: EdgeInsets.all(10.0), |
shadowColor |
陰影顏色 | shadowColor:Colors.red, |
elevation |
陰影擴(kuò)散的大小 | elevation : 10.0 |
return Contanier(width:200.0,height:200.0,child:Card());
16挠他、練習(xí)布局
實(shí)現(xiàn)以下布局
class MyBody extends StatelessWidget{
List list = new List();
MyBody(){
this.list = [{
'avtorImg' : "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=1452751795,1897979528&fm=26&gp=0.jpg",
'avtorName' : "十年之后_1",
'avtorDesc' : "1描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述",
'backGround' : "https://dss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=3778173668,1422088699&fm=26&gp=0.jpg"
},{
'avtorImg' : "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=2405043393,1737103092&fm=26&gp=0.jpg",
'avtorName' : "十年之后_2",
'avtorDesc' : "2描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述",
'backGround' : "https://dss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=2335751370,711568964&fm=26&gp=0.jpg"
},{
'avtorImg' : "https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=3940043770,1553058007&fm=26&gp=0.jpg",
'avtorName' : "十年之后_3",
'avtorDesc' : "3描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述",
'backGround' : "https://dss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=1532844926,3671374399&fm=26&gp=0.jpg"
},{
'avtorImg' : "https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=2255910787,3354486640&fm=26&gp=0.jpg",
'avtorName' : "十年之后_4",
'avtorDesc' : "4描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述",
'backGround' : "https://dss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=2155983538,3860699715&fm=26&gp=0.jpg"
},{
'avtorImg' : "https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=2611652800,2596506430&fm=26&gp=0.jpg",
'avtorName' : "十年之后_5",
'avtorDesc' : "5描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述",
'backGround' : "https://dss1.bdstatic.com/6OF1bjeh1BF3odCf/it/u=1242146115,2880436607&fm=74&app=80&f=JPEG&size=f121,90?sec=1880279984&t=0136ee81b657a616fbe11b994842e68e"
}];
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return ListView.builder(
itemCount: this.list.length,
itemBuilder: (ctx,i){
return Padding(
padding: EdgeInsets.fromLTRB(10.0, 10.0, 10.0, 0),
child: Card(
elevation:3.0,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
AspectRatio(aspectRatio: 10.0/5.0,child: Image.network(this.list[i]["backGround"],fit: BoxFit.cover,),),
Padding(
padding: EdgeInsets.fromLTRB(0,10.0,0,10.0),
child: ListTile(
leading: ClipOval(child: Image.network(this.list[i]["avtorImg"],width:50.0,height:50.0,fit: BoxFit.cover,),),
title: Text(this.list[i]["avtorName"],style: TextStyle(fontWeight: FontWeight.w600),),
subtitle: Text(this.list[i]["avtorDesc"],maxLines:1,overflow: TextOverflow.ellipsis,style: TextStyle(color: Color.fromRGBO(102, 102, 102, 1))),
)
)
],
)
)
);
}
);
}
}
17、RaisedButton按鈕組件
如果需要給按鈕寬高篡帕,那么可以通過(guò)給
RaisedButton
包裹一層Container
設(shè)置寬高
屬性 | 描述 | 用法 |
---|---|---|
color |
按鈕的背景顏色 | color:Colors.*** |
textColor |
按鈕里面的文本顏色 | textColor:Colors.pink |
child |
子元素 | child:Text() |
onPressed |
點(diǎn)擊事件 |
onPressed(){} /onPressed:自定義函數(shù)
|
disabledTextColor |
按鈕禁用狀態(tài)時(shí)文本顏色 | disabledTextColor:Colors.pink |
disabledColor |
按鈕禁用狀態(tài)時(shí)背景顏色 | disabledColor:Colors.pink |
elevation |
按鈕的陰影 | elevation:20.0 |
shape |
圓角殖侵、原型圓形按鈕 | 看例子 |
splashColor |
點(diǎn)擊按鈕之后顏色變化過(guò)渡的效果 | splashColor: Colors.red |
focusColor、hoverColor
圓角:shape:RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(25.0)) )
RaisedButton(
padding: EdgeInsets.all(10.0),
child: Text("按鈕"),
onPressed: (){},
shape:RoundedRectangleBorder(//圓角按鈕
borderRadius: BorderRadius.all(Radius.circular(25.0))
),
);
17-1圓形按鈕
使用
shape
屬性,如果文本溢出镰烧,我們可以在包裹一層Container
容器
RaisedButton(onPressed: (){
print("圓形按鈕");
},child: Text("圓形按鈕"),elevation: 20,splashColor: Colors.red,shape:CircleBorder(
side:BorderSide(color:Colors.white)
),)
17-2圖標(biāo)按鈕
RaisedButton.icon()
RaisedButton.icon(onPressed: (){
print("圖標(biāo)按鈕");
}, icon: Icon(Icons.search), label: Text("圖標(biāo)按鈕")),
18拢军、Wrap流式布局
它類似與
GridView.count
,但是GridView.count
需要定義一行顯示幾個(gè),而且子元素寬度自動(dòng)填滿
屬性 | 描述 | 用法 |
---|---|---|
spacing |
子元素之間的間距 | spacing:20.0 |
runSpacing |
垂直之間的間距 | runSpacing:20.0 |
direction |
主軸的方向,默認(rèn)水平 | direction:Axis.horizontal, |
alignment |
主軸的對(duì)齊方式 | alignment:WrapAlignment.start |
Wrap(
spacing : 3.0,
runSpacing : 20.0,
direction:Axis.horizontal,
children: <Widget>[
MyButton("啊實(shí)打?qū)嵢?),
MyButton("啊實(shí)打"),
MyButton("啊實(shí)打2352實(shí)群"),
MyButton("實(shí)群"),
MyButton("實(shí)群"),
MyButton("啊實(shí)打2實(shí)群"),
MyButton("啊實(shí)打?qū)嵢?463"),
MyButton("群"),
MyButton("啊實(shí)43群"),
MyButton("啊4群"),
],
);
19怔鳖、StatefulWidget
當(dāng)頁(yè)面改變數(shù)據(jù)的時(shí)候我們需要使用
StatefulWidget
,例如當(dāng)我們點(diǎn)擊按鈕茉唉,讓文本的內(nèi)容發(fā)生改變
在StatefulWidget
中如果需要初始化值需要在initState
方法中實(shí)現(xiàn)
int _curderIndex = 0;
List _navList = new List();
@override
void initState() {
super.initState();
this._navList = [
];
}
class HomePage extends StatelessWidget {
String text = "你好Flutter1";
@override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Text(this.text),
SizedBox(height: 30.0,),
RaisedButton(
child: Text("按鈕"),
onPressed: (){
this.text = "asdq";
print(this.text);
},
)
],
);
}
}
通過(guò)上述例子我們知道 文本不會(huì)發(fā)生變化但是值是變化了的。這說(shuō)明在StatelessWidget不會(huì)改變組件的狀態(tài)了
19-1结执、定義一個(gè)StatefulWidget
組件
class HomePage extends StatefulWidget{
HomePage(Key key) : super({key : key});//可以省略
_HomePageState createState()=>_HomePageState ();
}
class _HomePageState extends State<HomePage>{
@overirde
Widget build(BuildContext context){
return Text("1");
}
}
在
StatefulWidget
組件中有一個(gè)setState((){})
的方法度陆,可以改變組件的狀態(tài)
class _HomePageState extends State<HomePage>{
int num = 0;
@override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Chip(label: Text("點(diǎn)擊${num}次")),
SizedBox(height: 30.0,),
RaisedButton(child: Text("按鈕"),
onPressed: (){
setState(() {//重點(diǎn)
this.num ++;
});
})
],
);
}
}
通過(guò)動(dòng)態(tài)組件我們寫一個(gè)案例:點(diǎn)擊按鈕增加一條數(shù)據(jù)
class _HomePageState extends State<HomePage>{
int num = 0;
List list = new List();
@override
Widget build(BuildContext context) {
return ListView(
children: <Widget>[
Column(
children: this.list.map((e){**重點(diǎn)**
return Text(e);
}).toList(),
),
SizedBox(height:30.0),
RaisedButton(
child: Text("按鈕"),
onPressed: (){
setState((){**重點(diǎn)**
this.num ++;
this.list.add("${this.num}條數(shù)據(jù)");
});
}
)
],
);
}
}
20、BottomNavigationBar自定義底部導(dǎo)航欄組件献幔,以及頁(yè)面切換
BottomNavigationBar
底部導(dǎo)航欄組件懂傀,它是屬于Scaffold
組件中的屬性
屬性 | 值類型 | 說(shuō)明 |
---|---|---|
items |
一個(gè)為BottomNavigationBarItem 的集合 |
items:[ BottomNavigationBarItem(icon: Icon(Icons.home),title: Text("首頁(yè)"))] |
onTap |
點(diǎn)擊導(dǎo)航欄的回調(diào)事件 | onTap:(index){print(index);}, |
currentIndex |
默認(rèn)選中的下標(biāo) | currentIndex:2 |
type |
導(dǎo)航欄的類型:fixed、shifting
|
type:BottomNavigationBarType.shifting |
fixedColor |
底部導(dǎo)航欄type為fixed時(shí)導(dǎo)航欄的顏色蜡感,如果為空的話默認(rèn)使用ThemeData.primaryColor | fixedColor:Colors.red |
iconSize |
導(dǎo)航欄圖片的大小 | iconSize:23 |
bottomNavigationBar: BottomNavigationBar(
currentIndex : 1,
onTap:(i){},
items: [
BottomNavigationBarItem(icon: Icon(Icons.home),title: Text("首頁(yè)")),
BottomNavigationBarItem(icon: Icon(Icons.list),title: Text("分類")),
BottomNavigationBarItem(icon: Icon(Icons.settings),title: Text("設(shè)置")),
],
),
20-1蹬蚁、設(shè)置點(diǎn)擊導(dǎo)航欄切換頁(yè)面/選中狀態(tài)
我們知道改變狀態(tài)需要在
StatefulWidget
中實(shí)現(xiàn)恃泪,那么我們把整個(gè)Scaffold
單獨(dú)抽出成一個(gè)組件
class HomePage extends StatefulWidget{
HomePage({Key key}):super(key:key);
@override
_HomePageState createState()=>_HomePageState();
}
class _HomePageState extends State<HomePage>{
int index = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("頁(yè)面定位布局"),),
body: MyBody(),
bottomNavigationBar: BottomNavigationBar(
currentIndex : this.index,
onTap:(i){
setState(() {
this.index = i;
});
},
items: [
BottomNavigationBarItem(icon: Icon(Icons.home),title: Text("首頁(yè)")),
BottomNavigationBarItem(icon: Icon(Icons.list),title: Text("分類")),
BottomNavigationBarItem(icon: Icon(Icons.settings),title: Text("設(shè)置")),
],
),
drawer: Drawer(
child: ListView(
children: <Widget>[
DrawerHeader(child: Text("Drawer"),decoration: BoxDecoration(color:Colors.pink),),
ListTile(leading: Icon(Icons.settings),title: Text("設(shè)置"),),
],
),
),
);
}
}
20-2、利用bottomNavigationBar切換頁(yè)面
我們?cè)趌ib中新建一個(gè)
pages
文件夾,然后創(chuàng)建幾個(gè)簡(jiǎn)單的Widget
import 'package:flutter/material.dart';
import './tabs/home.dart';
import './tabs/list.dart';
import './tabs/seting.dart';
class Tabs extends StatefulWidget{
Tabs({Key key}) : super (key:key);
@override
_TabsState createState()=>_TabsState();
}
class _TabsState extends State<Tabs>{
int _curInedex = 0;
List _pageList = [//頁(yè)面數(shù)組
HomePage(),
ListPage(),
SetingPage()
];
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(title:Text("導(dǎo)航欄的使用缚忧,切換")),
bottomNavigationBar: BottomNavigationBar(
currentIndex: this._curInedex,
onTap: (i){
setState((){
this._curInedex = i;
});
},
items: [
BottomNavigationBarItem(icon: Icon(Icons.home),title: Text("首頁(yè)")),
BottomNavigationBarItem(icon: Icon(Icons.line_weight),title: Text("分類")),
BottomNavigationBarItem(icon: Icon(Icons.settings),title: Text("設(shè)置")),
],
),
drawer: Drawer(
child: ListView(
children: <Widget>[
DrawerHeader(child: Text("抽屜組件"),decoration:BoxDecoration(color:Colors.pink)),
ListTile(leading: Icon(Icons.settings),title: Text("設(shè)置"),)
],
),
),
body: this._pageList[this._curInedex],重點(diǎn)
);
}
}
21悟泵、Flutter中的路由
Navigator.of()
跳轉(zhuǎn)某一頁(yè)面,Navigator.pop()回到上一頁(yè)面
Navigator.of(context).push(
MaterialPageRoute(builder:()=>頁(yè)面組件())
)
21-1闪水、頁(yè)面跳轉(zhuǎn)傳值
類似于
vue
的router
傳值
非常簡(jiǎn)單糕非,我們知道構(gòu)造函數(shù)是可以傳參的而我們的builder :()=>頁(yè)面組件(這里是可以傳參的)
Navigator.of(context).push(
MaterialPageRoute(builder:()=>MyPage(title:"標(biāo)題"));
)
class MyPage extends StatelessWidget{
String title = "";
MyPage({title:this.title})
...
}
22-2、路由命名跳轉(zhuǎn)
使用
Navigator.pushNamed()
如果要使用pushNamed
方法那么需要在MaterialApp
中定義好路由
MaterialApp(
title: "路由跳轉(zhuǎn)",
theme: ThemeData(primaryColor: Colors.pink),
routes: {//這里的key可以隨意起
"/form":(BuildContext context)=>FormPage(),
"/serach":(BuildContext context)=>SerachPage()
},
home: MyScaffold()
);
按鈕中實(shí)現(xiàn)路由跳轉(zhuǎn)
onPressed:(){
Navigator.pushNamed(context, "/serach");
}
22-3球榆、命名路由傳值朽肥、路由驗(yàn)證
命名路由傳值不能像構(gòu)造參數(shù)傳值那樣,需要指定
onGenerateRoute
屬性Flutter中文網(wǎng)持钉,onGenerateRoute
屬于MaterialApp
的屬性
路由攔截驗(yàn)證
假設(shè)我們要開(kāi)發(fā)一個(gè)電商APP衡招,當(dāng)用戶沒(méi)有登錄時(shí)可以看店鋪、商品等信息每强,但交易記錄始腾、購(gòu)物車、用戶個(gè)人信息等頁(yè)面需要登錄后才能看空执。
首先我們定義路由Map
案例:我們超前使用本地存儲(chǔ)功能獲取userName
MaterialApp(
routes: {
"/login" : (BuildContext context)=>LoginPage(),
"/home" :(BuildContext context)=>HomePage(),
"/card" :(BuildContext context)=>CardPage(),
...
},
"onGenerateRoute":(RouteSettings setings){
final String routeName = settings.name;//獲取進(jìn)入的路由名字,
final prefs = await SharedPreferences.getInstance(); //本地存儲(chǔ)獲取
final userName = prefs.getString("userName");
if(routeName !="/login" && !userName.isEmpty){//如果用戶名不存在那么我們跳轉(zhuǎn)至登錄頁(yè)面
Navigator.pushNamed(context, "/login");
}
}
);
命名路由傳參
這里有個(gè)巨坑浪箭,如果此時(shí)
MaterialApp
還配置routes
屬性會(huì)報(bào)錯(cuò);
切記,切記,切記
final _routes = {
"/login" : (BuildContext context)=>LoginPage(),
"/home" :(BuildContext context)=>HomePage(),
"/card" :(BuildContext context,{arguments})=>CardPage(infoCard:arguments),
...
},
MaterialApp(
"onGenerateRoute" : (RouteSettings setings){
final String name = settings.name;
final Function pageBuilder = this._routes[name];
if (pageBuilder != null) {
if (settings.arguments != null) {
// 如果透?jìng)髁藚?shù)
return MaterialPageRoute(
builder: (context) =>
pageBuilder(context, arguments: settings.arguments));
} else {
// 沒(méi)有透?jìng)鲄?shù)
return MaterialPageRoute(builder: (context) => pageBuilder(context));
}
}
}
)
然后我們需要在 CardPage頁(yè)面中接收`infoCard`參數(shù)
class CardPage extends StatelessWidget{
final infoCard;
CardPage({this.infoCard});
...
}
配置根路由
我們開(kāi)發(fā)
Vue
項(xiàng)目知道,一般會(huì)配置一個(gè)根路由
在flutter
中配置跟路由使用initialRoute
屬性辨绊,該屬性屬于MaterialApp
,當(dāng)使用了該屬性時(shí)奶栖,在使用home
屬性可能會(huì)導(dǎo)致混亂
MaterialApp(
initialRoute:"/home"
)
22-4恭应、替換根路由
Navigator.pushReplacementNamed();
Navigator.of(context).pushAndRemoveUntil;
使用場(chǎng)景:當(dāng)我們跳轉(zhuǎn)頁(yè)面中在跳轉(zhuǎn)頁(yè)面障般,例如當(dāng)我們點(diǎn)擊注冊(cè)按鈕進(jìn)入注冊(cè)頁(yè)面,然后輸入完信息之后岗屏,點(diǎn)擊下一步默蚌,跳轉(zhuǎn)第二步注冊(cè)冻晤,然后點(diǎn)擊注冊(cè)完成按鈕,返回的頁(yè)面應(yīng)該不是第一步中的注冊(cè)頁(yè)面绸吸,而是其實(shí)頁(yè)面
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text("請(qǐng)輸入手機(jī)號(hào)鼻弧,密碼,點(diǎn)擊下一步繼續(xù)完成注冊(cè)操作"),
RaisedButton(onPressed: (){
//進(jìn)入第二步驟注冊(cè)頁(yè)面
Navigator.pushReplacementNamed(context, "/regSend");
},child: Text("下一步"),)
],
)
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text("注冊(cè)完成"),
RaisedButton(onPressed: (){
//此時(shí)pop返回的不是第一步注冊(cè)頁(yè)面了惯裕,而是其實(shí)頁(yè)面了
Navigator.of(context).pop();
},child: Text("完成注冊(cè)"),)
],
)
如果頁(yè)面嵌套很多層温数,而每次都使用Navigator.pushReplacementNamed();
保存根確實(shí)有些小麻煩,那么我們可以使用pushAndRemoveUntil
方法,不管你嵌套多少層蜻势,直接使用該方法直接可返回跟路由
Navigator.of(context).pushAndRemoveUntil(
//這個(gè)案例是返回tab頁(yè)面
new MaterialPageRoute(builder: (context)=>Tabs(index:1)),
(route)=>route == null);
23撑刺、floatingActionButton浮動(dòng)按鈕
floatingActionButton
是屬于Scaffold
中的屬性
floatingActionButton: FloatingActionButton(onPressed: (){
Navigator.pop(context);//路由返回
},child: Text("返回"),),
23-1 控制floatingActionButton的顯示位置
floatingActionButtonLocation
屬性該屬性是在Scaffold
中的,
與floatingActionButton
是同級(jí)關(guān)系
Scaffold(
floatingActionButton: FloatingActionButton(onPressed: (){},child: Icon(Icons.add),),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,//底部中間
)
23-2實(shí)現(xiàn)底部導(dǎo)航的凸起按鈕
思路:我們可以定義5個(gè)
bottomNavigationBar
然后使floatingActionButton
蓋住中間的那一個(gè)然后點(diǎn)擊事件我們改變curIndex的值即可
Scaffold(
floatingActionButton: Container(
width: 62.0,
height: 62.0,
padding: EdgeInsets.all(3.0),//padding
decoration: BoxDecoration(
shape:BoxShape.circle,//圓形
color: Colors.white,//白色
boxShadow:[BoxShadow(color: Colors.black26, offset: Offset(0, 0),blurRadius: 2.0, spreadRadius: 0.0)]//陰影
),
child: FloatingActionButton(onPressed:(){
setState(() {
this.curIndex = i;
});
},splashColor: null,elevation:0,child: Icon(Icons.add,size: 40.0,color: Color.fromRGBO(51, 51, 51, 1),),backgroundColor: Colors.yellow,),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
bottomNavigationBar: BottomNavigationBar(
items: [
BottomNavigationBarItem(icon: Icon(Icons.home),title: Text("首頁(yè)")),
BottomNavigationBarItem(icon: Icon(Icons.list),title: Text("分類")),
BottomNavigationBarItem(icon: Icon(Icons.text_fields),title: Text("賣閑置")),
BottomNavigationBarItem(icon: Icon(Icons.shopping_cart),title: Text("購(gòu)物車")),
BottomNavigationBarItem(icon: Icon(Icons.people),title: Text("我的")),
],
type:BottomNavigationBarType.fixed,
currentIndex: this.curIndex,
onTap: (i){
setState(() {
this.curIndex = i;
});
},
),
)
24、SingleChildScrollView
當(dāng)我們軟鍵盤彈起的時(shí)候握玛,會(huì)蓋住我們的內(nèi)容够傍,這是就會(huì)報(bào)越界,使用
SingleChildScrollView
頁(yè)面會(huì)隨高度改變而又滾動(dòng)條
25甫菠、自定義AppBar以及Tab切換
在使用
AppBar
我們之前一直都是直接title
屬性帶過(guò),現(xiàn)在我們仔細(xì)看看它有哪些屬性
屬性 | 描述 | 用法 |
---|---|---|
title |
標(biāo)題 |
title:Text("標(biāo)題") 當(dāng)然也可以不是Text |
leading |
AppBar左側(cè)組件 |
leading:Icon(Icons.back) 當(dāng)然也可以不是Icon |
actions |
右側(cè)組件集合 | actions:[Icon(Icons.back),Icon(Icons.back)] |
backgroundColor |
Appbar背景顏色 | backgroundColor:Colors.blue |
bottom |
通常放TabBar冕屯,標(biāo)題下面放一欄tab切換 | bottom:TabBar(tabs: [ ]) |
iconTheme |
appbar中的圖標(biāo)統(tǒng)一樣式 | iconTheme: IconThemeData(color: Colors.pink,opacity:0.3,size:20), |
textTheme |
文字樣式 | textTheme : TextTheme(headline1:TextStyle(color: Colors.black)) |
centerTitle |
標(biāo)題是否居中 | centerTitle:true |
Scaffold(
appBar : AppBar(
leading: IconButton(icon: Icon(Icons.pin_drop), onPressed: (){
//這里我們使用了IconButton組件圖標(biāo)按鈕點(diǎn)擊返回根組件
Navigator.pushNamed(context, "/");
}),
backgroundColor: Colors.blue,
title: Text("AppBarDemo"),
actions: [//右側(cè)組件集合
Icon(Icons.home),
Text("電話")
],
centerTitle : true,//標(biāo)題居中
iconTheme: IconThemeData(color: Colors.pink,opacity:1,size:30),
textTheme : TextTheme(headline1:TextStyle(color: Colors.black),overline:TextStyle(color: Colors.black))
)
)
25-1Tab切換
進(jìn)行Tab切換在
Scaffold
組件中需要包裹一層DefaultTabController
組件
TabBar常用屬性
屬性 | 描述 | 用法 |
---|---|---|
tabs |
tab的內(nèi)容 | tabs: [Tab(text: "tab1"),Tab(text: "tab2",) ] |
controller |
TabController對(duì)象 | controller:TabController() |
isScrollable |
是否可以滾動(dòng),當(dāng)有多個(gè)Tab選項(xiàng)時(shí)就會(huì)被擠在一起,設(shè)置為true 可以解決 |
isScrollable:false |
indicatorColor |
指示器顏色 | indicatorColor:Colors.blue |
indicatorWeight |
指示器高度 | indicatorWeight:2 |
indicatorPadding |
指示器的padding | indicatorPadding:EdgeInsets.all(10), |
indicator |
指示器的描述樣式 | indicator: Decoration(***) |
labelColor |
文字的顏色 | labelColor:Colors.blue |
labelStyle |
文字的樣式 | labelStyle:TextStyle() |
labelPadding |
文字的padding | labelPadding:EdgeInsets.all(10) |
unselectedLabelColor |
未選中的文字顏色 | unselectedLabelColor:Colors.pink |
unselectedLabelStyle |
未選中的文字樣式 | lunselectedLabelStyle:TextStyle() |
DefaultTabController(
length:2,//定義有幾個(gè)tab切換
child:Scaffold(
appBar:AppBar(
title:Text("自定義Tab切換"),
bottom:TaBar(
tabs:[
Tab(text:"音樂(lè)",icon:Icon(Icons.headset)),
Tab(text:"推薦"),
],//tab切換
),
),
body:TabBarView(//主內(nèi)容需要用TabBarView包括
children:[
Center(child:Text("對(duì)應(yīng)音樂(lè)")),//順序?qū)?yīng)bottom中的tabs順序
Center(child:Text("對(duì)應(yīng)推薦")),
]
)
)
)
這個(gè)是單獨(dú)頁(yè)面定義自動(dòng)以Tab切換寂诱,如果我們要在底部導(dǎo)航欄頁(yè)面增加Tab切換怎么做呢。因?yàn)槲覀兊撞繉?dǎo)航欄頁(yè)面是分別抽出來(lái)公共
Scaffold
組件的安聘,如果被DefaultTabController
包裹痰洒,那么所有的底部導(dǎo)航欄頁(yè)面都會(huì)增加Tab切換
Scaffold中可以繼續(xù)嵌套Scaffold
DefaultTabController(length: 2, child: Scaffold(
appBar: AppBar(
leading: Icon(null),
centerTitle: true,
title: Row(//這里title我們改成了TaBar
children: <Widget>[
Expanded(child: TabBar(labelColor:Colors.blue,tabs: [
Tab(text: "tab1"),
Tab(text: "tab2",)
]))
],
),
),
body: TabBarView(children: [
Column(
mainAxisAlignment:MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text("頁(yè)面?zhèn)髦堤D(zhuǎn),類似于vue、Router跳轉(zhuǎn)傳值"),
RaisedButton(onPressed: (){
Navigator.of(context).push(
MaterialPageRoute(builder: (context)=>FormPage(formInfo:{'id':"傳值的12"}))
);
},child: Text("傳值跳轉(zhuǎn)"),)
],
),
Center(child:Text("第二個(gè)tab2"))
]),
)
)
25-2 自定義TabBar
為什么我們要自定義呢浴韭?為什么不用上述的例子呢丘喻?用上述的例子我們無(wú)法監(jiān)聽(tīng)tab切換的事件,而自定義我們可以監(jiān)聽(tīng)
如果要使用自定義TabBar的話念颈,組件必須是StatefulWidget
動(dòng)態(tài)組件并且需要實(shí)現(xiàn)SingleTickerProviderStateMixin
class TabBarController extends StatefulWidget{
_TabBarControllerState createState()=> _TabBarControllerState();
}
//這里要實(shí)現(xiàn)SingleTickerProviderStateMixin
class _TabBarControllerState extends State<TabBarController> with SingleTickerProviderStateMixin{
TabController _tabController;
@override
void initState(){
this._tabController = TabController(length:2,vsync:this);
this._tabController.addListener((){//監(jiān)聽(tīng)切換事件
print(this._tabController.index);//切換的下標(biāo)
});
}
@override
Widget build(BuildContext context) {
return Scaffold{
appBar:AppBar(
title:Text("TabBarController"),
bottom:TabBar(tabs:[
Tab(child:Text("tab1")),
Tab(child:Text("tab2")),
],
controller:this._tabController//別忘了這一步
)
),
body:TabBarView(
children : [
Center(child:Text("切換至Tab1")),
Center(child:Text("切換至Tab2")),
],
controller:this._tabController//別忘了這一步TabBarView也需要加上
)
}
}
}
26泉粉、Draw抽屜側(cè)邊欄
drawer
是屬于Scaffold
中的屬性左側(cè)側(cè)邊欄
endDrawer
是屬于Scaffold
中的屬性右側(cè)側(cè)邊欄
Scaffold(
drawer: Drawer(
child: ListView(
children: <Widget>[
DrawerHeader(child: Text("抽屜組件"),decoration:BoxDecoration(color:Colors.pink)),
ListTile(leading: Icon(Icons.settings),title: Text("設(shè)置"),)
],
),
),
endDrawer : Drawer(
child: ListView(
children: <Widget>[
DrawerHeader(child: Text("抽屜組件"),decoration:BoxDecoration(color:Colors.pink)),
ListTile(leading: Icon(Icons.settings),title: Text("設(shè)置"),)
],
),
)
)
26-1使用UserAccountsDrawerHeader在側(cè)邊欄顯示用戶信息
屬性 | 描述 | 用法 |
---|---|---|
accountName |
用戶名 | accountName:Text("十年之后") |
accountEmail |
可以稱為用戶描述寄語(yǔ),官方是郵箱的意思 | accountEmail:Text("簡(jiǎn)書(shū)寫你所想") |
currentAccountPicture |
用戶頭像圖片 | currentAccountPicture:CircleAvatar(backgroundImage: NetworkImage(***))) |
drawer: Drawer(
child: ListView(
children: <Widget>[
UserAccountsDrawerHeader(
accountName: Text("十年之后"), accountEmail: Text("簡(jiǎn)書(shū)榴芳,寫你所想"),
currentAccountPicture:CircleAvatar(backgroundImage: NetworkImage("https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=2586537036,779451914&fm=26&gp=0.jpg"),radius: 25.0,)
),
ListTile(
leading: Icon(Icons.settings),
title: Text("設(shè)置"),
)
],
),
),
27 ButtonBar按鈕組
ButtonBar
里面放N個(gè)按鈕
屬性 | 描述 | 用法 |
---|---|---|
children |
按鈕組 | children:[] |
alignment |
按鈕組的對(duì)齊方式 | alignment:MainAxisAlignment.start, |
ButtonBar(
alignment:MainAxisAlignment.start,
children: <Widget>[
FlatButton(onPressed: (){},child: Text("扁平化按鈕"),color:Colors.blue),
],
)
28表單
28-1TextFaild
輸入表單類似
input
屬性 | 描述 | 應(yīng)用 |
---|---|---|
decoration - hintText |
類似于前端placeholder提示信息 | decoration:InputDecoration(hintText:"輸入名字") |
decoration - border |
給輸入框增加邊框 | decoration:InputDecoration(border:OutlineInputBorder()) |
maxLength |
限制輸入框輸入的字符長(zhǎng)度 |
maxLength:4 限制只能輸入4個(gè)字符 |
maxLines |
多行文本嗡靡,類似于textarea
|
maxLines:4 限制4行 |
obscureText |
密碼框 | obscureText:true |
controller |
輸入框里面輸入的值 | controller:TextEditingController(text:'十年之后') |
decoration - labelText |
decoration:InputDecoration(labelText:"用戶名") |
|
decoration - icon |
decoration:InputDecoration(icon: Icon(Icons.home)) |
|
onChanged |
監(jiān)聽(tīng)輸入框文本改變的事件 | onChanged:(val){print(val);} |
TextField(
obscureText : true,//密碼
maxLength : 14,//只能輸入14個(gè)字符
maxLines : 1,//只有一行
decoration : InputDecoration(
border:OutlineInputBorder(),//邊框
labelText:"密碼",
icon:Icon(Icons.format_indent_increase)
)
)
28-1-1、TextFaild獲取輸入的值/修改值
利用
TextFaild
中的controller
屬性我們綁定值
var user_name = TextEditingController();
@initState(){
user_name.text = "十年之后初始值";注意這里修改的是text的屬性的值
}
TextField(
controller:user_name,這里賦值
decoration: InputDecoration(
labelText: "用戶名",
contentPadding: EdgeInsets.all(3),
border: OutlineInputBorder()
),
)
點(diǎn)擊按鈕獲取表單輸入的值
TextField(
controller:user_name,這里賦值
decoration: InputDecoration(
labelText: "用戶名",
contentPadding: EdgeInsets.all(3),
border: OutlineInputBorder()
),
)
RaisedButton(onPressed: (){
print(this.user_name.text);注意這里是獲取user_name中的text
},child: Text("獲取表單的值"),)
點(diǎn)擊修改輸入框的值
RaisedButton(onPressed: (){
setState(() {
this.user_name.text = "十年之后Dart與Flutter";
});
},child: Text("修改表單的值"),),
28-2 CheckBox多選框
屬性 | 描述 | 應(yīng)用 |
---|---|---|
value |
綁定的值 |
value:flag 事先定義flag |
onChanged |
監(jiān)聽(tīng)狀態(tài)改變 | onChanged:(val){setState((){flag=val;})} |
activeColor |
選中時(shí)的顏色 | activeColor:Colors.blue |
var flag = false;
Row(children:[
Checkbox(value: flag, onChanged: (val){
setState(() {
this.flag = val;
});
}),
Text(this.flag?"選中":"未選中")
])
28-2-1 CheckBoxListTitle
屬性 | 描述 | 用法 |
---|---|---|
selected |
選中高亮 | selected:判斷當(dāng)前枚舉值是否等該枚舉值就高亮 |
CheckBoxListTitle
與ListTitle
類似
CheckboxListTile(value: flag,onChanged: (val){
setState(() {
flag = val;
});
},title:Text("同意協(xié)議"),subtitle: Text("23456"),),
28-3 Radio單選框
Radio
往往是成對(duì)出現(xiàn)的窟感,怎么保證多個(gè)Radio
是一個(gè)組呢讨彼?
這時(shí)候我們要用groupValue
屬性給多個(gè)Radio
綁定同一個(gè)值
屬性 | 描述 | 應(yīng)用 |
---|---|---|
value |
該單選框的枚舉值 |
value:1 寫上你的枚舉值不用是變量 |
groupValue |
綁定的值 |
groupValue:this.sex 事先定義sex |
onChanged |
監(jiān)聽(tīng)改變事件 | onChanged:(val){setState((){sex=val;})} |
var sex = 1;
Row(
children: <Widget>[
Text("男:"),
Radio(value: 1, groupValue: this.sex, onChanged: (v){
setState(() {
this.sex = v;
});
}),
Text("女:"),
Radio(value: 2, groupValue: this.sex, onChanged: (v){
setState(() {
this.sex = v;
});
})
],
)
28-3-1、RadioListTitle
屬性 | 描述 | 用法 |
---|---|---|
selected |
選中高亮 | selected:判斷當(dāng)前枚舉值是否等該枚舉值就高亮 |
與CheckBoxListTitle
類似
RadioListTile(value: 1, groupValue: this.a, onChanged: (v){
setState(() {
this.a = v;
});
},title: Text("爬山"),subtitle: Text("2020-06-02"),selected:this.a==1),
RadioListTile(value: 2, groupValue: this.a, onChanged: (v){
setState(() {
this.a = v;
});
},title: Text("游泳"),subtitle: Text("2020-06-02"),selected:this.a==2),
28-4肌括、Switch開(kāi)關(guān)
Switch(value: b, onChanged: (v){
setState(() {
b =v;
});
})
28-4-1 SwitchListTitle
SwitchListTile(value: b, onChanged: (v){
setState(() {
b =v;
});
},title: Text("開(kāi)關(guān)"),subtitle: Text("描述"),)
28-5点骑、練習(xí)表單
重點(diǎn)是利用數(shù)組循環(huán)map渲染興趣
Scaffold(
appBar: AppBar(title: Text("formDemo練習(xí)"),),
body: Container(
padding: EdgeInsets.all(20.0),
child: Column(
children: <Widget>[
TextField(
controller: this.user_name,
onChanged: (v){
setState(() {
this.user_name.text = v;
});
},
decoration: InputDecoration(
labelText: "用戶名",
border: OutlineInputBorder(),
contentPadding: EdgeInsets.all(3.0)
),
),
SizedBox(height: 10.0,),
Row(
children: <Widget>[
Text("性別"),
Radio(value: true, groupValue: this.sex, onChanged: this._setSex),
Text("男"),
Radio(value: false, groupValue: this.sex, onChanged: this._setSex),
Text("女"),
],
),
SizedBox(height: 10.0,),
Row(
children: this._listCheck(),
),
SizedBox(height: 10.0,),
TextField(
controller: this.user_info,
maxLines: 4,
decoration: InputDecoration(
border: OutlineInputBorder(),
hintText:"用戶信息"
),
onChanged: (v){
setState(() {
this.user_info.text = v;
});
},
),
SizedBox(height:10.0),
RaisedButton(onPressed: (){},child: Text("提交"),color: Colors.blue,textColor: Colors.white,)
],
)
)
);
29酣难、DateTime時(shí)間谍夭、時(shí)間組件
29-1、獲取當(dāng)前時(shí)間
DateTime.now()
print(DateTime.now()) 2020-06-03 15:06:30.832249
29-2憨募、獲取時(shí)間戳
millisecondsSinceEpoch
print(DateTime.now().millisecondsSinceEpoch) 1591167990832
29-3紧索、時(shí)間戳轉(zhuǎn)化成日期對(duì)象
DateTime.fromMillisecondsSinceEpoch(時(shí)間戳)
DateTime date = DateTime.now() 獲取當(dāng)前時(shí)間
int timeStamp = date.millisecondsSinceEpoch;
print(DateTime.fromMillisecondsSinceEpoch(timeStamp))
29-4、轉(zhuǎn)化成指定的年月日
使用第三方庫(kù)
date_format
地址
1菜谣、在項(xiàng)目的跟目錄pubspec.yaml
中追加包
dependencies:
date_format: ^1.0.8
2珠漂、在需要用到插件的文件中添加
import 'package:date_format/date_format.dart';
3、使用
DateTime date = DateTime.now();
print(formatDate(date, [yyyy, '年', mm, '月', dd,'日',' ',HH,':',nn,':',ss]));
2020年06月03日 15:23:43
29-5尾膊、flutter自帶的日期組件
使用日期組件并獲取選中后的值
DateTime date = DateTime.now();//獲取當(dāng)前日期
void _showDatePicker() async{//自定義顯示日期方法
var result = await showDatePicker(
context : context,//上下文
initialDate:date,//默認(rèn)選中的日期
firstDate:DateTime(1980),//日期組件的起始日期我們定在1980年
lastDate:DateTime(2050),//日期組件的結(jié)束日期
);
print(result );//這個(gè)就是我們選中之后的值注意該方法為異步方法
setState((){
this.date = result;
})
}
//然后我們?cè)邳c(diǎn)擊事件中調(diào)用這個(gè)自定義方法
InkWell(
onTap:(){
this._showDatePicker()//調(diào)用日期控件
},
child:Text("顯示日期組件")
)
29-6媳危、flutter自帶的時(shí)間控件
DateTime time = DateTime.now();//獲取當(dāng)前日期
void _showTimePicker() async{//自定義顯示日期方法
var result = await showTimePicker(
context: context,
initialTime: TimeOfDay(hour:time.hour,minute:time.minute)//重點(diǎn)哦
);
print(result );//這個(gè)就是我們選中之后的值注意該方法為異步方法
setState((){
this.time = result;
})
}
//然后我們?cè)邳c(diǎn)擊事件中調(diào)用這個(gè)自定義方法
InkWell(
onTap:(){
this._showTimePicker()//調(diào)用日期控件
},
child:Text("顯示時(shí)間組件")
)
29-7、怎么把日期冈敛、時(shí)間控件轉(zhuǎn)為中文
要用到flutter中的國(guó)際化待笑,具體可以查看Flutter 中的國(guó)際化
29-8、第三方日期抓谴、時(shí)間組件
DatePicker.showDatePicker(context,
showTitleActions: true,
minTime: DateTime(2018, 3, 5),
maxTime: DateTime(2019, 6, 7), onChanged: (date) {
print('change $date');
}, onConfirm: (date) {
print('confirm $date');
},
currentTime: DateTime.now(),
locale: LocaleType.zh
);
30暮蹂、InkWell組件
效果:給一些沒(méi)有點(diǎn)擊事件的組件增加事件的,
例如如果我們要給Text
增加點(diǎn)擊事件寞缝,以往我們只能套子button中,但現(xiàn)在不用
InkWell(
child:Text("監(jiān)聽(tīng)點(diǎn)擊事件"),
onTap:(){
print(DateTime.now())
}
)
31仰泻、第三方輪播圖插件
flutter_swiper
Swiper需要包裹在Container
中荆陆,并且需要設(shè)置寬高不然報(bào)錯(cuò)
Swiper(
itemBuilder: (BuildContext context,int index){
return new Image.network("http://via.placeholder.com/350x150",fit: BoxFit.fill,);
},
itemCount: 3,
pagination: new SwiperPagination(),
control: new SwiperControl(),
),
);
32、各種DiaLog彈出層
AlertDialog
集侯、SimpleDialog
被啼,showModalBottomSheet
這些DiaLog
需要放在showDialog
方法中
關(guān)閉遮罩Navigator.pop()
32-1、AlertDialog
void _showAlertDiaLog() async{
var result = await showDialog(context: context,builder: (context){
return AlertDialog(
title: Text("提示信息"),
content: Text("您確定要?jiǎng)h除么棠枉?"),
actions: <Widget>[
RaisedButton(onPressed: (){
print("確定");
Navigator.pop(context,'傳值給result');傳值出去
},child: Text("是"),),
RaisedButton(onPressed: (){
print("否");
Navigator.pop(context);
},child: Text("否"),)
],
);
});
print(result);
}
32-2趟据、SimpleDialog
void _showSimpleDiaLog()async {
var result = await showDialog(context: context,builder: (context){
return SimpleDialog(
title: Text("提示信息"),
children: [
SimpleDialogOption(
onPressed:(){
Navigator.pop(context,'測(cè)試');
},
child: Text("測(cè)試"),
),
Divider(),
SimpleDialogOption(
onPressed:(){
Navigator.pop(context,'測(cè)試1');
},
child: Text("測(cè)試1"),
),
Divider(),
SimpleDialogOption(
onPressed:(){
Navigator.pop(context,'測(cè)試2');
},
child: Text("測(cè)試2"),
),
Divider(),
//當(dāng)然也可以是其他的組件
InkWell(
onTap: (){
Navigator.pop(context,'InkWell組件');
},
child: Text("InkWell組件"),
)
],
);
});
print(result);
}
32-3、showModalBottomSheet類似于購(gòu)物車/時(shí)間選擇器底部彈出框
他不用使用
showDialog
來(lái)彈出
void _showShowModalBottomSheet(){
showModalBottomSheet(
context: context,
builder: (context){
return Container(
height: 250.0,//控制彈出的高度
child: Column(
children: <Widget>[
ListTile(
title: Text("分享A"),
onTap: (){
Navigator.pop(context);
},
),
Divider(),
ListTile(
title: Text("分享B"),
onTap: (){Navigator.pop(context);},
),
Divider(),
ListTile(
title: Text("分享C"),
onTap: (){Navigator.pop(context);},
),
],
),
);
}
);
}
32-4术健、使用第三方插件toast
dependencies:
fluttertoast: ^4.0.1
import 'package:fluttertoast/fluttertoast.dart';
void _showShowToast(){
Fluttertoast.showToast(
msg: "提示信息",
gravity: ToastGravity.BOTTOM,
timeInSecForIosWeb: 1,//設(shè)置停留時(shí)間 只在IOS端有效
backgroundColor: Colors.black,
textColor: Colors.white,
fontSize: 16.0
);
}
33汹碱、flutter中網(wǎng)絡(luò)請(qǐng)求
33-1、JSON字符串與flutter中的Map類型相互轉(zhuǎn)換
需要調(diào)用
import 'dart:convert';
jsonDecode
字符串json轉(zhuǎn)為Map
jsonEncode
Map轉(zhuǎn)為字符串
String list_json = '{"result":"測(cè)試","code":0}';
jsonDecode(list_json ); = >轉(zhuǎn)為Map
Map map = {"result":"測(cè)試","code":0};
jsonEncode(map );
技巧
container圓形/陰影
Container(
width:50.0,
height:50.0,
decoration:BoxDecoration(
color:Colors.yellow,//背景圖片
shape:BoxShape.circle,//圓形
boxShadow:[BoxShadow(color: Colors.black, offset: Offset(0, 0),blurRadius: 2.0, spreadRadius: 0.0)]//陰影
)
)
width/height相對(duì)于父容器100%
double.infinity
container(
height:double.infinity,
height:double.infinity,
)
總結(jié)目前學(xué)的組件有哪些
名稱 | 描述 |
---|---|
MaterialApp |
根組件 |
Scaffold |
根組件中的home |
Text |
文本組件 |
Container |
容器組件 |
ListView |
列表組件 |
ListView.builder |
列表組件中的循環(huán)動(dòng)態(tài)生成 |
SizedBox |
這個(gè)組件目的撐開(kāi)組件與組件之間的距離 |
GridView.count() /GridView.builder()
|
柵格化布局 |
Padding |
內(nèi)邊距組件EdgeInsets.only(bottom: 10.0) 僅bottom增加邊距 |
Row |
橫軸排列組件 |
Cloumn |
縱軸排列組件 |
Expanded |
Flex布局組件 |
Image |
圖片組件 |
Icon |
圖標(biāo)組件 |
Stack |
對(duì)子元素統(tǒng)一定位 |
Align |
與Stack 一起配合使用荞估,對(duì)多個(gè)子元素進(jìn)行定位 |
Position |
與Stack 一起配合使用咳促,對(duì)多個(gè)子元素進(jìn)行定位 |
AspectRatio |
定義子組件與父元素的寬高比例 |
Card |
卡片,可以給容器加陰影效果 |
ClipOval |
圓形組件 |
CircleAvatar |
圓形組件含有backgroundImage |
Wrap |
流式布局,當(dāng)子元素橫軸鋪滿時(shí)自動(dòng)換行至第二行 |
RaisedButton |
凸起按鈕 |
BottomNavigationBar |
導(dǎo)航欄屬于Scaffold 中的參數(shù)/屬性 |
floatingActionButton |
浮動(dòng)底部按鈕導(dǎo)航欄屬于Scaffold 中的參數(shù)/屬性,可以實(shí)現(xiàn)底部凸起導(dǎo)航按鈕
|
SingleChildScrollView |
解決鍵盤彈起覆蓋內(nèi)容而引起的越界錯(cuò)誤 |
IconButton |
圖標(biāo)按鈕,注意此圖標(biāo)按鈕不帶字 |
RaisedButton.icon |
帶字的圖標(biāo)按鈕 |
FlatButton |
扁平化按鈕,不帶邊框,不帶陰影 |
OutlineButton |
只帶邊框的按鈕,沒(méi)有背景色 |
BottonBar |
按鈕組 |
floatingActionButtonLocation |
不是button控制floatingActionButton 的位置 |
TextFaild |
輸入框 |
Divider() |
直接使用效果是一根線條/分割線 |
CheckBox |
復(fù)選框 |
CheckBoxListTitle() |
帶標(biāo)題的復(fù)選框,可以包裹Container控制寬高 |
Radio() |
單選框 |
RadioListTitle() |
帶標(biāo)題的單選框,可以包裹Container控制寬高 |
Switch() |
開(kāi)關(guān) |
SwitchListTitle() |
帶標(biāo)題的開(kāi)關(guān),可以包裹Container控制寬高 |
InkWell |
給一些沒(méi)有點(diǎn)擊事件的組件增加監(jiān)聽(tīng)點(diǎn)擊事件 |
showDiaLog() |
用來(lái)顯示彈出框 |
AlertDiaLog() |
提示框 |
SimpleDialog() |
提示框1 |
showModalBottomSheet() |
底部彈出框/類似日期控件 |