Flutter基本組件1

文本

Flutter中使用Text來實(shí)現(xiàn)一般的文本灼捂,構(gòu)建一個(gè)Text方法如下:

//構(gòu)造實(shí)例
 Text(......)
 new Text(......)

屬性

屬性 作用
style 文本樣式课梳,返回TextStyle鞭莽,可以設(shè)置字體顏色枉疼、下劃線旭贬、字體大小等(最常用的玩意兒呛梆,基本上都得用)
textAlign 文本對齊方式
softWrap 是否自動(dòng)換行凯傲,值為boolean型
overflow 當(dāng)文本內(nèi)容超過最大行數(shù)時(shí)犬辰,剩余內(nèi)容的顯示方式當(dāng)文本內(nèi)容超過最大行數(shù)時(shí),剩余內(nèi)容的顯示方式
textDirection 文本方向冰单,即文字從那邊開始顯示(布局里這屬性有些用幌缝,這里貌似基本上沒啥用)
locale 此屬性很少設(shè)置,用于選擇區(qū)域特定字形的語言環(huán)境(基本上沒啥用)
semanticsLabel 圖像的語義描述诫欠,用于向Andoid上的TalkBack和iOS上的VoiceOver提供圖像描述(可忽略涵卵,暫時(shí)沒啥用)

[站外圖片上傳中...(image-6886f2-1562061232581)]

TextStyle

TextStyle可以設(shè)置文字的屬性浴栽,其中比較簡單的包括Color(文本顏色)、fontSize(文字大小)轿偎,如果不設(shè)置典鸡,文本將使用最接近的DefaultTextStyle的樣式。如果給定樣式的TextStyle.inherit屬性為true(默認(rèn)值)坏晦,則給定樣式將與最接近的DefaultTextStyle合并萝玷。以下是屬性:

屬性 作用
color 文本顏色。與foreground互斥
decoration 繪制文本裝飾(下劃線昆婿、上劃線球碉、刪除線)
decorationColor Decoration的顏色,和decoration配合使用仓蛆,單獨(dú)使用沒效果
decorationStyle 繪制文本裝飾的樣式
fontWeight 繪制文本時(shí)使用的字體粗細(xì)(默認(rèn)w400)睁冬,文字加粗效果用這個(gè)
fontStyle 字體變體(斜體、正常)
fontFamily 設(shè)置字體看疙,外面導(dǎo)入的稀奇古怪的字體
fontSize 字體大小
letterSpacing 水平字母之間的空間間隔
wordSpacing 水平單詞之間的空間間隔
height 文本行與行的高度(非控件高度痴突,注意了)
locale 區(qū)域特定字形
background 文本背景色
foreground 文本的前景色,和color互斥狼荞,需要返回paint(畫筆)

這里做了一個(gè)簡單的實(shí)現(xiàn)

Widget _ZongheText() {
    return Text(
      "一片喧嘩叫嚷之中,忽聽得山下一個(gè)雄壯的聲音說道:誰說星宿派武功勝得了丐幫的降龍十八掌帮碰?這聲音也不如此響亮相味,但清清楚楚的傳入了從人耳中,眾人一愕之間殉挽,都住了口丰涉。hello world hheh aaaayy",
      style: TextStyle(
          inherit: false,
          color: Colors.pinkAccent,
          fontWeight: FontWeight.w600,
          fontSize: 16,
          letterSpacing: 2.0,
          wordSpacing: 5.0,
          //只適用于英文
          fontStyle: FontStyle.italic,
          textBaseline: TextBaseline.alphabetic,
          height: 3,
          decorationStyle: TextDecorationStyle.dashed,
          decoration: TextDecoration.underline,
          fontFamily: "systemmessage"),
    );
  } 

效果如下:

[站外圖片上傳中...(image-1dc262-1562061232581)]

RichText

如果需要對一段文本的不同段落采用不同的文字樣式,可以使用該控件斯碌。具體使用方法如下:

//RichText構(gòu)造實(shí)例
new RichText(......)
Text.rich(......)

//測試demo
  Widget _RichTestWidget(BuildContext context) {
    return Container(
        margin: EdgeInsets.fromLTRB(0, 10, 5, 0),
        padding: EdgeInsets.fromLTRB(0, 5, 0, 5),
        child: Text.rich(TextSpan(
            text: "flutter中RichText用于處理一段文字可能有不同的風(fēng)格一死,如:",
            children: <TextSpan>[
              TextSpan(text: "紅色,", style: TextStyle(color: Colors.red)),
              TextSpan(text: "黃色傻唾,", style: TextStyle(color: Colors.yellow)),
              TextSpan(text: "藍(lán)色投慈,", style: TextStyle(color: Colors.blue)),
              TextSpan(
                  text: "點(diǎn)我試試",
                  recognizer: TapGestureRecognizer()
                    ..onTap = () {
                      var snackBar = SnackBar(
                        content: Text("hello world"),
                        duration: Duration(seconds: 3), // 持續(xù)時(shí)間
                      );
                      _scaffoldkey.currentState.showSnackBar(snackBar);
                    }),
            ],
            style: TextStyle(color: Color(0xff000000)))));
  }

效果如下:

[站外圖片上傳中...(image-9b1769-1562061232581)]

PS

  1. Text沒有寬度、高度以及padding設(shè)置冠骄,如果需要設(shè)置這些屬性伪煤,則需要在外面包裹一層Container,設(shè)置Container的這些屬性
  2. 不同于Android的TextView凛辣,Text沒有點(diǎn)擊觸發(fā)監(jiān)聽抱既,如果需要可點(diǎn)擊,則需要設(shè)置手勢(感覺比較麻煩扁誓,不推薦)或者使用FlatButton(相當(dāng)于一個(gè)可點(diǎn)擊的Text)
  3. color和foreground只能存在一個(gè)防泵,否則報(bào)錯(cuò)
  4. RichText中如果內(nèi)部的TextSpan設(shè)置了TextStyle蚀之,則外部的TextStyle無效。

按鈕

在 Flutter 里有很多的 Button捷泞,包括了:MaterialButton足删、RaisedButton、FloatingActionButton肚邢、FlatButton壹堰、IconButton、ButtonBar骡湖、DropdownButton 等贱纠。
一般常用的 Button 是 MaterialButton、IconButton响蕴、FloatingActionButton谆焊。

一般按鈕(MaterialButton、RaisedButton浦夷、OutlineButton辖试、FlatButton)

RaisedButton、OutlineButton劈狐、FlatButton都是一般的按鈕罐孝,這三個(gè)按鈕均是繼承于MaterialButton,它們的區(qū)別在于:

  1. RaisedButton:一般的按鈕肥缔,類似android的button莲兢,有凸起
  2. FlatButton:扁平式按鈕,相當(dāng)于有點(diǎn)擊事件的text
  3. OutlineButton:帶邊框的背景透明的按鈕

構(gòu)造方法如下:

//構(gòu)造MaterialButton续膳,參數(shù)里面如果沒有onPressed改艇,會(huì)報(bào)警告,不影響編譯坟岔,默認(rèn)為button被禁用谒兄,
//這里onPressed回調(diào)里面,()表示回調(diào)參數(shù)社付,這里沒有表示未傳參承疲,{}里面編寫回調(diào)后的操作代碼
MaterialButton( onPressed: () {}) 

由于這三個(gè)button均是繼承于MaterialButton,MaterialButton具有的屬性這三個(gè)button也都具有鸥咖,只是MaterialButton的部分屬性它們不具有纪隙,這里MaterialButton的具體屬性如下,常用屬性加粗顯示:

屬性 作用
onPressed 點(diǎn)擊按鈕的回調(diào)扛或,設(shè)置為null的話绵咱,點(diǎn)擊效果失效
textColor 文字顏色
disabledTextColor 按鈕被禁用時(shí)的文字顏色
color 按鈕的背景色 均有
disabledColor 按鈕禁用時(shí)的背景顏色
disabledTextColor 按鈕禁用時(shí)的文字顏色
splashColor 點(diǎn)擊按鈕時(shí)水波紋的顏色
shape 設(shè)置按鈕的形狀
padding 內(nèi)邊距
elevation 陰影高度
highlightElevation 按鈕高亮(按下)時(shí)的陰影高度
disabledElevation 按鈕禁用時(shí)的陰影高度
minWidth 最小寬度
height 按鈕高度

左邊FlatButton,右邊MaterialButton
[站外圖片上傳中...(image-49792b-1562061232581)]

    return Row(children: <Widget>[
      Container(
          height: 24,
          child: FlatButton(
            padding: EdgeInsets.fromLTRB(5, 0, 5, 0),
            child: Text(
              this.text,
              style: TextStyle(color: _color(), fontSize: 12),
            ),
            onPressed: () {
              setState(() {
                if (this.choose) {
                  this.choose = false;
                } else {
                  this.choose = true;
                }
              });
            },
            shape: _shapeBorder(),
          )),
      MaterialButton(
        padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
        minWidth: 0,
        height: 24,
        child: Text(
          this.text,
          style: TextStyle(color: _color(), fontSize: 12),
        ),
        onPressed: () {
          setState(() {
            if (this.choose) {
              this.choose = false;
            } else {
              this.choose = true;
            }
          });
        },
        shape: _shapeBorder(),
      ),
    ]); 

shape

這個(gè)屬性需要多注意下,用來設(shè)定button的邊框形狀悲伶。常用的有以下幾個(gè):

  1. BeveledRectangleBorder 帶斜角的長方形邊框
  2. CircleBorder 圓形邊框
  3. RoundedRectangleBorder 圓角矩形
  4. StadiumBorder 兩端是半圓的邊框

圖標(biāo)按鈕(IconButton)

這個(gè)比較簡單艾恼,一個(gè)可交互的圖形圖標(biāo)。屬性頁沒啥難以理解的麸锉,邊框是個(gè)透明圓形钠绍,類似Android的ImageButton。直接上代碼:

   Widget _IconButton() {
    return IconButton(
      onPressed: () {},
      icon: Image.asset("assets/images/food01.jpeg"),
//      icon: Icon(Icons.forward),
      iconSize: 24,

    );
  }

懸浮按鈕(FloatingActionButton)

FloatingActionButton花沉,在Material Design中柳爽,一般用來處理界面中最常用,最基礎(chǔ)的用戶動(dòng)作碱屁。它一般出現(xiàn)在屏幕內(nèi)容的前面磷脯,通常是一個(gè)圓形,中間有一個(gè)圖標(biāo)娩脾。 FAB有三種類型:regular, mini, and extended赵誓。不要強(qiáng)行使用FAB,只有當(dāng)使用場景符合FAB功能的時(shí)候使用才最為恰當(dāng)柿赊。需要注意的屬性如下:

屬性 作用
heroTag hero效果使用的tag,系統(tǒng)默認(rèn)會(huì)給所有FAB使用同一個(gè)tag,方便做動(dòng)畫效果俩功,使得界面切換不再那么生硬
mini 是否為“mini”類型,默認(rèn)為false碰声,設(shè)置為true诡蜓,要小一號(hào),正常size = 56dp 胰挑,mini為size = 40dp
isExtended 是否為”extended”類型
tooltip FAB的文字解釋蔓罚,F(xiàn)AB被長按時(shí)顯示在按鈕上方(沒啥用,可以不管)

floatingActionButtonLocation

這是Scaffold Widget的一個(gè)屬性洽腺,和FloatingActionButton配合使用「埠担可以設(shè)置FloatingActionButton的位置蘸朋。具體效果如下圖:
[站外圖片上傳中...(image-38ec77-1562061232581)]
使用FloatActionButtonLocation中的centerDocked屬性和BottomNavigationBar配合可以實(shí)現(xiàn)下面的設(shè)計(jì),這個(gè)設(shè)計(jì)在喵嘰和王者榮耀里面出現(xiàn)過扣唱,具體效果如下:

[站外圖片上傳中...(image-7c7736-1562061232581)]

class TestPage extends StatefulWidget {
  @override
  _TestSate createState() {
    // TODO: implement createState
    return _TestSate();
  }
}

class _TestSate extends State<TestPage> {
  int _tabIndex = 0;

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(title: new Text("ZXZ-IMAGE")),
      floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
      floatingActionButton: FloatingActionButton(backgroundColor: Colors.lightBlueAccent,child : Text("+",style: TextStyle(fontSize: 24),),onPressed: (){}),
      body: _PageList()[_tabIndex],
      bottomNavigationBar:  BottomNavigationBar(
          items: _list(),
          currentIndex: _tabIndex,
          onTap: (index) {
            setState(() {
              _tabIndex = index;
            });
          }),
    );
  }

  List<BottomNavigationBarItem> _list() {
    List<BottomNavigationBarItem> list = [];
    list.add(BottomNavigationBarItem(
        icon: Image.asset("assets/images/house.png"),
        title: Text("Construct")));
    list.add(BottomNavigationBarItem(
        icon: Image.asset("assets/images/plane.png"),
        title: Text("Attribute")));
    return list;
  }

  List<Widget> _PageList() {
    List<Widget> result = [];
    result.add(ImageConstructPage());
    result.add(ImageAttributePage());
    return result;
  }
} 

下拉按鈕(DropdownButton)

Material Style下拉菜單按鈕藕坯,使用方法如下:

class _DropdownState extends State<_DropdownWidget>{

  CityItem _item;
  List<DropdownMenuItem<CityItem>> _list;

  @override
  void initState() {
    _list = [];
    _list.add(new DropdownMenuItem<CityItem>(child: Text("上海"),value: CityItem("上海", 0)));
   _list.add(DropdownMenuItem<CityItem>(child: Text("北京",style: TextStyle(color: Colors.red),),value: CityItem("北京", 1)));
  }
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return DropdownButton(onChanged: (value) {
      setState(() {
        _item = value;
      });
    },items: _list,
    value: _item,
    hint: Text("請選擇城市"),);
  }
 

由于我們在點(diǎn)擊每一個(gè)條目后,展示的選中條目會(huì)變化噪沙,所以DropdownButton應(yīng)當(dāng)繼承StatefulWidget炼彪,在選中條目后也就是onChange的回調(diào)中使用setState((){})更新對象的狀態(tài)。另外正歼,這里的列表數(shù)據(jù)必須是List<DropdownMenuItem<T>>辐马。DropdownMenuItem<T>里面包含一個(gè)child和value,綁定了view和data局义,這里每個(gè)item都可以設(shè)置一個(gè)child喜爷,意味著下拉菜單的每個(gè)item可以有不同的view冗疮。這里需要注意的是下面兩個(gè)屬性,其他的屬性比較簡單或者已經(jīng)再其他button說明過檩帐,就不再說明术幔。

屬性 作用
onChanged 菜單選中回調(diào)
items 要顯示的列表

上面代碼的結(jié)果如下:

[站外圖片上傳中...(image-75c22c-1562061232581)]

ButtonBar

可以水平擺放一堆button的控件,但我試了下湃密,也可以擺text诅挑,不可滑動(dòng),超過屏幕寬度報(bào)錯(cuò)泛源,感覺這更像一個(gè)水平布局拔妥,不明白為啥官方歸納到基礎(chǔ)組件里面。使用簡單俩由,在此不舉例了毒嫡。

PS

  1. RaisedButton、FlatButton以及OutlineButton的minWidth=88dp幻梯,minHeight=36dp兜畸,且無法設(shè)置,只有通過Container包裹設(shè)置其寬度碘梢,如果需要設(shè)置其寬度自適應(yīng)咬摇,可以使用MaterialButton,設(shè)置minWidth = 0煞躬。
  2. 如果要設(shè)置button的高度肛鹏,可以使用Container包裹button,或者使用MaterialButton(這玩意兒有屬性height)恩沛。
  3. 如果設(shè)置MaterialButton的onPressed為null在扰,則此時(shí)button為空白。
  4. DropdownButton下拉菜單選中的值(注意:在初始化時(shí)雷客,要么為null芒珠,這時(shí)顯示默認(rèn)hint的值;如果自己設(shè)定值搅裙,則值必須為列表中的一個(gè)值皱卓,如果不在列表中,會(huì)拋出異常)
  5. IconButton需要被包裹在Scaffold widget中部逮,否則會(huì)報(bào)錯(cuò) textfield widgets require a material widget ancestor
  6. 如果需要去掉點(diǎn)擊效果且不禁用該控件娜汁,可以把splashColor和hightlightColor同時(shí)設(shè)置為transparent
  7. OutlineButton是一個(gè)有默認(rèn)邊線且背景透明的按鈕,也就是說我們設(shè)置其邊線和顏色是無效的兄朋,其他屬性跟MaterialButton中屬性基本一致

圖片

Image, 圖片顯示W(wǎng)idget, 和Android ImageView相似诀黍,但是從實(shí)際使用的方法上看放棒,與常用的圖片加載庫等脂,如Picasso壕吹,Glide等相似,支持本地圖片,資源圖片,網(wǎng)絡(luò)圖片等加載方式。

  1. Image:通過ImageProvider來加載圖片
  2. Image.asset:用來加載本地資源圖片
  3. Image.file:用來加載本地(File文件)圖片
  4. Image.network:用來加載網(wǎng)絡(luò)圖片
  5. Image.memory:用來加載Uint8List資源(byte數(shù)組)圖片

屬性

屬性 作用
width & height 容器寬度高度
fit 圖片填充方式
color & colorBlendMode 感覺類似Android Paint Xfermode
repeat 復(fù)制方式灼芭,桌面的圖片平鋪 (橫向、縱向般又、橫向縱向)
centerSlice 當(dāng)圖片需要被拉伸顯示的時(shí)候彼绷,centerSlice定義的矩形區(qū)域會(huì)被拉伸(感覺沒啥用)
matchTextDirection 與Directionality配合使用,圖片展示方向(鏡像)

fit

屬性 作用
BoxFit.contain 全圖顯示茴迁,顯示原比例寄悯,不需充滿
BoxFit.fill 全圖顯示,顯示可能拉伸堕义,填滿
BoxFit.cover 顯示可能拉伸猜旬,可能裁剪,充滿
BoxFit.fitWidth 顯示可能拉伸倦卖,可能裁剪洒擦,寬度充滿
BoxFit.fitHeight 顯示可能拉伸,可能裁剪怕膛,高度充滿

看圖紙觀點(diǎn):

[站外圖片上傳中...(image-f400a9-1562061232581)]

在平時(shí)的開發(fā)中熟嫩,基本上都是用上面兩個(gè),其他基本上用不到褐捻。

圓角圖片

  1. 使用ClipOval掸茅,這里注意如果原圖不是正方形,使用這個(gè)會(huì)成一個(gè)橢圓柠逞。
  Widget _AssetImageRec() {
    return Image.asset(
      "assets/images/food01.jpeg",
      width: 200,
      height: 200,
      fit: BoxFit.fill,
    );
  }
  
  Widget _CircleAvatar() {
    return new ClipOval(child: _AssetImageRec());
  } 
  1. 可以用Container包裹一個(gè)Image昧狮,然后設(shè)置Container的decoration
  2. 使用_ClipRRect,通過設(shè)置BorderRadius來實(shí)現(xiàn)板壮。
  Widget _ClipRRect() {
    return ClipRRect(
      child: _AssetImage(),
      borderRadius: BorderRadius.all(Radius.circular(60)),
    );
  } 

網(wǎng)絡(luò)緩存圖片(占位圖片)

  1. 使用FadeInImage.assetNetwork(flutter自帶)

Widget _FadeInImage() {
    return FadeInImage.assetNetwork(
      placeholder: "assets/images/food01.jpeg",//占位圖
      image://網(wǎng)絡(luò)圖片
          "https://rpic.douyucdn.cn/live-cover/roomCover/cover_update/2019/05/29/43cf32dcde0b77c765681c6f0a9af6fb.jpg",
      width: 200,
      height: 200,
      fit: BoxFit.fill,
      fadeInDuration: Duration(milliseconds: 400),
      fadeOutDuration: Duration(milliseconds: 400),
    );
  } 
  1. 使用第三方庫:(cached_network_image:https://pub.dartlang.org/packages/cached_network_image

列表item實(shí)現(xiàn)

下圖是斗魚極速版中首頁的item逗鸣,基本上可以通過text和image來實(shí)現(xiàn),這里會(huì)用到Stack來實(shí)現(xiàn)控件的覆蓋个束,Column實(shí)現(xiàn)豎直線性布局慕购,Row實(shí)現(xiàn)水平線性布局聊疲,這里不多做介紹茬底,具體代碼貼上:

[站外圖片上傳中...(image-5658f9-1562061232581)]

Widget _RoomItem(RoomItem item, double screenWidth) {
    return FlatButton(
      child: Column(children: <Widget>[
        _ImageItem(item, screenWidth),
        Container(
          child: Text(item.roomName,
              textAlign: TextAlign.left,
              softWrap: false,
              overflow: TextOverflow.ellipsis),
          margin: EdgeInsets.fromLTRB(0, 5, 0, 0),
        )
      ], crossAxisAlignment: CrossAxisAlignment.start),
      padding: EdgeInsets.zero,
      onPressed: () {},
    );
  }

  Widget _ImageItem(RoomItem item, double screenWidth) {
    double itemWidth = (screenWidth - 5) / 2;
    return Stack(children: <Widget>[
      Image.network(
        item.coverUrl,
        width: itemWidth,
        height: itemWidth * 3 / 5,
        fit: BoxFit.fill,
      ),
      Container(
        width: itemWidth,
        height: itemWidth * 3 / 5,
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            _CornerWidget(),
            Expanded(
              child: Container(),
            ),
            Container(
                height: 29,
                width: itemWidth,
                alignment: AlignmentDirectional.bottomStart,
                decoration: BoxDecoration(
                    gradient: LinearGradient(
                        colors: [Colors.transparent, Color(0x7b000000)],
                        begin: Alignment.topCenter,
                        end: Alignment.bottomCenter)),
                child: Row(children: <Widget>[
                  Container(
                      padding: EdgeInsets.fromLTRB(4, 0, 0, 6),
                      width: 100,
                      child: Text(item.authorName,
                          style: TextStyle(color: Colors.white, fontSize: 11),
                          softWrap: false,
                          overflow: TextOverflow.ellipsis)),
                  Expanded(
                    child: Container(
                        padding: EdgeInsets.fromLTRB(0, 0, 6, 6),
                        child: Row(
                            textDirection: TextDirection.rtl,
                            children: <Widget>[
                              Text(item.hot,
                                  style: TextStyle(
                                      color: Colors.white, fontSize: 11),
                                  textAlign: TextAlign.right),
                              Container(
                                child: Image.asset(
                                    "assets/images/icon_room_hot.webp",
                                    fit: BoxFit.contain,
                                    width: 9,
                                    height: 9),
                                margin: EdgeInsets.fromLTRB(0, 0, 4, 0),
                              )
                            ])),
                  )
                ]))
          ],
        ),
      ),
    ]);
  } 

單選框、復(fù)選框

Material widgets庫中提供了Material風(fēng)格的單選開關(guān)Switch和復(fù)選框Checkbox获洲,它們都是繼承自StatelessWidget阱表,所以它們本身不會(huì)保存當(dāng)前選擇狀態(tài),所以一般都是在父widget中管理選中狀態(tài)。當(dāng)用戶點(diǎn)擊Switch或Checkbox時(shí)最爬,它們會(huì)觸發(fā)onChanged回調(diào)涉馁,我們可以在此回調(diào)中處理選中狀態(tài)改變邏輯。

公共屬性

屬性 作用
value 當(dāng)前控件的值
activeColor 選中時(shí)控件顏色
onChanged 狀態(tài)發(fā)生變化時(shí)回調(diào)爱致,(bool value) {}

Switch(ios的那種滑動(dòng)的單項(xiàng)選擇器)

屬性 作用
inactiveTrackColor 未選中時(shí)橫條顏色
inactiveThumbColor 未選中時(shí)滑塊顏色
inactiveThumbImage 未選中時(shí)滑塊上的圖片
activeThumbImage 選中時(shí)滑塊上的圖片
activeTrackColor 選中時(shí)橫條顏色

Checkbox(類似于android的checkbox)

屬性 作用
checkColor 選中后里面那個(gè)勾的顏色
tristate 會(huì)添加一個(gè)狀態(tài)(true-null-false)烤送,在null時(shí)會(huì)有顯示一個(gè)橫條
inactiveTrackColor 選中時(shí)橫條顏色

Radio(類似于android的RadioButton)

屬性 作用
groupValue 和value一起控制是否為選中狀態(tài),當(dāng)groupValue = value時(shí)代表選中狀態(tài)
tristate 會(huì)添加一個(gè)狀態(tài)(true-null-false)糠悯,在null時(shí)會(huì)有顯示一個(gè)橫條
inactiveTrackColor 選中時(shí)橫條顏色

直接代碼:

 class TestPage extends StatefulWidget {
  @override
  _TestState createState() {
    // TODO: implement createState
    return _TestState();
  }
}

class _TestState extends State<TestPage> {
  bool _isSwitchChoosed = false;
  bool _isCheckboxChoosed = false;
  String _radioChoosed = null;

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(
        title: Text("ZXZ-CHOOSE"),
      ),
      body: Column(
        mainAxisAlignment: MainAxisAlignment.start,
        children: <Widget>[_SwitchWidget(), _CheckBox(), _Radio()],
      ),
    );
  }

  Widget _SwitchWidget() {
    return Switch(
        onChanged: (bool value) {
          setState(() {
            _isSwitchChoosed = value;
          });
        },
        value: _isSwitchChoosed,
        activeColor: Color(0xFFFF6633),
        inactiveThumbColor: Colors.white);
  }

  Widget _CheckBox() {
    return Checkbox(
      onChanged: (bool value) {
        setState(() {
          _isCheckboxChoosed = value;
        });
      },
      value: _isCheckboxChoosed,
      activeColor: Color(0xFFFF6633),
      tristate: true,
    );
  }

  Widget _Radio() {
    return Row(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        Radio<String>(
            value: "北京",
            groupValue: _radioChoosed,
            onChanged: (String s) {
              setState(() {
                this._radioChoosed = s;
              });
            },
        activeColor: Color(0xFFFF6633),),
        Radio<String>(
            value: "上海",
            groupValue: _radioChoosed,
            onChanged: (String s) {
              setState(() {
                this._radioChoosed = s;
              });
            }),
        Expanded(child: RadioListTile<String>(
            value: "廣州",
            title: new Text("廣州"),
            groupValue: _radioChoosed,
            onChanged: (String s) {
              setState(() {
                this._radioChoosed = s;
              });
            }),)
        ,
        Radio<String>(
            value: "深圳",
            groupValue: _radioChoosed,
            onChanged: (String s) {
              setState(() {
                this._radioChoosed = s;
              });
            })
      ],
    );
  }
}

效果如下:

[站外圖片上傳中...(image-e0ca8e-1562061232581)]

PS

  1. 還有個(gè)CheckboxListTile和RadioListTile帮坚,可以關(guān)注下。

進(jìn)度條

LinearProgressIndicator & CircularProgressIndicator

Flutter使用LinearProgressIndicator表示條形進(jìn)度條互艾,CircularProgressIndicator表示圓形進(jìn)度條试和,由于兩個(gè)控件的屬性基本相同,下面是幾個(gè)比較重要的屬性:

屬性 作用
value 當(dāng)前進(jìn)度纫普,如果 value 為 null 或空阅悍,進(jìn)度條會(huì)是一個(gè)動(dòng)畫,很像一個(gè)loading動(dòng)畫昨稼,值只能設(shè)置 0 ~ 1.0节视,如果大于 1,則表示已經(jīng)結(jié)束悦昵,顯示背景顏色肴茄。
valueColor 進(jìn)度條的顏色,是個(gè)顏色漸變的動(dòng)畫

slider(滑塊)

滑塊組件但指,可用于數(shù)量的選擇寡痰,一般可用于調(diào)節(jié)變量,像音量啥的棋凳,以下是它的屬性:

屬性 說明
value 控件的位置拦坠,只能在min和max之間,否則報(bào)錯(cuò)
onChanged 變化時(shí)回調(diào)
onChangeStart 滑動(dòng)開始時(shí)回調(diào)一次
onChangeEnd 滑動(dòng)結(jié)束時(shí)回調(diào)一次
min 最小值剩岳,不設(shè)置默認(rèn)為0
max 最大值贞滨,不設(shè)置默認(rèn)為1
divisions 分為幾塊,比如設(shè)置為5拍棕,Slider只能滑動(dòng)到5個(gè)位置
label divisions設(shè)置顯示在節(jié)點(diǎn)上的label晓铆,配合divisions使用,不設(shè)置divisions則無效
activeColor 滑動(dòng)過的區(qū)域的顏色
inactiveColor 未 滑動(dòng)過的區(qū)域的顏色

直接代碼:

  Widget _getCircularProgressIndicator() {
    return Container(
      margin: EdgeInsets.fromLTRB(0, 10, 0, 10),
      child: CircularProgressIndicator(
        value: null,
        backgroundColor: Colors.grey,
        strokeWidth: 2,
      ),
    );
  } 
class _SliderTest extends StatefulWidget {
  @override
  _SliderState createState() {
    return _SliderState();
  }
}

class _SliderState extends State<_SliderTest> {
  double _value = 0;
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Container(
      child: Slider(
          value: _value,
          onChanged: (double val) {
            setState(() {
              this._value = val;
            });
          },
      divisions: 5,
      label: "1",),
    );
  }
}

這里截圖如下:

[站外圖片上傳中...(image-94d658-1562061232581)]

PS

  1. LinearProgressIndicator绰播、CircularProgressIndicator骄噪、slider都具有狀態(tài)的變化,一般都應(yīng)放在StatefulWidget中
  2. LinearProgressIndicator蠢箩、CircularProgressIndicator的value如果設(shè)置為null链蕊,會(huì)形成一個(gè)永不停止的動(dòng)畫事甜,很有l(wèi)oading動(dòng)畫的風(fēng)格,簡單的loading可以用這個(gè)一試滔韵。

輸入框

Flutter中的文本輸入框(TextField)就類似于Android中的EditText逻谦,但是用起來比EditText方便很多,改變樣式也更加的方便陪蜻。

屬性

下面看下TextField中特有的屬性(之前其他控件已列過的屬性不再列)

屬性 作用
controller 編輯框的控制器邦马,如果不創(chuàng)建的話默認(rèn)會(huì)自動(dòng)創(chuàng)建,用于和文本交互宴卖,例如清除文本
focusNode 用于管理焦點(diǎn)
decoration 輸入框的裝飾器勇婴,用來修改外觀,返回InputDecoration
keyboardType 設(shè)置輸入類型嘱腥,不同的輸入類型鍵盤不一樣
textInputAction 用于控制鍵盤動(dòng)作(一般位于右下角耕渴,默認(rèn)是完成)
autofocus 是否自動(dòng)獲取焦點(diǎn)
obscureText 是否隱藏輸入的文字,一般用在密碼輸入框中
autocorrect 是否自動(dòng)校驗(yàn)
maxLength 能輸入的最大字符個(gè)數(shù)齿兔,設(shè)置這個(gè)了右下角會(huì)冒出個(gè)計(jì)數(shù)器角標(biāo)橱脸,且沒法隱藏這個(gè)角標(biāo),略雞肋
maxLengthEnforced 配合maxLength一起使用分苇,在達(dá)到最大長度時(shí)是否阻止輸入添诉,默認(rèn)為true
onEditingComplete 點(diǎn)擊鍵盤完成按鈕時(shí)觸發(fā)的回調(diào),該回調(diào)沒有參數(shù)医寿,(){}
onSubmitted 同樣是點(diǎn)擊鍵盤完成按鈕時(shí)觸發(fā)的回調(diào)栏赴,該回調(diào)有參數(shù),參數(shù)即為當(dāng)前輸入框中的值靖秩。(String){}
inputFormatters 對輸入文本的校驗(yàn)
cursorWidth 光標(biāo)的寬度
cursorRadius 光標(biāo)的圓角
cursorColor 光標(biāo)的顏色
onTap 點(diǎn)擊輸入框時(shí)的回調(diào)(){}

TextEditingController

TextEditingController作為TextField的controller屬性须眷。 在用戶輸入時(shí),controller的text和selection屬性不斷的更新沟突。要在這些屬性更改時(shí)得到通知花颗,請使用controller的addListener方法監(jiān)聽控制器 。 (如果你添加了一個(gè)監(jiān)聽器惠拭,需要在State對象的dispose方法中刪除監(jiān)聽器)扩劝。該TextEditingController還可以讓您控制TextField的內(nèi)容。最常見的是TextEditingController.text用來獲取當(dāng)前輸入框的內(nèi)容职辅,TextEditingController.clear清空輸入框的內(nèi)容棒呛。

InputDecoration

InputDecoration主要用于控制TextField的外觀以及提示信息等。主要可以設(shè)置前綴樣式域携、后綴樣式等簇秒,屬性很多,這里借用下網(wǎng)上的勞動(dòng)成果涵亏,具體如下:

[站外圖片上傳中...(image-234926-1562061232581)]

斗魚頂部搜索框

斗魚頂部的搜索框前部和后面均有一個(gè)圖標(biāo)宰睡,這里一開始想用InputDecoration.prefix和InputDecoration.suffix來實(shí)現(xiàn),但是和輸入框沒法對齊气筋,因此這里就沒用這倆屬性拆内。

class _TextField extends State<_TextFieldWidget> {
  bool _hasInput = false;
  TextEditingController controller;

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    controller = TextEditingController();
  }

  @override
  Widget build(BuildContext context) {
    double statusBarHeight = MediaQuery.of(context).padding.top;
    // TODO: implement build
    return Container(
        width: MediaQuery.of(context).size.width,
        padding: EdgeInsets.fromLTRB(16, statusBarHeight, 0, 0),
        child: Row(children: <Widget>[
          Expanded(child: _search()),
          _cancelBtn(context)
        ]));
  }

  Widget _search() {
    return Container(
        color: Color(0xffF0F2F5),
        child: Row(mainAxisSize: MainAxisSize.min, children: <Widget>[
          Container(
              padding: EdgeInsets.all(10),
              child: Image.asset(
                "assets/images/icon_home_search.webp",
                width: 24,
                height: 24,
              )),
          Expanded(
            child: TextField(
              controller: controller,
              cursorColor: Color(0xffff7700),
              cursorWidth: 1.5,
              onChanged: (text) {
                //內(nèi)容改變的回調(diào)
                setState(() {
                  if (text.length > 0) {
                    _hasInput = true;
                  } else {
                    _hasInput = false;
                  }
                });
              },
              decoration: InputDecoration(
                counter: null,
                  contentPadding: EdgeInsets.fromLTRB(0, 10, 0, 10),
                  fillColor: Color(0xffF0F2F5),
                  filled: true,
                  hintText: "搜索房間/主播/分類",
                  hintStyle: TextStyle(fontSize: 14, color: Color(0xffbbbbbb)),
                  border: OutlineInputBorder(
                      borderSide: BorderSide(color: Color(0xffF0F2F5)),
                      borderRadius: BorderRadius.all(Radius.circular(2))),
                  focusedBorder: OutlineInputBorder(
                      borderSide: BorderSide(color: Color(0xffF0F2F5)),
                      borderRadius: BorderRadius.all(Radius.circular(2))),
                  enabledBorder: OutlineInputBorder(
                      borderSide: BorderSide(color: Color(0xffF0F2F5)),
                      borderRadius: BorderRadius.all(Radius.circular(2)))),
              style: TextStyle(
                fontSize: 14,
                color: Color(0xff333333),
              ),
            ),
          ),
          Container(
              padding: EdgeInsets.fromLTRB(0, 0, 12, 0),
              child: IconButton(
                  splashColor: Colors.transparent,
                  highlightColor: Colors.transparent,
                  icon: Image.asset(
                    _hasInput ? "assets/images/icon_search_clear.webp" : "",
                    width: 16,
                    height: 16,
                  ),
                  onPressed: () {
                    setState(() {
                      controller.clear();
                    });
                  })),
        ]));
  }

  Widget _cancelBtn(BuildContext context) {
    return MaterialButton(
        minWidth: 0,
        padding: EdgeInsets.all(0),
        onPressed: () {
          showDialog(
              context: context,
              builder: (_) => new LoginDialog(),
              barrierDismissible: false);
        },
        child: Text("取消",
            style: TextStyle(
                color: Color(0x54000000),
                fontSize: 14,
                fontWeight: FontWeight.bold)),
        elevation: null);
  }
} 

[站外圖片上傳中...(image-ca4c74-1562061232581)]

PS

  1. Row無法包裹TextField,需要在TextField外再包裹一層Expanded方可
  2. TextField需要被包裹在Scaffold widget中宠默,否則會(huì)報(bào)錯(cuò) textfield widgets require a material widget ancestor麸恍,后來發(fā)現(xiàn)用Material包裹也行
  3. TextField的prefixIcon和prefix不好用,prefixIcon限制了類型搀矫,prefix的對齊效果賊差抹沪,建議還是用Row包裹Image+TextField實(shí)現(xiàn)圖標(biāo)后面緊跟輸入框的視圖。
  4. TextField的最大限制輸入maxLength設(shè)置之后導(dǎo)致右下角會(huì)冒出個(gè)計(jì)數(shù)器角標(biāo)瓤球,而且消不掉融欧,這就尷尬了,感覺只能在onChanged里面處理了卦羡。

對話框

SimpleDialog & AlertDialog & AboutDialog

  1. SimpleDialog噪馏,一般可以利用多個(gè)SimpleDialogOption為用戶提供了幾個(gè)選項(xiàng)。
  2. AlertDialog绿饵,警告對話框欠肾。警告對話框有一個(gè)可選標(biāo)題title和一個(gè)可選列表的actions選項(xiàng)。
  3. AboutDialog拟赊,關(guān)于對話框刺桃。提供一個(gè)app信息的對話框

展示 & 隱藏

  1. 對話框本質(zhì)上是屬于一個(gè)路由的頁面route,由Navigator進(jìn)行管理吸祟,所以控制對話框的顯示和隱藏瑟慈,也是調(diào)用Navigator.of(context)的push和pop方法。
  2. 在Flutter中屋匕,提供了showDialog()封豪、showGeneralDialog()、showCupertinoDialog()炒瘟,其中調(diào)用showDialog()方法展示的是material風(fēng)格的對話框吹埠,調(diào)用showCupertinoDialog()方法展示的是ios風(fēng)格的對話框。而這兩個(gè)方法其實(shí)都會(huì)去調(diào)用showGeneralDialog()方法疮装,可以從源碼中看到最后是利用Navigator.of(context, rootNavigator: true).push()一個(gè)頁面缘琅。這里我在android上使用showCupertinoDialog(),出現(xiàn)的漸變動(dòng)畫會(huì)有一點(diǎn)卡頓廓推,另外還有一個(gè)showAboutDialog()刷袍,打開的是一個(gè)關(guān)于的對話框。
 //打開關(guān)于對話框
 showAboutDialog(
        context: context,
        applicationIcon:
        Image.asset("assets/images/house.png"),
        applicationName: "flutter-douyu",
       applicationVersion: "1.0.0"); }) 
//打開一個(gè)對話框
void _showDialog(BuildContext context){
     showDialog(context: context, builder: (_) =>
        AlertDialog(title: Text("測試"), content: Text("測試測試測試測試測試"),
          actions: <Widget>[
            FlatButton(onPressed: () {
              Navigator.of(context).pop();//關(guān)閉對話框
            }, child: Text("確定")),
            FlatButton(onPressed: () {
              Navigator.of(context).pop();
            }, child: Text("取消")),
          ],));
  }

自定義對話框

自定義Dialog可以有兩種方式:

  1. 在Dialog提供了child參數(shù)供寫視圖界面
  2. 繼承Dialog類樊展,就需要重寫build函數(shù)呻纹。

斗魚的登錄界面就是個(gè)自定義對話框堆生,具體視圖如下圖所示:

[站外圖片上傳中...(image-bcd28a-1562061232581)]
代碼太長,不一一貼雷酪,主要代碼如下:

//第一種方式
 void _showDialog1(BuildContext context) {
    showDialog(
        context: context,
        builder: (_) => Dialog(
            backgroundColor: Colors.transparent,
            child: Container(
              width: 311,
              height: 500,
              child: Center(
                  child: Stack(
                children: <Widget>[
                  Container(
                    margin: EdgeInsets.fromLTRB(0, 80, 0, 0),
                    padding: EdgeInsets.all(0),
                    decoration: BoxDecoration(
                        borderRadius: BorderRadius.all(Radius.circular(2)),
                        color: Colors.white),
                    width: 311,
                    height: 420,
                    child: _CloseImg(context),
                  ),
                  _LogoImg(),
                  _MainWidget()
                ],
              )),
            )));
  }
  //第二種方式
class LoginDialog extends Dialog {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
        backgroundColor: Colors.transparent,
        body: Center(
            child: Stack(
          children: <Widget>[
            Container(
              margin: EdgeInsets.fromLTRB(0, 80, 0, 0),
              padding: EdgeInsets.all(0),
              decoration: BoxDecoration(
                  borderRadius: BorderRadius.all(Radius.circular(2)),
                  color: Colors.white),
              width: 311,
              height: 420,
              child:  _CloseImg(context),//
            ),//底部那個(gè)大白框
            _LogoImg(),//上面那個(gè)鯊魚娘
            _MainWidget()//最主要的操作面板
          ],
        )));
  }
}

PS

  1. 按照我們公司的UI以往的設(shè)計(jì)方案(坑爹尿性)來看淑仆,基本上用Flutter自帶的Dialog樣式固定,基本上沒啥用了哥力,還是自定義吧~~
  2. 繼承Dialog類蔗怠,重寫build函數(shù)時(shí)會(huì)發(fā)現(xiàn)里面所有的Text控件會(huì)默認(rèn)有個(gè)雙下劃波浪線,不知道為啥這么設(shè)置吩跋。寞射。。

總結(jié)

  1. 不同于android的控件锌钮,F(xiàn)lutter的控件很少能夠自己設(shè)置寬高桥温,基本上都需要被包裹在Container里面才行。
  2. 使用本地文件梁丘,除了導(dǎo)入文件之外策治,還需要在項(xiàng)目根目錄下的pubspec.yaml文件中的assets:目錄下添加該文件
  3. 實(shí)際寫布局的時(shí)候會(huì)發(fā)現(xiàn)層級很深,導(dǎo)致代碼里的child一個(gè)接一個(gè)兰吟,建議最好不要超過三層通惫,如果超過寫在新的方法體內(nèi),否則極難閱讀混蔼。
  4. 控件里的屬性并不是不設(shè)置就沒有履腋,例如button里面的splashColor不設(shè)置會(huì)使用默認(rèn)的,如果想不使用該屬性惭嚣,需要自己設(shè)置遵湖。
  5. 部分控件屬性極多,不需要完全搞明白晚吞,弄明白重要的就行
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末延旧,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子槽地,更是在濱河造成了極大的恐慌迁沫,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,723評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件捌蚊,死亡現(xiàn)場離奇詭異集畅,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)缅糟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評論 2 382
  • 文/潘曉璐 我一進(jìn)店門挺智,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人窗宦,你說我怎么就攤上這事赦颇《” “怎么了?”我有些...
    開封第一講書人閱讀 152,998評論 0 344
  • 文/不壞的土叔 我叫張陵媒怯,是天一觀的道長订讼。 經(jīng)常有香客問我,道長沪摄,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,323評論 1 279
  • 正文 為了忘掉前任纱烘,我火速辦了婚禮杨拐,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘擂啥。我一直安慰自己哄陶,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,355評論 5 374
  • 文/花漫 我一把揭開白布哺壶。 她就那樣靜靜地躺著屋吨,像睡著了一般。 火紅的嫁衣襯著肌膚如雪山宾。 梳的紋絲不亂的頭發(fā)上至扰,一...
    開封第一講書人閱讀 49,079評論 1 285
  • 那天,我揣著相機(jī)與錄音资锰,去河邊找鬼敢课。 笑死,一個(gè)胖子當(dāng)著我的面吹牛绷杜,可吹牛的內(nèi)容都是我干的直秆。 我是一名探鬼主播,決...
    沈念sama閱讀 38,389評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼鞭盟,長吁一口氣:“原來是場噩夢啊……” “哼圾结!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起齿诉,我...
    開封第一講書人閱讀 37,019評論 0 259
  • 序言:老撾萬榮一對情侶失蹤筝野,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后粤剧,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體遗座,經(jīng)...
    沈念sama閱讀 43,519評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,971評論 2 325
  • 正文 我和宋清朗相戀三年俊扳,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了途蒋。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,100評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡馋记,死狀恐怖号坡,靈堂內(nèi)的尸體忽然破棺而出懊烤,到底是詐尸還是另有隱情,我是刑警寧澤宽堆,帶...
    沈念sama閱讀 33,738評論 4 324
  • 正文 年R本政府宣布腌紧,位于F島的核電站,受9級特大地震影響畜隶,放射性物質(zhì)發(fā)生泄漏壁肋。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,293評論 3 307
  • 文/蒙蒙 一籽慢、第九天 我趴在偏房一處隱蔽的房頂上張望浸遗。 院中可真熱鬧,春花似錦箱亿、人聲如沸跛锌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽髓帽。三九已至,卻和暖如春脑豹,著一層夾襖步出監(jiān)牢的瞬間郑藏,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評論 1 262
  • 我被黑心中介騙來泰國打工瘩欺, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留译秦,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,547評論 2 354
  • 正文 我出身青樓击碗,卻偏偏與公主長得像筑悴,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子稍途,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,834評論 2 345

推薦閱讀更多精彩內(nèi)容