Flutter(六)——多子元素组件:ListView,Scaffold,AppBar,Row,Column

简介: Flutter(六)——多子元素组件:ListView,Scaffold,AppBar,Row,Column

前言


Flutter开发中,多子元素组件包括:Scaffold,AppBar,Row,Column,Stack,IndexedStack,ListView,GridView,Flow,Table,Flex,Wrap,CustomScrollView,CustomMultiChildLayout等,下面博主将一一介绍其使用方式。(本文学完能实现如下效果)


Scaffold


Scaffold是基于Material库的一个与路由相关的,良好的“结构体”,它可以被认为是Flutter为我们提供的一个标准化的布局容器,在开发中,使用的频率非常高,所以必须掌握,我们先来看看其使用代码:

return Scaffold(
      appBar: AppBar(),
      body: Row(),
      bottomNavigationBar: ,
      floatingActionButton: 
      ), 
    );


根据上面的代码,我们可以看到,Scaffold结构体为我们很好继承了AppBar,FloatingActionButton等控件。这里我们先认识一下,待介绍完其他组件,在后续章节深入使用。


AppBar


做过Android开发应该一眼就能看出来,这就是一个标题栏组件,用于控制App的路由,显示标题栏,以及显示右侧的一些操作栏。其绘制区域一般位于屏幕的顶端,我们来看看AppBar的整体分布区域图:

从上图我们可以看到,Leading区域默认是隐藏的,但是如果有左侧滑栏时会显示。并且,当这个界面时上一个界面跳转过来的时候,这里会显示返回键,我们来看看具体使用的代码:

appBar: AppBar(
        // Here we take the value from the MyHomePage object that was created by
        // the App.build method, and use it to set our appbar title.
        title: Text("AppBar"),
          actions: [
            IconButton(
              icon: Icon(Icons.playlist_play),
              tooltip: '菜单1',
              onPressed: (){},
            ),
            IconButton(
              icon: Icon(Icons.playlist_add),
              tooltip: '菜单2',
              onPressed: (){},
            ),
            IconButton(
              icon: Icon(Icons.playlist_add_check),
              tooltip: '菜单3',
              onPressed: (){},
            ),
        ],
      ),


大多数情况下,使用上面的代码基本囊括了所有的AppBar常用使用方式,但是,可能我们有些情况还需要自定义标题栏。比如左侧不是返回按钮, 可能是商标,或者别的图标或者点击功能,这个时候我们可以通过重写leading属性,代码如下:

leading: IconButton(
            icon:new Icon(Icons.face),
            onPressed: (){}
),


这样我们就自定义了leading按钮,上面两段代码合并在一起实现的效果如下:


Row和Column


Row和Column在Flutter里的布局是需要我们终点掌握的内容,他们都属于线性布局。从Android层面来理解,类似的布局是LinearLayout,从前端来看,有点像标签。


需要注意的是,Column是不支持滚动的,如果需要实现滚动功能,则要考虑使用ListView。我们先来看看Row。Row是一个多子元素组件,用于在水平方向上防止并显示子组件,Row的基本属性如下表所示:


属性

取值
childred 传入子组件数组
crossAxisAlignment 子组件在纵轴方向上的对齐方式
mainAxisAlignment 子组件在水平方向上的对齐方式
textDirection 布局顺序,一般情况下从左到右
mainAxisSize max,表示尽可能多地占用水平方向上的位置,min则反之

了解Row组件的属性后,我们来看看它的使用代码:

body: Row(
        textDirection: TextDirection.rtl,//从右到左
        children: [
          Container(
            width: 100,
            height: 100,
            color: Colors.blue,
            alignment: Alignment.center,
            child: Text(
              "A",
              style: new TextStyle(color: Colors.white,fontSize: 25),
            ),
          ),
          Spacer(
            flex: 1,
          ),
          Container(
            width: 100,
            height: 100,
            color: Colors.blue,
            alignment: Alignment.center,
            child: Text(
              "B",
              style: new TextStyle(color: Colors.white,fontSize: 25),
            ),
          ),
          Spacer(
            flex: 1,
          ),
          Container(
            width: 100,
            height: 100,
            color: Colors.blue,
            alignment: Alignment.center,
            child: Text(
              "C",
              style: new TextStyle(color: Colors.white,fontSize: 25),
            ),
          ),
        ],
      ),


上面代码不用多说前面已经基本介绍过,除了Spacer,它的作用是创建一个可调整的空间隔,可用于调整Flex容器(如行或列)中窗口小部件之间的间距, 显示效果如下:

接着我们再来看看Column组件,其实它和Row组件基本相似,区别仅仅在于是在垂直方向上放置控件,唯一需要注意的是Row和Column里Cross Axis和Main Axis是不一样的,Row的Main Axis是横方向上的,Column的Main Axis是纵方向上的,Cross Axis同理。


ListView


ListView是Android开发中非常重要的组件,与Java开发Android中的ListView,RecycleView类似,作用都是可滚动项的线性列表,里面存放着相关组件的集合。在一般情况下,这些组件的结构都具有重复性,即每个item的结构相同。


ListView构建方式如下:


(1)ListView


(2)ListView.builder


(3)ListView.custom


(4)ListView.separated


我们来看看它的使用方式,代码如下:

body: ListView(
        padding: const EdgeInsets.all(10.0),
        itemExtent: 30.0,
        children: [
          Text("One"),
          Text("Two"),
          Text("Three"),
          Text("Four"),
          Text("Five"),
        ],
      ),


这算是最基本的使用方式,显示下过如下:

需要解释两个属性,这里itemExtent表示子项的高度,如果是ListView是水平显示,表示子项的宽度,特别注意,尽量设置这个参数,因为这样不需要动态计算,代码运行效率高,至于其他属性,看看下表:


属性 取值

shrinkWrap

是否根据子组件的高度来设置ListView的高度,默认为false
RepaintBoundart 当addRepaintBoundaries为true时,避免列表项滚动时重绘
AutomaticKeepAlive 当addRepaintKeepdaries为true时,则ListView滑出屏幕的区域不会被回收

接着我们再来看看ListView.builder的使用方式(ListView.builder被用于创建重复的子项布局):

body: ListView.builder(
        padding: const EdgeInsets.all(10.0),
        itemExtent: 30.0,
        itemCount: 5,//可以不传
        itemBuilder:(context,position){
        return ListItem();
        }
      ),


因为ListView是懒加载,所以可以不指定itemCount。列表有可能是无限长的,而itemBuilder传入的类型是IndexedWidgetBuilder,只会返回一个组件。当我们滚动到具体的位置因子时,就会创建列表项。


接着,我们来看看ListView.separated。他的作用是“分割”,即在列表子项中夹杂其他项,代码的基本结构如下所示:

ListView.separated(
  itemCount:itemCount,
  itemBuilder:(context,position){
  return ListItem();
  }
  separatorBuilder:(context,position){
  return SeparatorItem();
  }
)


separatorBuilder和itemBuilder基本类似。我们在实际的项目实践中,有可能需要用到分割线来分割列表的每一项item,这个时候ListView.separated就派上用处了。然而,在separatorBuilder里面,不一定只能传入分割线,也可以传入其他东西,比如图片,我们来看看其效果:

body: ListView.separated(
          itemBuilder: (BuildContext context,int index){
            return ListTile(title: Text("第$index列表"));
          },
          separatorBuilder: (BuildContext context,int index){
            return Align(
              alignment: Alignment.centerLeft,
              child: FlutterLogo(),
            );
          },
          itemCount: 20)


显示效果如下图所示:

最后,我们再来看看ListView.custom。它可以通过SliverChildListDelegate来接收IndexedWidgetBuilder,并且为ListView生成列表项,从而实现自定义功能,这里就不赘述了,后续实践中会详细介绍。


以上便是ListView的各种创建方式。我们现在来做一个有意思的效果,这里需要用到ScrollPhysics。这个属性是ListView中的physics上面设置的,包括NeverScrollablePhysics(不滚动效果),BouncingScrollPhysics(IOS效果),ClampingScrollPhysics(Anroid效果),FixedExtentScrollPhysics(固定范围的滚动效果)等,FixedExtentScrollPhysics使用代码如下:

@override
  Widget build(BuildContext context) {
    FixedExtentScrollController fixedExtentScrollController =
    new FixedExtentScrollController();
    final List imgList = [
      'https://img.tukuppt.com//ad_preview/00/10/93/5c993b5d9d798.jpg!/fw/780',
      'https://img.tukuppt.com//ad_preview/00/05/71/5c98de9ce54c3.jpg!/fw/780',
      'https://img.tukuppt.com//ad_preview/00/07/27/5c9902dec7ca4.jpg!/fw/780',
      'https://img.tukuppt.com//ad_preview/00/10/95/5c993bc348d70.jpg!/fw/780',
      'https://img.tukuppt.com//ad_preview/00/04/92/5c98cbc632893.jpg!/fw/780',
      'https://img.tukuppt.com//ad_preview/00/05/74/5c98df32309c8.jpg!/fw/780',
      'https://img.tukuppt.com//ad_preview/00/17/37/5c99cebeb89f6.jpg!/fw/780',
      'https://img.tukuppt.com//ad_preview/00/15/33/5c99a01628499.jpg!/fw/780',
      'https://img.tukuppt.com//ad_preview/00/13/28/5c9970fdc6932.jpg!/fw/780'
    ];
    // This method is rerun every time setState is called, for instance as done
    // by the _incrementCounter method above.
    //
    // The Flutter framework has been optimized to make rerunning build methods
    // fast, so that you can just rebuild anything that needs updating rather
    // than having to individually change instances of widgets.
    return Scaffold(
      appBar: AppBar(
        // Here we take the value from the MyHomePage object that was created by
        // the App.build method, and use it to set our appbar title.
        leading: IconButton(
            icon:new Icon(Icons.face),
            onPressed: (){}
            ),
        title: Text("AppBar"),
          actions: [
            IconButton(
              icon: Icon(Icons.playlist_play),
              tooltip: '菜单1',
              onPressed: (){},
            ),
            IconButton(
              icon: Icon(Icons.playlist_add),
              tooltip: '菜单2',
              onPressed: (){},
            ),
            IconButton(
              icon: Icon(Icons.playlist_add_check),
              tooltip: '菜单3',
              onPressed: (){},
            ),
        ],
      ),
      body: ListWheelScrollView(
        controller: fixedExtentScrollController,
        physics: FixedExtentScrollPhysics(),
        itemExtent: 150.0,
        children : imgList.map((img){
          return Card(
            child: Row(
              children: [
                Image.network(img,width: 150.0),
                Text("随便文字",style: new TextStyle(color: Colors.black45,fontSize: 20.0),
                ),
              ],
            ),
          );
        }).toList(),
      ),
    );
  }

这段代码的显示的效果如该帖开头动图效果一样,多子元素组件这篇博文就讲到这里,下篇博文介绍剩余组件。

相关文章
|
1月前
Flutter 自定义组件继承与调用的高级使用方式
本文深入探讨了 Flutter 中自定义组件的高级使用方式,包括创建基本自定义组件、继承现有组件、使用 Mixins 和组合模式等。通过这些方法,您可以构建灵活、可重用且易于维护的 UI 组件,从而提升开发效率和代码质量。
136 1
|
1月前
|
开发工具 UED
Flutter&鸿蒙next中封装一个输入框组件
本文介绍了如何创建一个简单的Flutter播客应用。首先,通过`flutter create`命令创建项目;接着,在`lib`目录下封装一个自定义输入框组件`CustomInput`;然后,在主应用文件`main.dart`中使用该输入框组件,实现简单的UI布局和功能;最后,通过`flutter run`启动应用。本文还提供了后续扩展建议,如状态管理、网络请求和UI优化。
107 1
|
1月前
|
Dart UED
Flutter用户交互组件
Flutter用户交互组件
30 2
|
1月前
|
开发工具
Flutter&鸿蒙next中封装一个列表组件
Flutter&鸿蒙next中封装一个列表组件
50 0
|
2月前
|
开发者
flutter:功能性组件 (八)
本文介绍了Flutter中常用的UI组件和功能,包括进度指示器(线性和圆形)、下拉刷新、选项按钮(单选按钮、复选框、开关)、手势识别(GestureDetector、Ink和InkWell)以及提示和Offstage组件的使用方法和示例代码。这些组件和功能可以帮助开发者快速构建交互丰富的应用程序界面。
|
2月前
|
Android开发 iOS开发 容器
鸿蒙harmonyos next flutter混合开发之开发FFI plugin
鸿蒙harmonyos next flutter混合开发之开发FFI plugin
|
1月前
|
开发框架 Dart 前端开发
Flutter 是谷歌推出的一款高效跨平台移动应用开发框架,使用 Dart 语言,具备快速开发、跨平台支持、高性能、热重载及美观界面等特点。
Flutter 是谷歌推出的一款高效跨平台移动应用开发框架,使用 Dart 语言,具备快速开发、跨平台支持、高性能、热重载及美观界面等特点。本文从 Flutter 简介、特点、开发环境搭建、应用架构、组件详解、路由管理、状态管理、与原生代码交互、性能优化、应用发布与部署及未来趋势等方面,全面解析 Flutter 技术,助你掌握这一前沿开发工具。
57 8
|
1月前
|
存储 JavaScript 前端开发
在Flutter开发中,状态管理至关重要。随着应用复杂度的提升,有效管理状态成为挑战
在Flutter开发中,状态管理至关重要。随着应用复杂度的提升,有效管理状态成为挑战。本文介绍了几种常用的状态管理框架,如Provider和Redux,分析了它们的基本原理、优缺点及适用场景,并提供了选择框架的建议和使用实例,旨在帮助开发者提高开发效率和应用性能。
36 4
|
1月前
|
传感器 前端开发 Android开发
在 Flutter 开发中,插件开发与集成至关重要,它能扩展应用功能,满足复杂业务需求
在 Flutter 开发中,插件开发与集成至关重要,它能扩展应用功能,满足复杂业务需求。本文深入探讨了插件开发的基本概念、流程、集成方法、常见类型及开发实例,如相机插件的开发步骤,同时强调了版本兼容性、性能优化等注意事项,并展望了插件开发的未来趋势。
42 2
|
2月前
|
开发者
鸿蒙Flutter实战:07-混合开发
鸿蒙Flutter混合开发支持两种模式:1) 基于har包,便于主项目开发者无需关心Flutter细节,但不支持热重载;2) 基于源码依赖,利于代码维护与热重载,需配置Flutter环境。项目结构包括AppScope、flutter_module等目录,适用于不同开发需求。
112 3