Drat與Flutter基礎(chǔ)

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ū)分StatefullWidgetStatelessWidget的區(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)))
      )
    );
  }
}
image.png

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è)置底層背景為粉紅色
      )
    );
image.png

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ì)齊方式
        ),
      )
    );
  }
image.png

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常用屬性

屬性 描述 用法
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

image.png

BoxFit.fill
image.png

BoxFit.contain
image.png

    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
          ),
        ),
      )
image.png

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
image.png

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,),
        ),
      )
image.png

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
     )
image.png

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á)四大")
image.png

這是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è)走出困境?")
            ),
          )
        ],
      ),
image.png

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()
    );
  }
}
image.png

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();
  }
image.png

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組件

image.png

柵格布局:
常用有兩種方法:
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)情況

默認(rèn)情況

MainAxisAlignment.spaceEvenly均勻分配橫軸方向
image.png

縱軸相對(duì)于父元素瞧栗,如果父元素沒(méi)有斯稳,那么無(wú)效CrossAxisAlignment.start

image.png

11-2、Colum組件

用法屬性和Row一致

mainAxisAlignment:MainAxisAlignment.spaceEvenly,
crossAxisAlignment:CrossAxisAlignment.start,
image.png

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),
        ],
      );
  }
image.png

和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),
        ],
      );
image.png

12、布局小結(jié)

實(shí)現(xiàn)下面的布局


image.png
@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),)
      ],
    );
image.png

結(jié)果發(fā)現(xiàn)子組件都堆疊在一起了

alignment: Alignment.center

Alignment.center會(huì)把所有的組件居中堆疊在一起``

image.png

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,),
            ),
            
          ],
        ),
      ),
    );
image.png

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,),
            ),
            
          ],
        ),
      ),
    );
image.png

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


image.png

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)以下布局

image.png
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群"),
      ],
    );
image.png

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ù)");
            });
          }
        )
      ],
    );
  }
}
image.png

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)傳值

類似于vuerouter傳值
非常簡(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的值即可

image.png
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;
          });
        },
      ),
)

image.png

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))
      )
    )
image.png

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)推薦")),
      ]
     )
  )
)
image.png

這個(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"))
      ]),
    )
    )
image.png

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è)置"),)
          ],
        ),
      )
)
image.png

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
labelText
decoration:InputDecoration(labelText:"用戶名")
decoration - icon
表單圖標(biāo)
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)
  )
)
image.png

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)前枚舉值是否等該枚舉值就高亮

CheckBoxListTitleListTitle類似

CheckboxListTile(value: flag,onChanged: (val){
 setState(() {
  flag = val;
  });
 },title:Text("同意協(xié)議"),subtitle: Text("23456"),),
image.png

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),
image.png

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í)表單

image.png

重點(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自帶的日期組件

image.png

使用日期組件并獲取選中后的值

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í)間控件

image.png
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í)間組件

flutter_datetime_picker

  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);
  }
image.png

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);
  }
image.png

32-3、showModalBottomSheet類似于購(gòu)物車/時(shí)間選擇器底部彈出框

他不用使用showDialog來(lái)彈出

image.png
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

image.png

fluttertoast

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
jsonEncodeMap轉(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() 底部彈出框/類似日期控件
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末勘伺,一起剝皮案震驚了整個(gè)濱河市跪腹,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌飞醉,老刑警劉巖冲茸,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異缅帘,居然都是意外死亡轴术,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門钦无,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)逗栽,“玉大人,你說(shuō)我怎么就攤上這事失暂”顺瑁” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵弟塞,是天一觀的道長(zhǎng)凭峡。 經(jīng)常有香客問(wèn)我,道長(zhǎng)决记,這世上最難降的妖魔是什么摧冀? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上按价,老公的妹妹穿的比我還像新娘惭适。我一直安慰自己,他們只是感情好楼镐,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布癞志。 她就那樣靜靜地躺著,像睡著了一般框产。 火紅的嫁衣襯著肌膚如雪凄杯。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,007評(píng)論 1 284
  • 那天秉宿,我揣著相機(jī)與錄音戒突,去河邊找鬼。 笑死描睦,一個(gè)胖子當(dāng)著我的面吹牛膊存,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播忱叭,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼隔崎,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了韵丑?” 一聲冷哼從身側(cè)響起爵卒,我...
    開(kāi)封第一講書(shū)人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎撵彻,沒(méi)想到半個(gè)月后钓株,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡陌僵,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年轴合,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片拾弃。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡值桩,死狀恐怖摆霉,靈堂內(nèi)的尸體忽然破棺而出豪椿,到底是詐尸還是另有隱情,我是刑警寧澤携栋,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布搭盾,位于F島的核電站,受9級(jí)特大地震影響婉支,放射性物質(zhì)發(fā)生泄漏鸯隅。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蝌以。 院中可真熱鬧炕舵,春花似錦、人聲如沸跟畅。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)徊件。三九已至奸攻,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間虱痕,已是汗流浹背睹耐。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留部翘,地道東北人硝训。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像新思,于是被迫代替她去往敵國(guó)和親捎迫。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345