前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Padding、Row、Column、Expanded、Stack、AspectRatio、Card、Wrap等布局组件初体验

Padding、Row、Column、Expanded、Stack、AspectRatio、Card、Wrap等布局组件初体验

作者头像
拉维
发布2019-08-12 16:02:16
7560
发布2019-08-12 16:02:16
举报
文章被收录于专栏:iOS小生活

Padding组件

在HTML中,常见的布局标签都有padding属性,但是在Flutter中,很多的widget是没有padding属性的。这时我们就可以使用padding组件来处理容器与子元素之间的间距。

Padding组件有两个属性:

  • padding,EdgeInsets 设置填充的值
  • child,子组件

先来看下面一段代码:

代码语言:javascript
复制
class HomeContent extends StatelessWidget {

  List<Widget> _getChildren(){
    var children = listData.map((value){
      return Image.network(value["imgUrl", fit: BoxFit.cover,);
    });
    return children.toList();
  }

  @override
  Widget build(BuildContext context) {
    return GridView.count(
      crossAxisCount: 3,
      children: this._getChildren(),
    );
  }
  
}

这段代码的运行效果如下:

可以看到,GridView的子元素是Image。现在我们想给图片组件加一些内边距,但是Image组件是没有padding属性的,这个时候该怎么办呢?我们可以使用Padding组件。代码如下:

代码语言:javascript
复制
class HomeContent extends StatelessWidget {
  List<Widget> _getChildren() {
    var children = listData.map((value) {
      return Padding(//Padding组件
        child: Image.network(
          value["imgUrl"],
          fit: BoxFit.cover,
        ),
        padding: EdgeInsets.fromLTRB(10, 10, 0, 0),
      );
    });
    return children.toList();
  }

  @override
  Widget build(BuildContext context) {
    return Padding(//Padding组件
      padding: EdgeInsets.fromLTRB(0, 0, 10, 10),
      child: GridView.count(
        crossAxisCount: 3,
        children: this._getChildren(),
      ),
    );
  }
}

效果如下:

对于一些没有padding属性的组件,比如Image,我们可以在其外部包一个Padding组件,来实现内边距padding的效果

如何自定义一个组件

自定义一个组件无非就是三步:

  1. 实现build方法来定义组件的样式和布局;
  2. 声明需要传入的相关属性;
  3. 实现构造方法

下面是自定义一个名为IconContainer的组件:

代码语言:javascript
复制
class IconContainer extends StatelessWidget {
  
  //声明属性
  Color bgColor = Colors.yellow;
  double iconSize = 16;
  IconData iconname = Icons.home;

  //构造方法(使用大括号包起来的都是可选命名参数)
  IconContainer({this.bgColor, this.iconname, this.iconSize});

  //build方法
  @override
  Widget build(BuildContext context) {
    return Container(
      height: 100,
      width: 100,
      color: this.bgColor,
      child: Center(
        child: Icon(this.iconname, size: this.iconSize, color: Colors.white,),
      ),
    );
  }

}

Row 水平布局组件

Row组件有如下三个属性:

  • mainAxisAlignment,主轴的排列方式
  • crossAxisAlignment,交叉轴的排列方式
  • children,组件子元素
代码语言:javascript
复制
class HomeContent extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      width: 300,
      height: 500,
      color: Colors.pink,
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly, //调整主轴的排列方式(常用)
        crossAxisAlignment: CrossAxisAlignment.center, //调整交叉轴的排列方式(用的比较少)
        children: <Widget>[
          IconContainer(Colors.green, Icons.date_range, 30),
          IconContainer(Colors.red, Icons.edit_location, 35),
          IconContainer(Colors.yellow, Icons.fast_rewind, 40),
        ],
      ),
    );
  }
}

效果如下:

Column 垂直布局组件

Colume组件与Row组件的使用方式一模一样:

代码语言:javascript
复制
class HomeContent extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      width: 300,
      height: 500,
      color: Colors.pink,
      child: Column(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly, //调整主轴的排列方式(常用)
        crossAxisAlignment: CrossAxisAlignment.end, //调整交叉轴的排列方式(用的比较少)
        children: <Widget>[
          IconContainer(Colors.green, Icons.date_range, 30),
          IconContainer(Colors.red, Icons.edit_location, 35),
          IconContainer(Colors.yellow, Icons.fast_rewind, 40),
        ],
      ),
    );
  }
}

效果如下:

Expanded 组件

Expanden组件可以用在Row和Column布局中,有如下两个属性:

  • flex,元素占整个父 Row/Column 的比例
  • child,子元素
代码语言:javascript
复制
Row(
      children: <Widget>[
        Expanded(
          flex: 1,
          child: IconContainer(Colors.pink, Icons.fast_rewind, 30),
        ),
        Expanded(
          flex: 2,
          child: IconContainer(Colors.orange, Icons.hdr_strong, 40),
        ),
        Expanded(
          flex: 1,
          child: IconContainer(Colors.blue, Icons.screen_lock_rotation, 50),
        ),
      ],
    );

效果如下:

此外,我们也可以使用Expanded组件实现宽度或者高度的自适应。如下所示:

代码语言:javascript
复制
Row(
      children: <Widget>[
        Expanded(
          flex: 1,
          child: IconContainer(Colors.pink, Icons.fast_rewind, 30),
        ),
        IconContainer(Colors.orange, Icons.hdr_strong, 40),
      ],
    );

效果如下:

其他

可以使用SizedBox组件来定义组件的间隔。

Stack

Stack是堆的意思,有如下两个参数:

  • alignment,配置所有子元素的显示位置
  • children,子组件

Stack组件可以单独使用。当其子元素只有一个,或者只有少数个元素并且这些子元素的布局是统一的,此时就可以 单独使用Stack进行布局。如下所示:

代码语言:javascript
复制
Container(
      height: 400,
      width: 300,
      color: Colors.yellow,
      child: Stack(
        alignment: Alignment(0, 0),//这里的效果是,使children里面d额所有元素都居中展示
        children: <Widget>[
          Image.network(
              "http://pic27.nipic.com/20130325/11918471_071536564166_2.jpg"),
          Text(
            "666888",
            style: TextStyle(color: Colors.white, fontSize: 20),
          ),
        ],
      ),
    );

效果如下:

但一个容器中有多个元素,而这些元素各有各自不同的布局的时候,可以使用Stack结合Align或者Stack结合Positioned来实现。

Stack & Align

代码语言:javascript
复制
Container(
      height: 400,
      width: 300,
      color: Colors.yellow,
      child: Stack(
        alignment: Alignment(0, 0),
        children: <Widget>[
          Align(
            alignment: Alignment.topLeft,
            child: IconContainer(Colors.red, Icons.aspect_ratio, 30),
          ),
          Align(
            alignment: Alignment.topRight,
            child: IconContainer(Colors.blue, Icons.sd_card, 40),
          ),
          Align(
            child: IconContainer(Colors.green, Icons.data_usage, 50),
          ),
        ],
      ),
    );

通过Stack结合ALign可以控制Stack组件内部的每个元素的具体位置。Stack的alignment可以控制所有子元素的布局,Align的alignment属性可以控制某个具体子元素的布局,如果两者同时存在,则以Align的alignment属性为准。上述代码的效果如下:

Stack & Positioned

代码语言:javascript
复制
Container(
      height: 200,
      width: 300,
      color: Colors.yellow,
      child: Stack(
        children: <Widget>[
          Align(
            alignment: Alignment.center,
            child: Container(
              child: Image.network(
                "http://pic27.nipic.com/20130325/11918471_071536564166_2.jpg",
                fit: BoxFit.cover,
              ),
            ),
          ),
          Positioned(
            left: 10,
            bottom: 10,
            right: 10,
            child: Text(
              "http://pic27.nipic.com/20130325/11918471_071536564166_2.jpg",
              style: TextStyle(color: Colors.white, fontSize: 18),
            ),
          )
        ],
      ),
    );

效果图如下:

AspectRatio

AspectRatio的作用是根据设置调整子元素child的宽高比。

AspectRatio首先会在布局限制条件允许的范围内尽可能地扩展,Widget的宽度(高度)由高度(宽度)和比率决定,类似于BoxFit中的contain,按照固定比率去尽量占满区域。

AspectRatio有如下两个属性:

  • aspectRatio,宽高比
  • child,子组件

如下代码:

代码语言:javascript
复制
Container(
      width: 300,
      child: AspectRatio(
        aspectRatio: 2,
        child: Container(
          color: Colors.red,
        ),
      ),
    );

展示效果为:

Card

Card是卡片组件块,内容可以由大多数类型的Widget构成。Card具有圆角和阴影,这让它看起来具有立体感。

Card有如下三个属性:

  • margin,外边距
  • child,子组件
  • shape,Card的阴影效果,默认的阴影效果为圆角的长方形边

如下面代码:

代码语言:javascript
复制
ListView(
      children: <Widget>[
        Card(
          margin: EdgeInsets.all(10),
          child: Column(
            children: <Widget>[
              ListTile(
                title: Text(
                  "张三",
                  style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
                ),
                subtitle: Text("高级软件工程师"),
              ),
              ListTile(
                title: Text("电话:13241668866"),
              ),
              ListTile(
                title: Text("地址:北京市海淀区"),
              )
            ],
          ),
        ),

        Card(
          margin: EdgeInsets.all(10),
          child: Column(
            children: <Widget>[
              ListTile(
                title: Text(
                  "李四",
                  style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
                ),
                subtitle: Text("高级软件工程师"),
              ),
              ListTile(
                title: Text("电话:13241668866"),
              ),
              ListTile(
                title: Text("地址:北京市海淀区"),
              )
            ],
          ),
        ),

        Card(
          margin: EdgeInsets.all(10),
          child: Column(
            children: <Widget>[
              ListTile(
                title: Text(
                  "王武",
                  style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
                ),
                subtitle: Text("高级软件工程师"),
              ),
              ListTile(
                title: Text("电话:13241668866"),
              ),
              ListTile(
                title: Text("地址:北京市海淀区"),
              )
            ],
          ),
        )
      ],
    );

效果如下:

下面再来看一个例子,代码如下:

代码语言:javascript
复制
class HomeContent extends StatelessWidget {
  Widget _getItem(context, index) {
    Map itemdata = listData[index];
    return Card(
      margin: EdgeInsets.all(10),
      child: Column(
        children: <Widget>[
          AspectRatio(
            aspectRatio: 2,
            child: Image.network(
              itemdata["imgUrl"],
              fit: BoxFit.cover,
            ),
          ),
          ListTile(
            leading: CircleAvatar(
              backgroundImage: NetworkImage(itemdata["imgUrl"]),
            ),
            title: Text(itemdata["title"]),
            subtitle: Text(itemdata["detail"]),
          )
        ],
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      itemCount: listData.length,
      itemBuilder: this._getItem,
    );
  }
}

效果如下:

关于上面这个例子,有如下几点说明。

图片的圆角,我们可以使用ClipOval组件,也可以使用该例中的CircleAvator组件。

可以使用AspectRatio组件来实现组件固定的宽高比。

Wrap

Wrap可以实现流布局,单行的Wrap跟Row表现几乎一致,单列的Wrap跟Column表现几乎一致。但是Row与Column都是单行单列的,Wrap则突破了这个限制,mainAxis上空间不足时,则向crossAxis上去扩展展示。

Wrap有如下常用属性:

  • direction,主轴的方向,默认是水平
  • alignment,主轴的对齐方式
  • spacing,主轴方向上的间距
  • runSpacing,交叉轴方向上的间距
代码语言:javascript
复制
class HomeContent extends StatelessWidget {
  List<Widget> _getChildren() {
    var children = listData.map((value) {
      return MyButton(value["title"]);
    });
    return children.toList();
  }

  @override
  Widget build(BuildContext context) {
    return Wrap(
      children: this._getChildren(),
      alignment: WrapAlignment.start, //主轴方向上的对齐方式
      spacing: 30, //主轴方向上的间距
      runSpacing: 10, //交叉轴方向上的间距
    );
  }
}

class MyButton extends StatelessWidget {
  final String titleStr;
  MyButton(this.titleStr);

  @override
  Widget build(BuildContext context) {
    return RaisedButton(
      child: Text(this.titleStr),
      onPressed: () {
        print(Text(this.titleStr));
      },
    );
  }
}

显示效果如下:

以上。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-08-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 iOS小生活 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档