Flutter基础目录结构介绍、入口自定义widget、等相关组件使用原创

原创
小哥 3年前 (2022-11-11) 阅读数 5 #技术教程

提示:本文是一篇前端学习文章flutter过程中,如果有歧义,希望大家有很大的宝贵意见。

学习Dart 基础知识 移步这里
安装flutter环境相关 移步这里
flutter基本组件使用相关 移步这里

文章目录

一、Flutter 目录结构简介 入口

1.Flutter 目录结构简介

2.Flutter 入口


二、Flutter 自定义Widget


三、Flutter 组件使用

0.main.dart 基础设施;

import package:flutter/material.dart;

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
          appBar: AppBar(
            title: const Text(hello flutter demo),
          ),
          body: const MyContent()),
    );
  }
}

class MyContent extends StatelessWidget {
  const MyContent({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return const Text(data...);
  }
}

0.1. 自定义组件

是将组件拉出,并可以接收参数
自定义通用组件

class MyContent extends StatelessWidget {
  const MyContent({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return const IconContent(); //调用自定义组件
  }
}

// 自定义子组件
class IconContent extends StatelessWidget {
  const IconContent({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      width: 100,
      height: 100,
      padding: const EdgeInsets.all(8.0),
      color: Colors.red.shade900,
      child: const Icon(
        Icons.search,
        color: Colors.white70,
        size: 34,
      ),
    );
  }
}

自定义动态组件

class MyContent extends StatelessWidget {
  const MyContent({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return const IconContent(Icons.home,color:Colors.red,size:22); //调用自定义组件
  }
}

// 自定义定制组件
class IconContent extends StatelessWidget {
  final double size;  // 接收和发送的参数被视为常量,不能更改,从而减少了损失。
  final Color color;  // 接收和发送的参数被视为常量,不能更改,从而减少了损失。
  final IconData icon;  // 接收和发送的参数被视为常量,不能更改,从而减少了损失。

  const IconContent(
    this.icon, {
    Key? key,   // 继承自 statelesswidget 就这样写吧
    this.color = Colors.pink, // 默认赋值
    this.size = 50, //默认赋值
  }) : super(key: key);// 继承自 statelesswidget 就这样写吧

  @override
  Widget build(BuildContext context) {
    return Container(
      width: 100,
      height: 100,
      padding: const EdgeInsets.all(8.0),
      color: color,//  不需要使用新版本。 this.color 调用
      child: Icon(
        icon, //  不需要使用新版本。 this.icon 调用
        color: Colors.white,
        size: size,
      ),
    );
  }
}

**

注意 施工方法一般只处理传递的参数;

**


  1. Icon 图标使用

样式库地址: https://www.fluttericon.com/

const Icon(
    /// list 启动图标是一个icon
    Icons.set_meal_sharp,
    /// icon名称
    size: 60,
    /// icon 大小
    color: Colors.white,
    /// icon 颜色
    textDirection: TextDirection.ltr,
),

  1. Text组件 类似前端span

    Text( "Text组件的使用", style: TextStyle( // 文字颜色 color: Color(0xfff0000), // none 不要显示装饰线条,underline 在字体下方,overline 在字体上方,lineThrough穿过文字 decoration: TextDecoration.none, // solid 直线,double 双下划线,dotted 虚线,dashed 点下划线,wavy 波浪线 decorationStyle: TextDecorationStyle.solid, // 装饰线的颜色 decorationColor: Colors.red, // 文字大小 fontSize: 15.0, // normal 正常,italic 斜体 fontStyle: FontStyle.normal, // 字体的粗细 fontWeight: FontWeight.bold, // 字间宽度 letterSpacing: 1.0, // 文本行和文本行的高度,为字体大小(值)的倍数。1~2,如1.2) height: 1, //对齐文本的水平行: //TextBaseline.alphabetic:文本基线是标准字母基线 //TextBaseline.ideographic:文字基线是表意基线; //如果字符本身超过alphabetic 然后是基线ideograhpic基线位置位于角色本身的底部。 textBaseline: TextBaseline.alphabetic), // 段落的间距样式。 strutStyle: StrutStyle( fontFamily: serif, fontFamilyFallback: [monospace, serif], fontSize: 20, height: 2, leading: 2.0, fontWeight: FontWeight.w300, fontStyle: FontStyle.normal, forceStrutHeight: true, debugLabel: text demo, ), // 文本对齐方式 textAlign: TextAlign.center, // 文本排列方向 ltr 左到右,rtl右到左 textDirection: TextDirection.ltr, // 用于选择区域特定字形的语言环境 locale: Locale(zh_CN), // 软包裹 ,文本是否应跳出软行 softWrap: false, // 如何处理视觉溢出:clip 剪切溢出文本以修复其容器。ellipsis 使用省略号表示文本已溢出。fade 将溢出文本淡入透明。 overflow: TextOverflow.clip, // 文本比例 textScaleFactor: 1.0, // 可选的要跨越的最大文本行数, maxLines: 2, // 图像的语义描述,使用Andoid上的TalkBack和iOS上的VoiceOver提供图像描述 semanticsLabel: text demo, textWidthBasis: TextWidthBasis.longestLine, )


3.Flutter中 Container组件 类似前端div

margin :内边距和副边距Widget有关系
padding :外边距和父项。Widget有关系
alignment :子Widget对齐方式
默认是Alignment(0,0),子Widget中心。值的范围为(-1,1)。
child :子部件
clipBehavior :切割方法
color :背景颜色,如果foregroundDecoration套装,可盖color效果。
constraints :边界约束
decoration :用于设置特殊的背景和边框。在中绘制child背部的装饰。集decoration如果是这样,则不能设置color属性
foregroundDecoration :用于设置特殊的背景和边框。在中绘制child前部装饰
key :仅用于更新的唯一标记widget->key同一小工具的状态。
transform :矩阵变换 过度 旋转等
transformAlignment :设置矩阵变换的对齐方式。

Container(
  child: Image.network(
      http://pic.616pic.com/ys_bnew_img/00/17/41/RGxKWmyJIK.jpg),
  height: 300.0,
  width: 300.0,
  margin: const EdgeInsets.fromLTRB(20, 20, 20, 20),
  padding: const EdgeInsets.fromLTRB(20, 20, 20, 20),
  alignment: Alignment.bottomCenter,
  transform: Matrix4.skewX(0.1),
  decoration: BoxDecoration(
     color: Colors.white,
        borderRadius: const BorderRadius.all(
          Radius.circular(10),
        ),
        border: Border.all(
          color: tTextColor999.withOpacity(.2),
          width: 1,
        ),
        boxShadow: const [
          BoxShadow(
              color: Colors.black12,
              offset: Offset(0.0, 15.0), //阴影xy轴偏移量
              blurRadius: 15.0, //阴影模糊度
              spreadRadius: 1.0 //阴影漫射度
              )
        ],
        // 渐变色
        gradient: LinearGradient(
          colors: [tMainRedColor, Colors.red, tMainRedColor],
        ),
      ),
),

  1. Flutter中图片Image组件使用(远程、本地)

4.1.网络图片

Image.network(
    https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fb-ssl.duitang.com%2Fuploads%2Fitem%2F201609%2F07%2F20160907125722_LF84P.thumb.700_0.jpeg&refer=http%3A%2F%2Fb-ssl.duitang.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1653146319&t=a23832fe5477d1841073d48a644ad6e6,
    alignment: Alignment.topLeft, // 图片位置
    color: Colors.blue, // 图片颜色
    colorBlendMode: BlendMode.color, // 混色模式
    fit: BoxFit.cover, //剪切图片
    repeat: ImageRepeat.noRepeat, // 图片重复
),

4.2. 使用container实现圆形画面 4种方式

方式1 container 背景图片处理图片圆角

     Container(
        width: 300.0,
        height: 300.0,
        decoration: BoxDecoration(
          color: Colors.red,
          border: Border.all(
            color: Colors.purple,
            width: 4.0,
          ),
          borderRadius: BorderRadius.circular(150.0),
          image: const DecorationImage(
            image: NetworkImage(
                https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fb-ssl.duitang.com%2Fuploads%2Fitem%2F201609%2F07%2F20160907125722_LF84P.thumb.700_0.jpeg&refer=http%3A%2F%2Fb-ssl.duitang.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1653146319&t=a23832fe5477d1841073d48a644ad6e6),
            fit: BoxFit.cover,
            repeat: ImageRepeat.noRepeat,
          ),
        ),
      ),

方式2 container 此时将显示加工圆角下的子零部件。

Container(
      width: 50,
      height: 50,
      child: ClipRRect(
        borderRadius: const BorderRadius.all(Radius.circular(200)),
        child: Image.network(
          https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fb-ssl.duitang.com%2Fuploads%2Fitem%2F201609%2F07%2F20160907125722_LF84P.thumb.700_0.jpeg&refer=http%3A%2F%2Fb-ssl.duitang.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1653146319&t=a23832fe5477d1841073d48a644ad6e6,
          fit: BoxFit.cover,
        ),
      ),
),

方式3 处理头像

leading: CircleAvatar(
   backgroundImage: NetworkImage(
     "https://www.itying.com/images/flutter/1.png",
   ),
 ),

方式4 使用container 结合ClipOval实施原型图

Container(
      child: ClipOval(
        child: Image.network(
          https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fb-ssl.duitang.com%2Fuploads%2Fitem%2F201609%2F07%2F20160907125722_LF84P.thumb.700_0.jpeg&refer=http%3A%2F%2Fb-ssl.duitang.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1653146319&t=a23832fe5477d1841073d48a644ad6e6,
          width: 100,
          height: 100,
          fit: BoxFit.cover,
        ),
      ),
),

4.3. 使用本地图片

1.根目录创建一个文件。images 下创建 2.0x 3.0x 4.0x将文件放入不同的文件夹中 且再images也必须有一个;

2.然后,打开pubspec.yaml 声明添加的图片文件,注意配置配对 格式统一 对其

3.在代码中使用

Image.asset(
    本地路径..。,
    alignment: Alignment.topLeft, // 图片位置
    color: Colors.blue, // 图片颜色
    colorBlendMode: BlendMode.color, // 混色模式
    fit: BoxFit.cover, //剪切图片
    repeat: ImageRepeat.noRepeat, // 图片重复
),

  1. listView 垂直列表布局 、 水平布局

    class MyStatelessWidget extends StatelessWidget { const MyStatelessWidget({Key? key}) : super(key: key);

    @override Widget build(BuildContext context) { return ListView( scrollDirection: Axis.horizontal, // 垂直布局,高度固定,适应性广 scrollDirection: Axis.vertical, // 水平布局 、固定范围广、适应性强 padding: const EdgeInsets.fromLTRB(20, 20, 20, 20), children: [ ListTile( leading: const Icon( /// list 启动图标是一个icon Icons.set_meal_sharp, /// icon名称 size: 60, /// icon 大小 color: Colors.white, /// icon 颜色 textDirection: TextDirection.ltr, ), tileColor: Colors.blue[600], /// listTile 背景色 title: const Text( /// 标题是个text 东北北中国南中国, /// text内容 style: TextStyle( /// text样式 fontSize: 24.0, color: Colors.white, ), ), subtitle: const Text( 武汉、浙江等地发生大洪水, style: TextStyle( color: Colors.white38 ), ), ), ], ); } }


  1. Flutter ListView 和ListView.builder 动态列表 矩阵列表

6.1 动态列表是通过循环语句实现的。

class MyStatelessWidget extends StatelessWidget {
  const MyStatelessWidget({Key? key}) : super(key: key);

  List getData() {// 在此位置,返回值的类型必须声明为数组,并且值为Widget类型 如果调用是显式类型的数据,则返回。
    List lists = []; // 同上 类型必须是明确的
    for (var i = 0; i < 20; i++) {
      lists.add(ListTile(
        title: Text(
          这是($i+1)条数据啊, // 变量直接相加$
          style: TextStyle(
            color: Colors.blue.shade400,
          ),
        ),
      ));
    }
    return lists;
  }

  @override
  Widget build(BuildContext context) {
    return ListView(
      scrollDirection: Axis.vertical,
      children: getData(),// 这个位置需要类型的List所以在getData方法声明必须显式类型化Widget
    ); 
  }
}

6.2 通过方法遍历widget;

class MyStatelessWidget extends StatelessWidget {
  const MyStatelessWidget({Key? key}) : super(key: key);
  List getData() {
    // 必须在此位置声明类型 如果调用是显式类型的数据,则返回。
    List list = [ // 必须在此处明确声明该类型,否则将报告错误。
      {
        "name": 张三,
        "age": 12,   // text只能接受字符串 这个数字不能被错误地报告。
        "src": https://www.juliangip.com/index/static/pc/img/pro_pic2.png
      },
      {
        "name": 张三,
        "age": 12,
        "src": https://www.juliangip.com/index/static/pc/img/pro_pic2.png
      },
      {
        "name": 张三,
        "age": 12,
        "src": https://www.juliangip.com/index/static/pc/img/pro_pic2.png
      },
    ];

    var lists = list.map((item) {
      return ListTile(
        title: Text(item[name]), // 获取对象的值。
        leading: Image.network(item[src]),
        subtitle: Text(item[age]),
      );
    });
    return lists.toList();
  }

  @override
  Widget build(BuildContext context) {
    return ListView(
      scrollDirection: Axis.vertical,
      children: getData(),
    ); // 这个位置需要类型的List所以在getData方法声明必须显式类型化Widget
  }
}

6.3 ListView.builder 的使用 ,抽离Widget 自定义方法;

class MyStatelessWidget extends StatelessWidget {
  List list = [];
  MyStatelessWidget({Key? key}) : super(key: key) {
    list = [
      {
        "name": 张三,
        "age": 12,
        "src": https://www.juliangip.com/index/static/pc/img/pro_pic2.png
      },
      {
        "name": 张三,
        "age": 12,
        "src": https://www.juliangip.com/index/static/pc/img/pro_pic2.png
      },
      {
        "name": 张三,
        "age": 12,
        "src": https://www.juliangip.com/index/static/pc/img/pro_pic2.png
      }
    ];
  }

  // 自定义方法用于提取组件部件。

  Widget _getDataList(context, index) {
    return ListTile(
      title: Text(
        list[index][name],
      ),
      leading: Image.network(list[index][src]),
      subtitle: Text(list[index][age] + 岁数le ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      itemCount: list.length,
      itemBuilder: _getDataList,
    );

    /// 这个位置需要类型的List所以在getData方法声明必须显式类型化Widget
  }
}

  1. Flutter GridView组件和动力学GridView

7.1 GridView.count 实施网格布局

名称

类型

说明

scrollDirection

Axis

滚动方法

padding

EdgeInsetsGeometry

内边距

resolve

bool

组件反向排序

crossAxisSpacing

double

水平子 Widget 之间间距

mainAxisSpacing

double

垂直子 Widget 之间间距

crossAxisCount

int

int 一行的 Widget 数量

childAspectRatio

double

子 Widget 宽高比例

children

[ ]

gridDelegate

SliverGridDelegateWithFix edCrossAxisCount(常用) SliverGridDelegateWithMax CrossAxisExtent

主要使用控件布局。 GridView.builder 里面

import package:flutter/material.dart;

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text(hello flutter),
        ),
        body: MyGridViewCount(),
      ),
    );
  }
}

// ignore: must_be_immutable
class MyGridViewCount extends StatelessWidget {
   List lists = [
    {
      "title": goto事实上,它是非常优雅的,
      "url":
          https://pics4.baidu.com/feed/03087bf40ad162d9f89f23927bf594e68b13cdfb.jpeg?token=c4a6b12d01a8ea4272c90772bec72e10,
    },
    {
      "title": goto事实上,它是非常优雅的,居然一直被摒弃,
      "url":
          https://pics4.baidu.com/feed/03087bf40ad162d9f89f23927bf594e68b13cdfb.jpeg?token=c4a6b12d01a8ea4272c90772bec72e10,
    },
    {
      "title": goto事实上,它是非常优雅的,居然一直被摒弃,
      "url":
          https://pics4.baidu.com/feed/03087bf40ad162d9f89f23927bf594e68b13cdfb.jpeg?token=c4a6b12d01a8ea4272c90772bec72e10
    },
    {
      "title": goto事实上,它是非常优雅的,居然一直被摒弃,
      "url":
          https://pic.rmb.bdstatic.com/bjh/down/f1aa1dbb6e0d2eeabd1bcba92a3a67cf.jpeg@wm_2,t_55m+5a625Y+3L+WmmeS6ulNIT1c=,fc_ffffff,ff_U2ltSGVp,sz_26,x_17,y_17
    },
    {
      "title": goto事实上,它是非常优雅的,居然一直被摒弃,
      "url":
          https://pic.rmb.bdstatic.com/bjh/down/f1aa1dbb6e0d2eeabd1bcba92a3a67cf.jpeg@wm_2,t_55m+5a625Y+3L+WmmeS6ulNIT1c=,fc_ffffff,ff_U2ltSGVp,sz_26,x_17,y_17
    },
    {
      "title": goto事实上,它是非常优雅的,居然一直被摒弃,
      "url":
          https://pic.rmb.bdstatic.com/bjh/down/f1aa1dbb6e0d2eeabd1bcba92a3a67cf.jpeg@wm_2,t_55m+5a625Y+3L+WmmeS6ulNIT1c=,fc_ffffff,ff_U2ltSGVp,sz_26,x_17,y_17
    },
    {
      "title": goto事实上,它是非常优雅的,居然一直被摒弃,
      "url":
          https://pic.rmb.bdstatic.com/bjh/down/f1aa1dbb6e0d2eeabd1bcba92a3a67cf.jpeg@wm_2,t_55m+5a625Y+3L+WmmeS6ulNIT1c=,fc_ffffff,ff_U2ltSGVp,sz_26,x_17,y_17
    },
    {
      "title": goto事实上,它是非常优雅的,居然一直被摒弃,
      "url":
          https://pic.rmb.bdstatic.com/bjh/down/f1aa1dbb6e0d2eeabd1bcba92a3a67cf.jpeg@wm_2,t_55m+5a625Y+3L+WmmeS6ulNIT1c=,fc_ffffff,ff_U2ltSGVp,sz_26,x_17,y_17
    },
  ];

  MyGridViewCount({Key? key}) : super(key: key);

  List _getData() {
    return lists.map((item) {
      return Container(
        padding: const EdgeInsets.all(10),
        // container 样式
        decoration: BoxDecoration(  
        // container 边框样式
          border: Border.all( 
            color: Colors.grey.shade100,
          ),
           // container redius
          borderRadius: const BorderRadius.all(
            Radius.circular(4),
          ),
        ),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.center,// 垂直居中
          mainAxisAlignment: MainAxisAlignment.center, // 水平居中
          mainAxisSize: MainAxisSize.max,
          children: [
            Container(
              decoration: const BoxDecoration(
                borderRadius: BorderRadius.all(
                  Radius.circular(4),
                ),
              ),
              child: ClipRRect(
                borderRadius: const BorderRadius.all(Radius.circular(10)),
                child: Image.network(
                  item[url],
                  height: 110,
                  width: 400,
                  fit: BoxFit.cover,
                ),
              ),
            ),
            const SizedBox(
              height: 10,
            ),
            Text(
              item[title],
              style: const TextStyle(
                color: Colors.black87,
                fontSize: 14,
              ),
              maxLines: 1,
              overflow: TextOverflow.ellipsis,
              textAlign: TextAlign.center,
            ),
          ],
        ),
      );
    }).toList();
  }

  @override
  Widget build(BuildContext context) {
    return GridView.count(
      padding: const EdgeInsets.all(10),
      crossAxisSpacing: 10, //  水平子 widget 之间间距
      mainAxisSpacing: 10, //  垂直子 widget 之间间距
      crossAxisCount: 2, // 一行的 widget 数量
      // childAspectRatio: 0.7, // 宽高比
      children: _getData(),
    );
  }
}

7.2 GridView.builder 实施网格布局

import package:flutter/material.dart;

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text(hello flutter),
        ),
        body: MyGridViewCount(),
      ),
    );
  }
}

// ignore: must_be_immutable
class MyGridViewCount extends StatelessWidget {
  List lists = [
    {
      "title": goto事实上,它是非常优雅的,
      "url":
          https://pics4.baidu.com/feed/03087bf40ad162d9f89f23927bf594e68b13cdfb.jpeg?token=c4a6b12d01a8ea4272c90772bec72e10,
    },
    {
      "title": goto事实上,它是非常优雅的,居然一直被摒弃,
      "url":
          https://pics4.baidu.com/feed/03087bf40ad162d9f89f23927bf594e68b13cdfb.jpeg?token=c4a6b12d01a8ea4272c90772bec72e10,
    },
    {
      "title": goto事实上,它是非常优雅的,居然一直被摒弃,
      "url":
          https://pics4.baidu.com/feed/03087bf40ad162d9f89f23927bf594e68b13cdfb.jpeg?token=c4a6b12d01a8ea4272c90772bec72e10
    },
    {
      "title": goto事实上,它是非常优雅的,
      "url":
          https://pic.rmb.bdstatic.com/bjh/down/f1aa1dbb6e0d2eeabd1bcba92a3a67cf.jpeg@wm_2,t_55m+5a625Y+3L+WmmeS6ulNIT1c=,fc_ffffff,ff_U2ltSGVp,sz_26,x_17,y_17
    },
    {
      "title": goto事实上,它是非常优雅的,居然一直被摒弃,
      "url":
          https://pic.rmb.bdstatic.com/bjh/down/f1aa1dbb6e0d2eeabd1bcba92a3a67cf.jpeg@wm_2,t_55m+5a625Y+3L+WmmeS6ulNIT1c=,fc_ffffff,ff_U2ltSGVp,sz_26,x_17,y_17
    },
    {
      "title": goto事实上,它是非常优雅的,居然一直被摒弃,
      "url":
          https://pic.rmb.bdstatic.com/bjh/down/f1aa1dbb6e0d2eeabd1bcba92a3a67cf.jpeg@wm_2,t_55m+5a625Y+3L+WmmeS6ulNIT1c=,fc_ffffff,ff_U2ltSGVp,sz_26,x_17,y_17
    },
    {
      "title": goto事实上,它是非常优雅的,居然一直被摒弃,
      "url":
          https://pic.rmb.bdstatic.com/bjh/down/f1aa1dbb6e0d2eeabd1bcba92a3a67cf.jpeg@wm_2,t_55m+5a625Y+3L+WmmeS6ulNIT1c=,fc_ffffff,ff_U2ltSGVp,sz_26,x_17,y_17
    },
    {
      "title": goto事实上,它是非常优雅的,居然一直被摒弃,
      "url":
          https://pic.rmb.bdstatic.com/bjh/down/f1aa1dbb6e0d2eeabd1bcba92a3a67cf.jpeg@wm_2,t_55m+5a625Y+3L+WmmeS6ulNIT1c=,fc_ffffff,ff_U2ltSGVp,sz_26,x_17,y_17
    },
  ];

  MyGridViewCount({Key? key}) : super(key: key);

  Widget _getListData(context, index) {
    return Container(
      padding: const EdgeInsets.all(10),
      decoration: BoxDecoration(
        border: Border.all(
          color: Colors.grey.shade100,
        ),
        borderRadius: const BorderRadius.all(
          Radius.circular(4),
        ),
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.center,
        mainAxisAlignment: MainAxisAlignment.center,
        mainAxisSize: MainAxisSize.max,
        children: [
          Container(
            decoration: const BoxDecoration(
              borderRadius: BorderRadius.all(
                Radius.circular(4),
              ),
            ),
            child: ClipRRect(
              borderRadius: const BorderRadius.all(Radius.circular(10)),
              child: Image.network(
                lists[index][url],
                height: 110,
                width: 400,
                fit: BoxFit.cover,
              ),
            ),
          ),
          const SizedBox(
            height: 10,
          ),
          Text(
            lists[index][title],
            style: const TextStyle(
              color: Colors.black87,
              fontSize: 14,
            ),
            maxLines: 1,
            overflow: TextOverflow.ellipsis,
            textAlign: TextAlign.center,
          ),
        ],
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return GridView.builder(
      padding: const EdgeInsets.all(10),
      itemCount: lists.length,
      gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisSpacing: 10, //  水平子 widget 之间间距
        mainAxisSpacing: 10, //  垂直子 widget 之间间距
        crossAxisCount: 2, // 一行的 widget 数量
      ),
      itemBuilder: _getListData,
    );
  }
}

最终效果:


8.Flutter页面布局 Padding Row Column Expanded组件详解

8.1 Flutter Paddiing 组件

Padding 组件与 container 组件类似于组件。 div

主要公共参数

说明

child

子组件

padding

内边距

Padding(
  padding: const EdgeInsets.all(8.0),
  child: ClipOval(
    child: Image.network(
      "https://www.itying.com/images/flutter/2.png",
      fit: BoxFit.cover,
    ),
  ),
),

8.2 Flutter Row 水平布局组件

row 使用方法和 listview 的区别:listview 被整个屏幕覆盖,flutter中row 根据父零部件的宽度,它有多宽

主要公共参数

说明

mainAxisAlignment

一种主轴分选法

crossAxisAlignment

子轴排序法

children

子组件

import package:flutter/material.dart;

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
          appBar: AppBar(
            title: const Text(Flutter 的 Row组件),
          ),
          body: const MyContent()),
    );
  }
}

class MyContent extends StatelessWidget {
  const MyContent({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      height: 500,
      width: 350,
      color: Colors.pink,
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        crossAxisAlignment: CrossAxisAlignment.center,
        children: const [
          IconContent(
            Icons.home,
            color: Colors.blue,
            size: 30,
          ),
          IconContent(Icons.search),
          IconContent(Icons.usb_rounded),
        ],
      ),
    ); //调用自定义组件
  }
}

// 自定义定制组件
class IconContent extends StatelessWidget {
  final double size;
  final Color color;
  final IconData icon;

  const IconContent(
    this.icon, {
    Key? key,
    this.color = Colors.green,
    this.size = 50,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      width: 100,
      height: 100,
      padding: const EdgeInsets.all(8.0),
      color: color,
      child: Icon(
        icon,
        color: Colors.white,
        size: size,
      ),
    );
  }
}

8.3 Flutter Column 垂直布局组件

水平布局是等价的 flex的 column 使用方法和 listview 的区别:listview 被整个屏幕覆盖,flutter 是 row 它有多宽就有多宽

主要公共参数

说明

mainAxisAlignment

一种主轴分选法

crossAxisAlignment

子轴排序法

children

子组件

import package:flutter/material.dart;

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
          appBar: AppBar(
            title: const Text(Flutter 的 Column组件),
          ),
          body: const MyContent()),
    );
  }
}

class MyContent extends StatelessWidget {
  const MyContent({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      height: 500,
      width: 350,
      color: Colors.pink,
      child: Column(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        crossAxisAlignment: CrossAxisAlignment.center,
        children: const [
          IconContent(
            Icons.home,
            color: Colors.blue,
            size: 30,
          ),
          IconContent(Icons.search),
          IconContent(Icons.usb_rounded),
        ],
      ),
    ); //调用自定义组件
  }
}

// 自定义定制组件
class IconContent extends StatelessWidget {
  final double size;
  final Color color;
  final IconData icon;

  const IconContent(
    this.icon, {
    Key? key,
    this.color = Colors.green,
    this.size = 50,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      width: 100,
      height: 100,
      padding: const EdgeInsets.all(8.0),
      color: color,
      child: Icon(
        icon,
        color: Colors.white,
        size: size,
      ),
    );
  }
}

8.4 Flutter Expanded 类似 Web 中的 Flex 布局

expanded 可用于 Row 和 Column 布局中

属性

说明

child

子组件

flex

元素桩号是整个父零部件。 Row、Column 的比例

Row(
      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
      crossAxisAlignment: CrossAxisAlignment.center,
      children: const [
        Expanded(
          flex: 1,
          child: IconContent(
            Icons.home,
            color: Colors.blue,
            size: 30,
          ),
        ),
        Expanded(
          flex: 2,
          child: IconContent(
            Icons.usb_rounded,
            size: 30,
          ),
        ),
      ],
    )

  1. Flutter 页面布局 stack 层叠组件 stack 与 align stack 与 positioned 实现定位布局

9.1. stack 层叠组件

(有点像 ps 中的层的含义

从上到下写得越多,在上面写得越多,以后写得越多,首先写的参数就越多,如下所示 text 就把 container 遮挡了

import package:flutter/material.dart;

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
          appBar: AppBar(
            title: const Text(hello flutter demo),
          ),
          body: const MyContent()),
    );
  }
}

class MyContent extends StatelessWidget {
  const MyContent({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Stack(
        alignment: Alignment.center, // 定义组件的位置
        // alignment: const Alignment(0, -1),//或者这种00 是xy 中央商店,xy 最大值1,最小值为-1
        children: [
          Container(
            color: Colors.red.shade400,
            width: 300,
            height: 500,
          ),
          const Text(
            我是一个后写的领域,
            style: TextStyle(
              color: Colors.white,
              fontSize: 24,
            ),
          ),
        ],
      ),
    );
  }
}

注意:alignment 将控制所有组件,它们出现的位置,是的。 stack 下的所有子组件,

9.2. stack 与 Align 实施组件布局

注:因为 stack 下的 alignment 该物业正在运营。 stack 下的所有子组件,如果希望每个子组件具有不同的位置,请使用它。 Align 有 child 和 alignment(子组件位置由此特性更改。)

import package:flutter/material.dart;

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
          appBar: AppBar(
            title: const Text(hello flutter demo),
          ),
          body: const MyContent()),
    );
  }
}

class MyContent extends StatelessWidget {
  const MyContent({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        width: 200,
        height: 400,
        color: Colors.green,
        child: Stack(
          children: const [
            Align(
              alignment: Alignment.topLeft,
              child: Icon(Icons.home, size: 39, color: Colors.white),
            ),
            Align(
              alignment: Alignment.center,
              child: Icon(Icons.search, size: 40, color: Colors.white),
            ),
            Align(
              alignment: Alignment.bottomRight,
              child: Icon(Icons.architecture, size: 60, color: Colors.white),
            ),
          ],
        ),
      ),
    );
  }
}

9.3. stack 与 Positioned 实现定位布局

注意 有四个值 left right top bottom 跟 js 中的 position 与之非常相似,缺省值为0

import package:flutter/material.dart;

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
          appBar: AppBar(
            title: const Text(hello flutter demo),
          ),
          body: const MyContent()),
    );
  }
}

class MyContent extends StatelessWidget {
  const MyContent({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        width: 200,
        height: 400,
        color: Colors.green,
        child: Stack(
          children: const [
            Positioned(
              left: 10,
              top: 100,
              child: Icon(Icons.home, size: 39, color: Colors.white),
            ),
            Positioned(
              right: 10,
              top: 100,
              child: Icon(Icons.search, size: 40, color: Colors.white),
            ),
            Positioned(
              bottom: 100,
              child: Icon(Icons.architecture, size: 60, color: Colors.white),
            ),
          ],
        ),
      ),
    );
  }
}


  1. Flutter AspectRatio、Card 卡片组件

10.1 Flutter 中AspectRatio 组件

class MyContent extends StatelessWidget {
  const MyContent({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return AspectRatio(
      aspectRatio: 3.0 / 2.0, // 宽高比
      child: Container(
        color: Colors.red,
      ),
    );
  }
}

10.1 Flutter 中Card 卡片组件

class MyContent extends StatelessWidget {
  const MyContent({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return ListView(
      children: [
        Card(
          margin: const EdgeInsets.all(10),
          child: Column(children: const [
            ListTile(
              title: Text(
                洛基,
                style: TextStyle(color: Colors.black87),
              ),
              subtitle: Text(高级软件工程师),
            ),
            ListTile(
              title: Text(电话:xxx),
            ),
            ListTile(
              title: Text(邮箱:xxx),
            ),
          ]),
        ),
        Card(
          margin: const EdgeInsets.all(10),
          child: Column(children: const [
            ListTile(
              title: Text(
                洛基,
                style: TextStyle(color: Colors.black87),
              ),
              subtitle: Text(高级软件工程师),
            ),
            ListTile(
              title: Text(电话:xxx),
            ),
            ListTile(
              title: Text(邮箱:xxx),
            ),
          ]),
        ),
      ],
    );
  }
}

10.3 普通卡片样式布局

import package:flutter/material.dart;
import ./res/listData.dart;

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
          appBar: AppBar(
            title: const Text(hello flutter demo),
          ),
          body: const MyContent()),
    );
  }
}

class MyContent extends StatelessWidget {
  const MyContent({Key? key}) : super(key: key);
  // 删除自定义组件并遍历它们。
  List _getData() {
    return listData.map((val) {
      return Card(
        margin: const EdgeInsets.all(10.0),
        shadowColor: Colors.black12,
        child: Column(
          children: [
            AspectRatio(
              aspectRatio: 16.0 / 9.0,
              child: Image.network(
                val["imageUrl"],
                fit: BoxFit.cover,
                height: 300,
              ),
            ),
            ListTile(
              leading: CircleAvatar(
                backgroundImage: NetworkImage(
                  val["imageUrl"],
                ),
              ),
              title: Text(
                val["title"],
                overflow: TextOverflow.ellipsis,
                maxLines: 1,
              ),
              subtitle: Text(
                val["description"],
                maxLines: 1,
                overflow: TextOverflow.ellipsis,
              ),
            )
          ],
        ),
      );
    }).toList();
  }

  @override
  Widget build(BuildContext context) {
    return ListView(
      children: _getData(),
    );
  }
}

数据

  List listData=[
      {
          "title": Candy Shop,
          "author": Mohamed Chahin,
          "imageUrl": https://www.itying.com/images/flutter/1.png,
          "description": Flutter is Google’s mobile UI framework for crafting high-quality native experiences on iOS and Android in record time. Flutter works with existing,
      },
       {
          "title": Childhood in a picture,
          "author": Google,
          "imageUrl": https://www.itying.com/images/flutter/2.png,
          "description": Flutter is Google’s mobile UI framework for crafting high-quality native experiences on iOS and Android in record time. Flutter works with existing,
      },
      {
          "title": Alibaba Shop,
          "author": Alibaba,
          "imageUrl": https://www.itying.com/images/flutter/3.png,
          "description": Dart is a client-optimized language for fast apps on any platform... Dart is a client-optimized language for fast apps on any platform Optimizedfor,
      },
      {
          "title": Candy Shop,
          "author": Mohamed Chahin,
          "imageUrl": https://www.itying.com/images/flutter/4.png,
          "description": Dart is a client-optimized language for fast apps on any platform... Dart is a client-optimized language for fast apps on any platform Optimizedfor,
      },
       {
          "title": Tornado,
          "author": Mohamed Chahin,
          "imageUrl": https://www.itying.com/images/flutter/5.png,
          "description": Flutter is Google’s mobile UI framework for crafting high-quality native experiences on iOS and Android in record time. Flutter works with existing,
      },
      {
          "title": Undo,
          "author": Mohamed Chahin,
          "imageUrl": https://www.itying.com/images/flutter/6.png,
          "description": Flutter is Google’s mobile UI framework for crafting high-quality native experiences on iOS and Android in record time. Flutter works with existing,
      },
      {
          "title": white-dragon,
          "author": Mohamed Chahin,
          "imageUrl": https://www.itying.com/images/flutter/7.png,
          "description": Dart is a client-optimized language for fast apps on any platform... Dart is a client-optimized language for fast apps on any platform Optimizedfor,
      }      

  ];


11.Flutter 中 button 组件 使用。

11.1 Flutter 中 TextButton

TextButton(
  child: Text("TextButton按钮"),
  //添加单击事件
  onPressed: () {},
  //设置按钮是否自动获得焦点。
  autofocus: true,
  //定义文本样式
  style: ButtonStyle(
    //定义文本的样式 这里设置的颜色不起作用。
    textStyle: MaterialStateProperty.all(
        TextStyle(fontSize: 18, color: Colors.red)),
    //设置按钮上的字体和图标的颜色
    //foregroundColor: MaterialStateProperty.all(Colors.deepPurple),
    //更好的设置方式
    foregroundColor: MaterialStateProperty.resolveWith(
      (states) {
        if (states.contains(MaterialState.focused) &&
            !states.contains(MaterialState.pressed)) {
          //聚焦时的颜色
          return Colors.blue;
        } else if (states.contains(MaterialState.pressed)) {
          //按下时的颜色
          return Colors.deepPurple;
        }
        //默认状态使用灰色
        return Colors.grey;
      },
    ),
    //背景颜色
    backgroundColor: MaterialStateProperty.resolveWith((states) {
      //设置按下时的背景色
      if (states.contains(MaterialState.pressed)) {
        return Colors.blue[200];
      }
      //默认情况下不使用背景色
      return null;
    }),
    //设置水波颜色
    overlayColor: MaterialStateProperty.all(Colors.yellow),
    //设置阴影  在这里不适用。TextButton
    elevation: MaterialStateProperty.all(0),
    //设置按钮内边距
    padding: MaterialStateProperty.all(EdgeInsets.all(10)),
    //设置按钮的大小
    minimumSize: MaterialStateProperty.all(Size(200, 100)),

    //设置边框
    side:
        MaterialStateProperty.all(BorderSide(color: Colors.grey, width: 1)),
    //外框装饰 会覆盖 side 配置的样式
    shape: MaterialStateProperty.all(StadiumBorder()),
  ),
);

11.2 Flutter 中 IconButton

IconButton(
 onPressed: () {},
 icon: const Icon(Icons.search),
),

11.3 Flutter 中 ElevatedButton

ElevatedButton(
 onPressed: () {},
  child: const Text(ElevatedButton),
),

Container(
  width: 200,
  height: 50,
  child: ElevatedButton(
    onPressed: () {},
    child: Text(
      ElevatedButton,
    ),
    style: ButtonStyle(
      backgroundColor: MaterialStateProperty.all(Colors.red), // 背景色
      shadowColor: MaterialStateProperty.all(Colors.black), // 阴影
      elevation: MaterialStateProperty.all(4), // 阴影范围
    ),
  ),
),

// 在按钮前面添加icon
ElevatedButton.icon(
  onPressed: () {},
  icon: Icon(Icons.search),
  label: Text(图标按钮),
),

 // 圆角按钮
shape: MaterialStateProperty.all(
 RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
),

// 圆形按钮
  shape: MaterialStateProperty.all(CircleBorder(side: BorderSide(color: Colors.white))),


// 描边

side: MaterialStateProperty.all(BorderSide(width: 4, color: Colors.blue)),

注意:
想改变 button 纽扣大小,推荐一个面包 container 只需更改按钮大小
将按钮阴影设置为同时设置 evevation,否则无效;

11.4 Flutter 中 floatingActionButton

floatingActionButton: FloatingActionButton(
  onPressed: () {
    // Add your onPressed code here!
  },
  backgroundColor: Colors.green,
  child: const Icon(Icons.navigation),
),
floatingActionButtonLocation: FloatingActionButtonLocation.startFloat, // 按钮位置

注:投入 与 body 和 appBar对等级别,以及在 Scaffold下一步;还要修改按钮大小 container 摘要设置 container相当于设置按钮大小;


请注意下面的示例编写方法

import package:flutter/material.dart;
import package:flutter_app_3/pages/search.dart;

import ../pages/tabs/chat.dart;
import ../pages/tabs/find.dart;
import ../pages/tabs/mine.dart;
import ../pages/tabs/tel.dart;
import ../pages/search2.dart;

class BottomTemplate extends StatefulWidget {
  final int index; // 接收到的参数可以是 null
  const BottomTemplate({Key? key, this.index = 0}) : super(key: key);

  @override
  State createState() => _BottomTemplateState(this.index);
}

class _BottomTemplateState extends State {
  List pageList = [
    ChatPage(),
    TelPage(),
    Search2Page(),
    FindPage(),
    MinePage()
  ];
  int currentIndex = 0;
  String navigationBarName = 微信聊天页面;

  _BottomTemplateState(index) {
    this.currentIndex = index;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      drawer: Drawer(
        child: Center(
          child: ElevatedButton(
            onPressed: () {
              Navigator.of(context).pop();
              Navigator.of(context).pushNamed(/search2);
            },
            child: Text("跳转到 myapp 页面"),
          ),
        ),
      ),
      appBar: AppBar(
        title: Text(navigationBarName),
      ),
      floatingActionButton: Container(
        width: 60,
        height: 60,
        padding: EdgeInsets.all(8),
        decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(60.0),
          color: Colors.white,
          // border: Border.all(width: 1, color: Colors.green),
        ),
        child: FloatingActionButton(
          child: Icon(Icons.search),
          backgroundColor:
              this.currentIndex == 2 ? Colors.blue : Colors.grey.shade500,
          onPressed: () {
            setState(() {
              this.currentIndex = 2;
            });
          },
        ),
      ),
      floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
      body: pageList[currentIndex],
      bottomNavigationBar: BottomNavigationBar(
        type: BottomNavigationBarType.fixed, // 必须写两个以上 type
        currentIndex: currentIndex, // 目前,哪个页面下标从零开始
        fixedColor: Colors.blue, // 默认选择的颜色
        onTap: (int index) {
          setState(() {
            currentIndex = index;
            switch (index) {
              case 0:
                navigationBarName = "微信聊天页面";
                break;
              case 1:
                navigationBarName = "我的通讯录页面";
                break;
              case 2:
                navigationBarName = "搜索";
                break;
              case 3:
                navigationBarName = "发现页面";
                break;
              case 4:
                navigationBarName = "我页面";
                break;
            }
          });
        },
        items: const [
          // 底部按钮,每件物品
          BottomNavigationBarItem(
            icon: Icon(Icons.home_mini_sharp),
            label: "微信",
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.home_mini_sharp),
            label: "通讯录",
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.home_mini_sharp),
            label: "搜索",
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.home_mini_sharp),
            label: "发现",
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.home_mini_sharp),
            label: "我",
          ),
        ],
      ),
    );
  }
}

11.5 Flutter OutlinedButton

OutlinedButton(
  onPressed: () {},
  child: Text(OutlinedButton),
),

11.6 Flutter 中DropdownButton按钮(有待完善)

 DropdownButton(
  value: One,
  icon: const Icon(Icons.arrow_downward),
  elevation: 16,
  style: const TextStyle(color: Colors.deepPurple),
  underline: Container(
    height: 2,
    color: Colors.deepPurpleAccent,
  ),
  dropdownColor: Colors.red,
  items: [One, Two, Free, Four]
      .map>((String value) {
    return DropdownMenuItem(
      value: value,
      child: Text(
        value,
        style: const TextStyle(
          color: Colors.white,
        ),
      ),
    );
  }).toList(),
  onChanged: (String? s) {
    print(s);
  },
),

11.7 自定义按钮组件

1.定义按钮组件

class MyButton extends StatelessWidget {
  final double height;
  final double width;
  final text;
  final onPressed;
  MyButton(
      {this.height = 0, this.width = 0, this.text = , this.onPressed = null});

  @override
  Widget build(BuildContext context) {
    return Container(
      width: width,
      height: height,
      child: ElevatedButton(
        onPressed: onPressed,
        child: Text(text),
      ),
    );
  }
}

2.使用

MyButton(
    width: 300,
    height: 50,
    text: 我是一个定制按钮1,
    onPressed: () {
      print(我是一个由点击事件触发的自定义按钮。);
}),

版权声明

所有资源都来源于爬虫采集,如有侵权请联系我们,我们将立即删除