Flutter 基础组件

2025-06-30  本文已影响0人  雪_晟

版本信息:2.2.2 版本较老

一、基础组件
1、文本

1)普通文本

 Text(
              '文本是视图系统中的常见控件,用来显示一段特定样式的字符串,就比如Android里的TextView,或是iOS中的UILabel。',
              textAlign: TextAlign.center,

              style: TextStyle(
                  fontWeight: FontWeight.bold,
                  fontSize: 20,
                  color: Colors.red), //20号红色粗体展示
            ),

2)富文本

 Text.rich(
              TextSpan(children: <TextSpan>[
                TextSpan(
                    text: '文本是视图系统中常见的控件,它用来显示一段特定样式的字符串,类似',
                    style: redStyle), //第1个片段,红色样式
                TextSpan(text: 'Android', style: blackStyle), //第1个片段,黑色样式
                TextSpan(text: '中的', style: redStyle), //第1个片段,红色样式
                TextSpan(text: 'TextView', style: blackStyle) //第1个片段,黑色样式
              ]),
              textAlign: TextAlign.center,
            ),
2、图片

1)本地图片

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

2)网络图片

            Image.network(
              'https://upload.jianshu.io/users/upload_avatars/1694376/4b7e25bd43ee.jpg',
              width: 200,        // 设置图片宽度
              height: 200,       // 设置图片高度
              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'), // 目标网络图片
              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, //设置背景色为黄色
                shape: BeveledRectangleBorder(
                    borderRadius: BorderRadius.circular(20.0)), //设置斜角矩形边框
                colorBrightness: Brightness.light, //确保文字按钮为深色
                onPressed: () => print('FlatButton pressed'),
                height: 40,
                minWidth: 50,
                child: Row(
                  children: <Widget>[Icon(Icons.add), Text("Add")],
                )),
二、列表

在 Android 中是由 ListView 或 RecyclerView 实现的,在 iOS 中是用 UITableView 实现的;而在 Flutter 中,实现这种需求的则是列表控件 ListView。
1)竖直滚动

 ListView(
          children: <Widget>[
            ListTile(title: Text('第一项')),
            ListTile(title: Text('第二项')),
            ListTile(title: Text('第三项')),
            //设置ListTile组件的标题与图标
            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)水平滚动

 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方法构造多个item

  ListView.builder(
            itemCount: 100, //元素个数
            itemExtent: 50.0, //列表项高度
            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为偶数,创建绿色分割线;index为奇数,则创建红色分割线
            itemBuilder: (BuildContext context, int index) => ListTile(title: Text("title $index"), subtitle: Text("body $index"))//创建子Widget
        )

5)自定义scrollView

CustomScrollView组件,ListView 实现了单一视图下可滚动 Widget 的交互模型,同时也包含了 UI 显示相关的控制逻辑和布局模型。但是,对于某些特殊交互场景,比如多个效果联动、嵌套滚动、精细滑动、视图跟随手势操作等,还需要嵌套多个 ListView 来实现。这时,各自视图的滚动和布局模型就是相互独立、分离的,就很难保证整个页面统一一致的滑动效果。那么,Flutter 是如何解决多 ListView 嵌套时,页面滑动效果不一致的问题的呢?在 Flutter 中有一个专门的控件 CustomScrollView,用来处理多个需要自定义滚动效果的 Widget。

在 CustomScrollView 中,这些彼此独立的、可滚动的 Widget 被统称为 Sliver。比如,ListView 的 Sliver 实现为 SliverList,AppBar 的 Sliver 实现为 SliverAppBar。这些 Sliver 不再维护各自的滚动状态,而是交由 CustomScrollView 统一管理,最终实现滑动效果的一致性。

接下来,我通过一个滚动视差的例子,与你演示 CustomScrollView 的使用方法。视差滚动是指让多层背景以不同的速度移动,在形成立体滚动效果的同时,还能保证良好的视觉体验。 作为移动应用交互设计的热点趋势,越来越多的移动应用使用了这项技术。
以一个有着封面头图的列表为例,我们希望封面头图和列表这两层视图的滚动联动起来,当用户滚动列表时,头图会根据用户的滚动手势,进行缩小和展开。经分析得出,要实现这样的需求,我们需要两个 Sliver:作为头图的 SliverAppBar,与作为列表的 SliverList。
具体的实现思路是:在创建 SliverAppBar 时,把 flexibleSpace 参数设置为悬浮头图背景。flexibleSpace 可以让背景图显示在 AppBar 下方,高度和 SliverAppBar 一样;而在创建 SliverList 时,通过 SliverChildBuilderDelegate 参数实现列表项元素的创建;最后,将它们一并交由 CustomScrollView 的 slivers 参数统一管理。

      //头图header一起联动
        CustomScrollView(slivers: <Widget>[
          SliverAppBar(
            //SliverAppBar作为头图控件
            title: Text('CustomScrollView Demo'), //标题
            floating: true, //设置悬浮样式
            flexibleSpace: Image.network(
                "https://upload.jianshu.io/users/upload_avatars/1694376/4b7e25bd43ee.jpg",
                fit: BoxFit.cover), //设置悬浮头图背景
            expandedHeight: 300, //头图控件高度
          ),
          SliverList(
            //SliverList作为列表控件
            delegate: SliverChildBuilderDelegate(
              (context, index) =>
                  ListTile(title: Text('Item #$index')), //列表项创建方法
              childCount: 100, //列表元素个数
            ),
          ),
        ]
        )

6)监听偏移量,用类ScrollController

class _PageScrollControllerState extends State<PageScrollController> with WidgetsBindingObserver {
  late ScrollController _controller;//ListView 控制器
  bool isToTop = false;// 标示目前是否需要启用 "Top" 按钮
  @override
  void initState() {
    _controller = ScrollController();
    _controller.addListener(() {// 为控制器注册滚动监听方法
      if(_controller.offset > 1000) {// 如果 ListView 已经向下滚动了 1000,则启用 Top 按钮
        setState(() {isToTop = true;});
      } else if(_controller.offset < 300) {// 如果 ListView 向下滚动距离不足 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
                ); // 做一个滚动到顶部的动画
              }
            } : null), child: Text("Top"),),
          ),
          Expanded(
            child: ListView.builder(
              controller: _controller, // 初始化传入控制器
              itemCount: 100, // 列表元素总数
              itemBuilder: (context, index) =>
                  ListTile(title: Text("Index : $index")), // 列表项构造方法
            ),
          ),
        ],
      ),
    );
  }
  @override
  void dispose() {
    _controller.dispose(); // 销毁控制器
    super.dispose();
  }
}

7)监听开始滚动结束等,用widget NotificationListener

 body: NotificationListener<ScrollNotification>(// 添加 NotificationListener 作为父容器
              onNotification: (scrollNotification) {// 注册通知回调
                if (scrollNotification is ScrollStartNotification) {// 滚动开始
                  print('Scroll Start');
                } else if (scrollNotification is ScrollUpdateNotification) {// 滚动位置更新
                  print('Scroll Update');
                } else if (scrollNotification is ScrollEndNotification) {// 滚动结束
                  print('Scroll End');
                }
                return true;
              },
              child: ListView.builder(
                itemCount: 30,// 列表元素个数
                itemBuilder: (context, index) => ListTile(title: Text("Index : $index")),// 列表项创建方法
              ),
            )
上一篇 下一篇

猜你喜欢

热点阅读