Flutter 基礎(chǔ)組件

版本信息:2.2.2 版本較老

一、基礎(chǔ)組件
1、文本

1)普通文本

 Text(
              '文本是視圖系統(tǒng)中的常見控件,用來(lái)顯示一段特定樣式的字符串,就比如Android里的TextView,或是iOS中的UILabel。',
              textAlign: TextAlign.center,

              style: TextStyle(
                  fontWeight: FontWeight.bold,
                  fontSize: 20,
                  color: Colors.red), //20號(hào)紅色粗體展示
            ),

2)富文本

 Text.rich(
              TextSpan(children: <TextSpan>[
                TextSpan(
                    text: '文本是視圖系統(tǒng)中常見的控件,它用來(lái)顯示一段特定樣式的字符串,類似',
                    style: redStyle), //第1個(gè)片段,紅色樣式
                TextSpan(text: 'Android', style: blackStyle), //第1個(gè)片段,黑色樣式
                TextSpan(text: '中的', style: redStyle), //第1個(gè)片段,紅色樣式
                TextSpan(text: 'TextView', style: blackStyle) //第1個(gè)片段,黑色樣式
              ]),
              textAlign: TextAlign.center,
            ),
2、圖片

1)本地圖片

 Image.asset(
              'assets/images/back_circle.png', // 圖片的本地地址
              width: 100,
              height: 100,
              fit: BoxFit.cover, // 圖片填充方式
            ),

2)網(wǎng)絡(luò)圖片

            Image.network(
              'https://upload.jianshu.io/users/upload_avatars/1694376/4b7e25bd43ee.jpg',
              width: 200,        // 設(shè)置圖片寬度
              height: 200,       // 設(shè)置圖片高度
              fit: BoxFit.cover, // 圖片填充方式
            ),
 FadeInImage(
              placeholder: AssetImage('assets/images/loading.gif'), // 占位圖(本地資源)
              image: NetworkImage('https://lf-flow-web-cdn.doubao.com/obj/flow-doubao/doubao/logo-doubao-overflow.png'), // 目標(biāo)網(wǎng)絡(luò)圖片
              width: 200,
              height: 200,
              fit: BoxFit.cover,
            ),
3、按鈕
  //按鈕
            FloatingActionButton(
              onPressed: () => print('FloatingActionButton pressed'),
              child: Text('Btn'),
            ),
            FlatButton(
              onPressed: () => print('FlatButton pressed'),
              child: Text('Btn'),
            ),
            RaisedButton(
              onPressed: () => print('RaisedButton pressed'),
              child: Text('Btn'),
            ),
            FlatButton(
                color: Colors.yellow, //設(shè)置背景色為黃色
                shape: BeveledRectangleBorder(
                    borderRadius: BorderRadius.circular(20.0)), //設(shè)置斜角矩形邊框
                colorBrightness: Brightness.light, //確保文字按鈕為深色
                onPressed: () => print('FlatButton pressed'),
                height: 40,
                minWidth: 50,
                child: Row(
                  children: <Widget>[Icon(Icons.add), Text("Add")],
                )),
二、列表

在 Android 中是由 ListView 或 RecyclerView 實(shí)現(xiàn)的,在 iOS 中是用 UITableView 實(shí)現(xiàn)的;而在 Flutter 中,實(shí)現(xiàn)這種需求的則是列表控件 ListView。
1)豎直滾動(dòng)

 ListView(
          children: <Widget>[
            ListTile(title: Text('第一項(xiàng)')),
            ListTile(title: Text('第二項(xiàng)')),
            ListTile(title: Text('第三項(xiàng)')),
            //設(shè)置ListTile組件的標(biāo)題與圖標(biāo)
            ListTile(leading: Icon(Icons.map),  title: Text('Map')),
            ListTile(leading: Icon(Icons.mail), title: Text('Mail')),
            ListTile(leading: Icon(Icons.message), title: Text('Message')),
          ]
      ),

2)水平滾動(dòng)

 ListView(
          scrollDirection: Axis.horizontal,
          //item延展尺寸(寬度)
          itemExtent: 140,
          children: [
            Container(color: Colors.black),
            Container(color: Colors.red),
            Container(color: Colors.blue),
            Container(color: Colors.green),
            Container(color: Colors.yellow),
            Container(color: Colors.orange),
          ]),

3)build方法構(gòu)造多個(gè)item

  ListView.builder(
            itemCount: 100, //元素個(gè)數(shù)
            itemExtent: 50.0, //列表項(xiàng)高度
            itemBuilder: (BuildContext context, int index) => ListTile(
                title: Text("title $index"), subtitle: Text("body $index")))

4)分割線類型

ListView.separated(
            itemCount: 100,
            separatorBuilder: (BuildContext context, int index) => index %2 ==0? Divider(color: Colors.green) : Divider(color: Colors.red),//index為偶數(shù),創(chuàng)建綠色分割線;index為奇數(shù),則創(chuàng)建紅色分割線
            itemBuilder: (BuildContext context, int index) => ListTile(title: Text("title $index"), subtitle: Text("body $index"))//創(chuàng)建子Widget
        )

5)自定義scrollView

CustomScrollView組件,ListView 實(shí)現(xiàn)了單一視圖下可滾動(dòng) Widget 的交互模型,同時(shí)也包含了 UI 顯示相關(guān)的控制邏輯和布局模型。但是,對(duì)于某些特殊交互場(chǎng)景,比如多個(gè)效果聯(lián)動(dòng)、嵌套滾動(dòng)、精細(xì)滑動(dòng)、視圖跟隨手勢(shì)操作等,還需要嵌套多個(gè) ListView 來(lái)實(shí)現(xiàn)。這時(shí),各自視圖的滾動(dòng)和布局模型就是相互獨(dú)立、分離的,就很難保證整個(gè)頁(yè)面統(tǒng)一一致的滑動(dòng)效果。那么,F(xiàn)lutter 是如何解決多 ListView 嵌套時(shí),頁(yè)面滑動(dòng)效果不一致的問(wèn)題的呢?在 Flutter 中有一個(gè)專門的控件 CustomScrollView,用來(lái)處理多個(gè)需要自定義滾動(dòng)效果的 Widget。

在 CustomScrollView 中,這些彼此獨(dú)立的、可滾動(dòng)的 Widget 被統(tǒng)稱為 Sliver。比如,ListView 的 Sliver 實(shí)現(xiàn)為 SliverList,AppBar 的 Sliver 實(shí)現(xiàn)為 SliverAppBar。這些 Sliver 不再維護(hù)各自的滾動(dòng)狀態(tài),而是交由 CustomScrollView 統(tǒng)一管理,最終實(shí)現(xiàn)滑動(dòng)效果的一致性。

接下來(lái),我通過(guò)一個(gè)滾動(dòng)視差的例子,與你演示 CustomScrollView 的使用方法。視差滾動(dòng)是指讓多層背景以不同的速度移動(dòng),在形成立體滾動(dòng)效果的同時(shí),還能保證良好的視覺體驗(yàn)。 作為移動(dòng)應(yīng)用交互設(shè)計(jì)的熱點(diǎn)趨勢(shì),越來(lái)越多的移動(dòng)應(yīng)用使用了這項(xiàng)技術(shù)。
以一個(gè)有著封面頭圖的列表為例,我們希望封面頭圖和列表這兩層視圖的滾動(dòng)聯(lián)動(dòng)起來(lái),當(dāng)用戶滾動(dòng)列表時(shí),頭圖會(huì)根據(jù)用戶的滾動(dòng)手勢(shì),進(jìn)行縮小和展開。經(jīng)分析得出,要實(shí)現(xiàn)這樣的需求,我們需要兩個(gè) Sliver:作為頭圖的 SliverAppBar,與作為列表的 SliverList。
具體的實(shí)現(xiàn)思路是:在創(chuàng)建 SliverAppBar 時(shí),把 flexibleSpace 參數(shù)設(shè)置為懸浮頭圖背景。flexibleSpace 可以讓背景圖顯示在 AppBar 下方,高度和 SliverAppBar 一樣;而在創(chuàng)建 SliverList 時(shí),通過(guò) SliverChildBuilderDelegate 參數(shù)實(shí)現(xiàn)列表項(xiàng)元素的創(chuàng)建;最后,將它們一并交由 CustomScrollView 的 slivers 參數(shù)統(tǒng)一管理。

      //頭圖header一起聯(lián)動(dòng)
        CustomScrollView(slivers: <Widget>[
          SliverAppBar(
            //SliverAppBar作為頭圖控件
            title: Text('CustomScrollView Demo'), //標(biāo)題
            floating: true, //設(shè)置懸浮樣式
            flexibleSpace: Image.network(
                "https://upload.jianshu.io/users/upload_avatars/1694376/4b7e25bd43ee.jpg",
                fit: BoxFit.cover), //設(shè)置懸浮頭圖背景
            expandedHeight: 300, //頭圖控件高度
          ),
          SliverList(
            //SliverList作為列表控件
            delegate: SliverChildBuilderDelegate(
              (context, index) =>
                  ListTile(title: Text('Item #$index')), //列表項(xiàng)創(chuàng)建方法
              childCount: 100, //列表元素個(gè)數(shù)
            ),
          ),
        ]
        )

6)監(jiān)聽偏移量,用類ScrollController

class _PageScrollControllerState extends State<PageScrollController> with WidgetsBindingObserver {
  late ScrollController _controller;//ListView 控制器
  bool isToTop = false;// 標(biāo)示目前是否需要啟用 "Top" 按鈕
  @override
  void initState() {
    _controller = ScrollController();
    _controller.addListener(() {// 為控制器注冊(cè)滾動(dòng)監(jiān)聽方法
      if(_controller.offset > 1000) {// 如果 ListView 已經(jīng)向下滾動(dòng)了 1000,則啟用 Top 按鈕
        setState(() {isToTop = true;});
      } else if(_controller.offset < 300) {// 如果 ListView 向下滾動(dòng)距離不足 300,則禁用 Top 按鈕
        setState(() {isToTop = false;});
      }
    });
    super.initState();
  }
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Scroll Controller Widget")),
      body: Column(
        children: <Widget>[
          Container(
            height: 40.0,
            child: RaisedButton(onPressed: (isToTop ? () {
              if (isToTop) {
                _controller.animateTo(.0,
                    duration: Duration(milliseconds: 200),
                    curve: Curves.ease
                ); // 做一個(gè)滾動(dòng)到頂部的動(dòng)畫
              }
            } : null), child: Text("Top"),),
          ),
          Expanded(
            child: ListView.builder(
              controller: _controller, // 初始化傳入控制器
              itemCount: 100, // 列表元素總數(shù)
              itemBuilder: (context, index) =>
                  ListTile(title: Text("Index : $index")), // 列表項(xiàng)構(gòu)造方法
            ),
          ),
        ],
      ),
    );
  }
  @override
  void dispose() {
    _controller.dispose(); // 銷毀控制器
    super.dispose();
  }
}

7)監(jiān)聽開始滾動(dòng)結(jié)束等,用widget NotificationListener

 body: NotificationListener<ScrollNotification>(// 添加 NotificationListener 作為父容器
              onNotification: (scrollNotification) {// 注冊(cè)通知回調(diào)
                if (scrollNotification is ScrollStartNotification) {// 滾動(dòng)開始
                  print('Scroll Start');
                } else if (scrollNotification is ScrollUpdateNotification) {// 滾動(dòng)位置更新
                  print('Scroll Update');
                } else if (scrollNotification is ScrollEndNotification) {// 滾動(dòng)結(jié)束
                  print('Scroll End');
                }
                return true;
              },
              child: ListView.builder(
                itemCount: 30,// 列表元素個(gè)數(shù)
                itemBuilder: (context, index) => ListTile(title: Text("Index : $index")),// 列表項(xiàng)創(chuàng)建方法
              ),
            )
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容