Flutter入门-组件学习

基础组件

  • Text
  • Button
    • ElevatedButton,漂浮按钮,默认有背景颜色、阴影效果,按下后阴影会变大。
    • TextButton,文本按钮,就是可点击的文本。默认背景透明、不带阴影,按下后会有背景色。
    • OutlineButton,边框按钮,默认有一个边框、背景透明、不带阴影,按下后边框颜色会变亮、出现背景(弱)、阴影(弱)。
    • IconButton,图标按钮,没有文字,默认没有背景,点击会出现背景。
    • FloatingActionButton,悬浮按钮
    • 自定义Button,所有的按钮都是直接或间接对RawMaterialButton组件的包装定制。
    • 说明:ElevatedButton、TextButton、OutlineButton都可以添加icon。
  • Image
  • Dialog
  • Date
  • 表单组件
    • TextField
    • Checkbox、CheckboxListTile
    • Radio、RadioListTile
    • Switch

Text

查看源代码
在这里插入图片描述

示例1

const Text("hello world")

示例2

const Text(
      "hello world",
      maxLines: 3,
      textAlign: TextAlign.center,
      style: TextStyle(color: Colors.black),
),

Button

查看源代码
在这里插入图片描述

示例1

ElevatedButton(
    onPressed: () {},
    style: ButtonStyle(
        //背景颜色
        backgroundColor: MaterialStateProperty.all(Colors.red),
        //字体颜色
        foregroundColor: MaterialStateProperty.all(Colors.white),
        //阴影颜色
        shadowColor: MaterialStateProperty.all(Colors.blue),
        //阴影大小
        elevation: MaterialStateProperty.all(20.0),
        //按钮圆角
        shape: MaterialStateProperty.all(
          RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
        )),
    child: const Text("按钮"),
  ),

示例2

TextButton(
      onPressed: () {},
      child: const Text("按钮"),
  ),

示例3

OutlinedButton(
    onPressed: () {},
    style: ButtonStyle(
        //字体颜色
        foregroundColor: MaterialStateProperty.all(Colors.black),
        //边框粗细、颜色
        side: MaterialStateProperty.all(
          const BorderSide(width: 1, color: Colors.red),
        )),
    child: const Text("按钮"),
  ),

示例4

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

示例5

FloatingActionButton(
      child: const Text("按钮"),
      onPressed: () {},
    ),

示例6,scaffold属性组件

floatingActionButton: FloatingActionButton(
        backgroundColor: Colors.red,
        onPressed: () {},
        child: const Icon(Icons.add),
      ),    

Image

示例1,加载网络图片

Image.network(
      "https://xxx.png",
      width: 100,
      height: 100,
      fit: BoxFit.cover, //使用最多。可能拉伸或裁剪,但是不会变形且填满容器。
      //repeat: ImageRepeat.repeatX,
    ),

示例2,加载本地图片

Image.asset('images/lc_farm1.jpeg', height: 100),

加载本地图片需要进行配置,同一张图片可以配置不同分辨率的,方便适配。

在这里插入图片描述

示例3,加载等比例图片

AspectRatio(
    aspectRatio: 16.0 / 9.0,
    child: Image.network(
      "https://www.itying.com/images/flutter/1.png",
      fit: BoxFit.cover,
    ),
  ),

Dialog

示例1:AlertDialog

 /*
   * showDialog是一个Future方法,也就是异步方法,我们可以使用async和await
   */
  void _alertDialog() async {
    var result = await showDialog(
        context: context,
        builder: (context) {
          return AlertDialog(
            title: const Text("提示信息"),
            content: const Text("确定删除吗?"),
            actions: [
              TextButton(
                  onPressed: () {
                    debugPrint("click 确定");
                    //pop可以传值,也可以不传值,传值的话可以传递状态给外面。
                    Navigator.of(context).pop("OK");
                  },
                  child: const Text("确定")),
              TextButton(
                  onPressed: () {
                    debugPrint("click 取消");
                    Navigator.of(context).pop("Cancle");
                  },
                  child: const Text("取消")),
            ],
          );
        });

    debugPrint("result=$result");
  }

在这里插入图片描述

示例2

/*
   *  如果需要在外部接收对话框的值,可以使用async和await来异步处理,使用pop传递点击结果。
   */
  void _simpleDialog() {
    showDialog(
        context: context,
        //点击对话框外面对话框是否消失,默认true
        barrierDismissible: true,
        builder: (context) {
          return SimpleDialog(
            title: const Text("请选择语言"),
            children: [
              SimpleDialogOption(
                child: const Text("简体中文"),
                onPressed: () {
                  debugPrint("简体中文");
                  Navigator.of(context).pop();
                },
              ),
              const Divider(),
              SimpleDialogOption(
                child: const Text("繁体中文"),
                onPressed: () {
                  debugPrint("繁体中文");
                  Navigator.of(context).pop();
                },
              ),
              const Divider(),
              SimpleDialogOption(
                child: const Text("英文"),
                onPressed: () {
                  debugPrint("英文");
                  Navigator.of(context).pop();
                },
              ),
            ],
          );
        });
  }

在这里插入图片描述

示例3:

/*
   *  如果需要在外部接收对话框的值,可以使用async和await来异步处理,使用pop传递点击结果。
   */
  void _bottomSheet() {
    showModalBottomSheet(
        context: context,
        builder: (context) {
          return SizedBox(
            height: 240,
            child: Column(
              children: [
                ListTile(
                  title: const Text("分享"),
                  onTap: () {
                    debugPrint("click 分享");
                    Navigator.of(context).pop();
                  },
                ),
                const Divider(),
                ListTile(
                  title: const Text("收藏"),
                  onTap: () {
                    debugPrint("click 收藏");
                    Navigator.of(context).pop();
                  },
                ),
                const Divider(),
                ListTile(
                  title: const Text("取消"),
                  onTap: () {
                    debugPrint("click 取消");
                    Navigator.of(context).pop();
                  },
                ),
              ],
            ),
          );
        });
  }

在这里插入图片描述

date

示例1,日期选择器

 void _showDatePicker() {
    showDatePicker(
      context: context,
      initialDate: DateTime.now(),
      firstDate: DateTime(2001),
      lastDate: DateTime(2050),
      //locale: const Locale('zh'),
    ).then((value) {
      debugPrint("获取选中的日期:$value");
    });
  }

在这里插入图片描述

示例2,时间选择器

void _showTimePicker() async {
    var result = await showTimePicker(
      context: context,
      initialTime: TimeOfDay.now(),
    );

    setState(() {
      if (result != null) {
        _choiceTime = result;
      }
    });
  }

在这里插入图片描述

表单型组件

示例1,Checkbox

child: Column(
    children: [
      Checkbox(
          value: c1,
          onChanged: (v) {
            setState(() => {c1 = v!});
          }),
      Text(c1 ? "选中" : "未选中"),
      CheckboxListTile(
        value: c1,
        onChanged: (v) => {
          setState(() => {c1 = v!})
        },
        title: const Text("标题"),
        subtitle: const Text("二级标题"),
      ),
      const Divider(height: 1.0),
      CheckboxListTile(
        value: c1,
        onChanged: (v) => {
          setState(() => {c1 = v!})
        },
        title: const Text("标题"),
        subtitle: const Text("二级标题"),
        //设置图片,类似ListTitle的leading属性
        secondary: const Icon(Icons.home),
      ),
    ],
  ),

示例2,Radio

Row(
      children: [
        const Text("男"),
        Radio(
            value: 1,
            groupValue: sex,
            onChanged: (v) {
              setState(() => {sex = v!});
            }),
        const Text("女"),
        Radio(
            value: 0,
            groupValue: sex,
            onChanged: (v) {
              setState(() => {sex = v!});
            }),
        const SizedBox(width: 50),
        Text("选中性别:${sex == 1 ? '男' : '女'}"),
      ],
    ),

示例3,RadioListtile

RadioListTile(
      value: 0,
      groupValue: choice,
      title: const Text("标题"),
      subtitle: const Text("二级标题"),
      secondary: const Icon(Icons.help),
      selected: choice == 0,
      onChanged: (v) {
        setState(() {
          choice = v!;
        });
      }),

示例4,switch

Switch(value: s1, onChanged: _switchChanged),

示例5,TextField

body: Column(
      children: [
        const SizedBox(height: 10),
        const MyTextFieldDemo(),
        const SizedBox(height: 10),
        TextField(
          decoration: const InputDecoration(hintText: "请输入用户名"),
          controller: username,
        ),
        TextField(
          obscureText: true,
          decoration: const InputDecoration(hintText: "请输入密码"),
          onChanged: (value) {
            password = value;
          },
        ),
        const SizedBox(height: 20),
        ElevatedButton(
            onPressed: () {
              debugPrint("用户名=${username.text},密码=$password");
            },
            child: const Text("按钮"))
      ],
    ),

容器类组件

  • 框架组件:
    • MaterialApp,程序入口组件
    • Scaffold,带主题样式标题栏的组件
  • 容器:
    • Container
    • SizeBox
  • Padding,给组件设置内边距,因为很多组件没有padding属性。
  • 流式布局:
    • Wrap
  • 线性布局:
    • Row,水平布局
    • Column,垂直布局
    • Expanded,在Row和Column中使用,弹性布局,均分/占满剩余空间
  • 层叠布局
    • Stack,层叠布局
    • Stack+Align,实现定位布局,本质还是层叠布局
    • Stack+Positioned,实现定位布局,本质还是层叠布局

Padding/Container/SizeBox

示例1,Padding

Padding(
  padding: EdgeInsets.fromLTRB(0, 0, 0, 5),
  child: Image.network(
    "https://www.itying.com/images/flutter/1.png",
  ),
),

示例2,Container

 SizedBox(height: 5),

示例3,Container

return Container(
      width: 100.0,
      height: 100.0,
      color: Colors.red,
      child: Center(
        child: Icon(
          icon,
          color: color,
          size: size,
        ),
      ),
    );

Row/Column/Expanded

示例1,Row

//自定义icon容器组件
class IconContainer extends StatelessWidget {
  double size = 32;
  Color color = Colors.white;
  IconData icon;
  IconContainer(this.color, this.size, this.icon);

  
  Widget build(BuildContext context) {
    return Container(
      width: 100.0,
      height: 100.0,
      color: Colors.red,
      child: Center(
        child: Icon(
          icon,
          color: color,
          size: size,
        ),
      ),
    );
  }
}


//使用Row进行布局
class HomeContent extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return Row(
      mainAxisAlignment: MainAxisAlignment.spaceEvenly, //均分空间
      children: [
        IconContainer(Colors.white, 32, Icons.home), //自定义组件
        IconContainer(Colors.white, 32, Icons.settings),
        IconContainer(Colors.white, 32, Icons.search),
      ],
    );
  }
}

示例2,Column

class HomeContent extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return Container(
      width: 2000,  //分配较大数值,就可以占满屏幕空间
      child: Column(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly, //均分空间
        crossAxisAlignment: CrossAxisAlignment.center, //重心
        children: [
          IconContainer(Colors.white, 32, Icons.home),
          IconContainer(Colors.white, 32, Icons.settings),
          IconContainer(Colors.white, 32, Icons.search),
        ],
      ),
    );
  }
}

示例3,Expanded,右侧固定大小,左侧自适应占满剩余空间,主要就是flex属性

class HomeContent extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return Row(
      children: [
        Expanded(
            child: IconContainer(Colors.black, Colors.red, 15, Icons.home),
            flex: 1),
        IconContainer(Colors.black, Colors.green, 15, Icons.home),
      ],
    );
  }
}

Wrap

示例

class HomeContent extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return Container(
      width: 500,
      height: 500,
      color: Colors.grey,
      child: Wrap(
        spacing: 10,
        runSpacing: 10,
        alignment: WrapAlignment.start,
        runAlignment: WrapAlignment.end,
        children: [
          MyButton('button1'),
          MyButton('button22222'),
          MyButton('button3'),
          MyButton('button4444'),
          MyButton('button5'),
          MyButton('button66666666'),
          MyButton('button1'),
          MyButton('button22222'),
          MyButton('button3'),
          MyButton('button4444'),
          MyButton('button5'),
          MyButton('button66666666'),
        ],
      ),
    );
  }
}

Stack

层叠布局,类似FrameLayout

class HomeContent extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return Center(
      child: Stack(
        alignment: Alignment.center,
        children: [
          Container(
            width: 300,
            height: 400,
            color: Colors.red,
          ),
          Text('我是文本'),
        ],
      ),
    );
  }
}

功能型组件

  • 列表
    • ListView,线性布局
    • GridView,网络布局
    • AnimatedList,动画列表,列表item增加删除时有动画效果
  • 图片轮播:Pageview
  • 固定宽高比:AspectRatio
  • 卡片:Card
  • 头像组件:CircleAvatar,显示为圆形的头像效果
  • 日期选择器和时间选择器:
    • showDatePicker()、DateTime.now()
    • showTimePicker()、TimeOfDay.now()
  • 对话框
    • 提示对话框,在showDialog中返回AlertDialog
    • 选择对话框,在showDialog中返回SimpleDialog
    • 底部对话框,在showModalBottomSheet中返回Widget
    • 自定义对话框,在showDialog中返回MyDialog
    • 说明:如果想获取对话框中的按钮点击状态,也就是点击了哪个按钮,可以使用async和await来异步获取,因为showDialog的返回值是一个Future类型的,是异步的。
  • 点击事件组件,InkWell,给组件包裹上,组件就有了点击事件。
  • 手势组件,GestureDetector,给组件包裹上,组件就有了单击事件、双击事件、长按事件等。

ListView

示例1,基本列表

return ListView(
  children: <Widget>[
    ListTile(
      title: Text('列表标题'),
      subtitle: Text('列表二级标题'),
    ),
    ListTile(
      title: Text('列表标题'),
      subtitle: Text('列表二级标题'),
    ),
    ListTile(
      title: Text('列表标题'),
      subtitle: Text('列表二级标题'),
    ),
  ],
);

示例2,图文混排列表

return ListView(
  children: <Widget>[
    ListTile(
      leading: Image.network(
        'https://xxx.png',
        width: 50,
        height: 50,
      ),
      title: Text('列表标题'),
      subtitle: Text('列表二级标题'),
    ),
    ListTile(
      leading: Image.network(
        'https://xxx.png',
        width: 50,
        height: 50,
      ),
      title: Text('列表标题'),
      subtitle: Text('列表二级标题'),
    ),
  ],
);

GridView

body: GridView.count(
        crossAxisCount: 2,
        crossAxisSpacing: 10.0,
        mainAxisSpacing: 10.0,
        padding: const EdgeInsets.all(10.0),
        children: _getListData(),
      ),

图片轮播

return Scaffold(
      appBar: AppBar(title: const Text("PageView")),
      body: PageView(
        scrollDirection: Axis.horizontal, //滑动的方向,默认水平
        children: [
          Center(child: Text("第一屏", style: Theme.of(context).textTheme.headline1)),
          Center(child: Text("第二屏", style: Theme.of(context).textTheme.headline1)),
          Center(child: Text("第三屏", style: Theme.of(context).textTheme.headline1)),
          Center(child: Text("第四屏", style: Theme.of(context).textTheme.headline1)),
        ],
      ),
    );

Scaffold属性组件

  • appBar,标题栏
  • floatingActionbar,悬浮按钮
  • bottomnavigationBar,底部导航栏
  • drawer,左抽屉
    • Drawer,抽屉组件
    • DrawerHeader,抽屉头部组件
    • UserAccountsDrawerHeader,专门定义用户信息的抽屉头部组件
  • endDrawer,右抽屉,同理
  • title,Tabbar,Tab导航,结合body设置TabBarView

标题栏

appBar: AppBar(title: const Text("PageView")),

Tab导航

import 'package:flutter/material.dart';

class TabBarSample1 extends StatelessWidget {
  const TabBarSample1({super.key});

  
  Widget build(BuildContext context) {
    return DefaultTabController(
        length: 2,
        child: Scaffold(
          appBar: AppBar(
            title: const Text("自定义APpBar"),
            bottom: const TabBar(tabs: [
              Tab(text: "热门"),
              Tab(text: "推荐"),
            ]),
          ),

          //TabbarView的children数量和顺序必须和TabBar对应
          body: TabBarView(children: [
            ListView(
              children: const [
                ListTile(title: Text("第一个tab")),
                ListTile(title: Text("第一个tab")),
                ListTile(title: Text("第一个tab")),
              ],
            ),
            ListView(
              children: const [
                ListTile(title: Text("第二个tab")),
                ListTile(title: Text("第二个tab")),
                ListTile(title: Text("第二个tab")),
              ],
            ),
          ]),
        ));
  }
}

在这里插入图片描述

底部导航

return Scaffold(
      body: _pageList[_currentIndex], //点击标签,显示不同的页面
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: _currentIndex,
        onTap: (index) {
          debugPrint("当前选择index:$index");
          setState(() {
            _currentIndex = index;
          });
        },
        iconSize: 30.0, //icon大小
        //fixedColor: Colors.red, //选中颜色
        //type: BottomNavigationBarType.fixed, //配置底部可以放多个按钮
        items: const [
          BottomNavigationBarItem(icon: Icon(Icons.home), label: "首页"),
          BottomNavigationBarItem(icon: Icon(Icons.category), label: "分类"),
          BottomNavigationBarItem(icon: Icon(Icons.settings), label: "设置"),
        ],
      ),
    );

在这里插入图片描述

抽屉

// ignore_for_file: prefer_const_constructors

import 'package:flutter/material.dart';

class DrawerPage extends StatelessWidget {
  const DrawerPage({super.key});

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("抽屉页面"),
      ),
      drawer: Drawer(
        child: Column(
          children: [
            const UserAccountsDrawerHeader(
              accountName: Text("章三"),
              accountEmail: Text("admin@gmail.com"),
              currentAccountPicture: CircleAvatar(
                backgroundImage: NetworkImage("https://xxx.png"),
              ),
              otherAccountsPictures: [
                CircleAvatar(backgroundImage: NetworkImage("https://xxx.png")),
                CircleAvatar(backgroundImage: NetworkImage("https://xxx.png")),
              ],
              decoration: BoxDecoration(
                image: DecorationImage(
                    image: NetworkImage(
                        "https://xxx.png"),
                    fit: BoxFit.cover),
              ),
            ),
            ListTile(leading: Icon(Icons.home), title: Text("主页")),
            Divider(),
            ListTile(
              leading: Icon(Icons.info),
              title: Text("用户中心"),
              onTap: () {
                Navigator.of(context).pop(); //关闭侧边栏
                Navigator.pushNamed(context, '/userCenter'); //跳转
              },
            ),
            Divider(),
            ListTile(leading: Icon(Icons.settings), title: Text("设置")),
            Divider(),
          ],
        ),
      ),
    );
  }
}

在这里插入图片描述