Flutter 基础知识入门

本文主要是积累记录flutter基础为目的,也可以当做字典翻阅,不断更新中,有好的建议也欢迎大家指正

一、组件

1.1、Text文本

1,import ‘package:flutter/material.dart’;为flutter sdk提供的组件

2,main方法可以写成箭头函数的方式

3,快速生成一个类:stless

import 'package:flutter/material.dart';

// void main() => runApp(MyApp());

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Welcome to Flutter',
      home:Scaffold(
        appBar: AppBar(
          title: Text('Hello World'),
        ),
        body: Center(
          child: Text('曾经沧海难为水,除却巫山不是云。曾经沧海难为水,除却巫山不是云。曾经沧海难为水,除却巫山不是云。曾经沧海难为水,除却巫山不是云。',
          textAlign: TextAlign.center,
          maxLines: 2,
          overflow: TextOverflow.ellipsis,
          style: TextStyle(
            fontSize: 30.0,
            color: Color.fromARGB(255, 255, 0, 255),
            decoration: TextDecoration.underline,
            decorationStyle: TextDecorationStyle.solid
          ),),
        ),
      )
    );
  }
}
image-20210824172107430

1.2、Container容器

Container相关属性

1,alignment子控件对其方式:

alignment: Alignment.center,

centerLeft、center、bottomLeft、bottomCenter、bottomRight、centerRight、topCenter、topLeft、topRight(前面是纵向,后面是横向)

alignment: const FractionalOffset(0.5,0.5),

FractionalOffset取值为0-1,这里的0.5相当于Alignment.center

2,width宽度 浮点或整数类型

double.infinity在撑满到父容器,相当于flex 1

width: double.infinity,

3,height高度 浮点或整数类型

4,color背景颜色

5,padding内边距:EdgeInsets.all所有方向边距,EdgeInsets.fromLTRB左上右下的边距

6,margin外边距,用法与padding一样

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Welcome to Flutter',
      home:Scaffold(
        appBar: AppBar(
          title: Text('Container容器'),
        ),
        body: Center(
          child: Container(
            child: new Text('Hello World', style: TextStyle(fontSize: 40),),
            alignment: Alignment.topLeft,
            width: 500,
            height: 400,
            color: Colors.blue,
            // padding: const EdgeInsets.all(10),
            padding: const EdgeInsets.fromLTRB(10, 100, 30, 40),
          ),
        ),
      )
    );
  }
}
image-20210824172018493

decoration修饰图片背景

1,渐变色:这里与color冲突,需要去掉color属性

2,border边框样式

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Welcome to Flutter',
      home:Scaffold(
        appBar: AppBar(
          title: Text('decoration修饰'),
        ),
        body: Center(
          child: Container(
            child: new Text('Hello World', style: TextStyle(fontSize: 40),),
            alignment: Alignment.topLeft,
            width: 500,
            height: 400,
            margin: const EdgeInsets.all(10),
            padding: const EdgeInsets.fromLTRB(10, 100, 30, 40),
            decoration: new BoxDecoration(
              gradient: const LinearGradient(colors: [Colors.pink,Colors.amber,Colors.limeAccent]),
              border: Border.all(width: 2,color: Colors.deepOrange)
            ),
          ),
        ),
      )
    );
  }
}
image-20210824172158717

1.3、Image图片

1.3.1、网络图片、本地资源

Image.network(网络图片)、Image.asset(本地资源)、Image.file(sd卡资源)、Image.memory

  • 网络图片
Container(
              child: new Image.network(
                'https://tva1.sinaimg.cn/large/008i3skNly1gtbnmq97aag30k814qb29.gif',
                fit: BoxFit.scaleDown,
                color: Colors.greenAccent,
                colorBlendMode: BlendMode.modulate,
              ),
              width: 300,
              height: 500,
              color: Colors.limeAccent,
            )
image-20210824172227448
  • asset资源

需要在pubspec.yaml中配置图片

image-20210825113116025
Image.asset(
                'images/140133.20138321_o.png',
                fit: BoxFit.scaleDown,
                color: Colors.greenAccent,
                colorBlendMode: BlendMode.modulate,
              )

如果不配置,打包时会出现这种问题

19C94EE7D2A043912F2FE7AC473049B7

2,fit属性:

contain:宽高适配其中一个,不变形,无裁切

fitWidth:宽度适配,不变形,高度裁切

fitHeight:高度适配,不变形,宽度裁切

fill:长宽适配,变形,无裁切

cover:长宽适配,不变形,裁切一个方向

3,混合模式

colorBlendMode配合color属性使用,起到颜色叠加等滤镜效果

1.3.2、repeat 属性

repeatX:横向重复

repeatY:纵向重复

repeat:横纵向重复

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Welcome to Flutter',
        home: Scaffold(
          appBar: AppBar(
            title: Text('Repeat属性'),
          ),
          body: Center(
            child: Container(
              child: new Image.network(
                'https://tva1.sinaimg.cn/large/008i3skNly1gtbnmq97aag30k814qb29.gif',
                fit: BoxFit.scaleDown,
                repeat: ImageRepeat.repeatX,
              ),
              width: 300,
              height: 500,
              color: Colors.limeAccent,
            ),
          ),
        ));
  }
}
image-20210824172301363

1.3.3、圆形头像

image-20210825171110151
方式一:Container容器

利用Container容器的decoration剪切

final first = Container(
      width: 300,
      height: 300,
      decoration: BoxDecoration(
        color: Colors.yellow, //设置方框背景颜色
//            borderRadius: BorderRadius.all(
//              Radius.circular(150)      //变成圆形,不过一般不这么实现圆形图片
//            ),
        borderRadius: BorderRadius.circular(150), //实现圆形图片的方式一:   有些麻烦
        image:
            DecorationImage(image: NetworkImage('http://img5.mtime.cn/mg/2021/08/24/110937.63038065_285X160X4.jpg'), fit: BoxFit.cover //铺满全屏
                ),
      ),
    );
方式二:ClipOval

使用系统提供的椭圆控件

final second = ClipOval(
      child: Image.network(
        'http://img5.mtime.cn/mg/2021/08/24/110937.63038065_285X160X4.jpg',
        height: 100,
        width: 100,
        fit: BoxFit.cover,
      ),
    );
方式三:CircleAvatar(推荐)

使用系统提供的头像圆形控件

final third = CircleAvatar(
      backgroundImage: new NetworkImage('http://img5.mtime.cn/mg/2021/08/24/110937.63038065_285X160X4.jpg'),
      radius: 100,
    );

1.4、ListView列表

Flutter使用new和不用new有啥区别?

  1. dart 1.x的时候,new是不能省略的。
  2. dart 2.x的时候,new是可选关键词,可以省略
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {

    return MaterialApp(
        title: 'Welcome to Flutter',
        home: Scaffold(
            appBar: AppBar(
              title: Text('ListView列表组件'),
            ),
            body: MyList()
        ));
  }
}

class MyList extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return ListView(
      children: [
        ListTile(
          leading: new Icon(Icons.ac_unit),
          title: new Text('ac_unit'),
        ),
        ListTile(
          leading: new Icon(Icons.memory),
          title: new Text('memory'),
        ),
        Image.network('https://tva1.sinaimg.cn/large/008i3skNly1gtbnmryeetj30wq0jagmn.jpg'),
        Image.network('https://tva1.sinaimg.cn/large/008i3skNly1gtbnmryeetj30wq0jagmn.jpg'),
      ],
    );
  }
}
image-20210824172339889

横向列表组件

scrollDirection: Axis.horizontal,

class MyList extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return ListView(
      scrollDirection: Axis.horizontal,
      children: [
        Container(
          width: 180,
          color: Colors.lightBlue,
        ),
        Container(
          width: 180,
          color: Colors.amber,
        ),
        Container(
          width: 180,
          color: Colors.deepOrange,
        ),
        Container(
          width: 180,
          color: Colors.deepPurple,
        ),
      ],
    );
  }
}
image-20210824172418760

构造函数参数传递,生成动态列表

1,dart里面列表使用list,使用List的generate方法动态赋值

List tempList=new List<String>.generate(100, (index) => "tempList $index");

2,MyApp({Key key})其中的key是默认必须要带的

3,@required注解表示字段必传

4,改动main函数里面的东西需要重新运行,否则会不生效或者报错

import 'package:flutter/material.dart';

void main() => runApp(MyApp(items: new List<String>.generate(100, (index) => "item $index")));

class MyApp extends StatelessWidget {
  final List<String> items;

  MyApp({Key key, @required this.items}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Welcome to Flutter',
        home: Scaffold(
            appBar: AppBar(
              title: Text('ListView动态列表'),
            ),
            body: new ListView.builder(
                itemCount: items.length,
                itemBuilder: (context, index) {
                  return new ListTile(
                    title: new Text('${items[index]}'),
                  );
                })));
  }
}
image-20210824171926335

1.5、GridView表格

常用GridView.count创建表格组件,属性解析:

1,crossAxisCount 每行数量

2,crossAxisSpacing 行内间距

3,mainAxisSpacing列内间距

4,childAspectRatio item的宽高比

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Welcome to Flutter',
        home: Scaffold(
            appBar: AppBar(
              title: Text('Grid表格布局'),
            ),
            body: GridView.count(
              crossAxisCount: 2,
              crossAxisSpacing: 2,
              mainAxisSpacing: 2,
              childAspectRatio: 1,
              // padding: const EdgeInsets.all(20),
              children: [
                Image.network('http://img5.mtime.cn/mg/2021/08/24/141454.81651527_285X160X4.jpg',fit: BoxFit.cover,),
                Image.network('http://img5.mtime.cn/mg/2021/08/24/134535.67957178_285X160X4.jpg',fit: BoxFit.cover,),
                Image.network('http://img5.mtime.cn/mg/2021/08/24/112722.60735295_285X160X4.jpg',fit: BoxFit.cover,),
                Image.network('http://img5.mtime.cn/mg/2021/08/24/110937.63038065_285X160X4.jpg',fit: BoxFit.cover,),
                Image.network('http://img5.mtime.cn/mg/2021/08/24/101606.96675436_285X160X4.jpg',fit: BoxFit.cover,),
                Image.network('http://img5.mtime.cn/mg/2021/08/24/094036.69360356_285X160X4.jpg',fit: BoxFit.cover,),
                Image.network('http://img5.mtime.cn/mg/2021/08/24/093233.40634890_285X160X4.jpg',fit: BoxFit.cover,),
                Image.network('http://img5.mtime.cn/mg/2021/08/24/090626.28438629_285X160X4.jpg',fit: BoxFit.cover,),
              ],
            )));
  }
}
image-20210824171756068

1.6、TextField文本输入框

flutter中文本输入框组件 TextField,下面举例一些常用的

1.6.1、ui样式

image-20210901151412340

上述组件的ui样式如下

var widget = TextField(
      // autofocus: true,                       //自动获取焦点
      // obscureText: true,                     //密码方式
      // maxLines: 4,                           //设置对最大行数(会撑大高度)
      decoration: InputDecoration(
        icon: Icon(Icons.people),               //在文本框前面加上图标
        prefixIcon: Icon(Icons.perm_identity),  //文本框内的图标
        labelText: "用户名",                     //特殊效果,输入信息时,用户名动态跑到边框届提示
        border: OutlineInputBorder(),           //给表单四周添加边框
        hintText: "请输入用户名",                 //提示文案
        hintStyle: TextStyle(
          color: Colors.grey,
        ),
      ),
    );

此外TextField还有以下构造参数

 const TextField({
    Key key,
    this.controller,    //编辑框的控制器,跟文本框的交互一般都通过该属性完成,如果不创建的话默认会自动创建
    this.focusNode,  //用于管理焦点
    this.decoration = const InputDecoration(),   //输入框的装饰器,用来修改外观
    TextInputType keyboardType,   //设置输入类型,不同的输入类型键盘不一样
    this.textInputAction,   //用于控制键盘动作(一般位于右下角,默认是完成)
    this.textCapitalization = TextCapitalization.none,
    this.style,    //输入的文本样式
    this.textAlign = TextAlign.start,   //输入的文本位置
    this.textDirection,    //输入的文字排列方向,一般不会修改这个属性
    this.autofocus = false,   //是否自动获取焦点
    this.obscureText = false,   //是否隐藏输入的文字,一般用在密码输入框中
    this.autocorrect = true,   //是否自动校验
    this.maxLines = 1,   //最大行
    this.maxLength,   //能输入的最大字符个数
    this.maxLengthEnforced = true,  //配合maxLength一起使用,在达到最大长度时是否阻止输入
    this.onChanged,  //输入文本发生变化时的回调
    this.onEditingComplete,   //点击键盘完成按钮时触发的回调,该回调没有参数,(){}
    this.onSubmitted,  //同样是点击键盘完成按钮时触发的回调,该回调有参数,参数即为当前输入框中的值。(String){}
    this.inputFormatters,   //对输入文本的校验
    this.enabled,    //输入框是否可用
    this.cursorWidth = 2.0,  //光标的宽度
    this.cursorRadius,  //光标的圆角
    this.cursorColor,  //光标的颜色
    this.keyboardAppearance,
    this.scrollPadding = const EdgeInsets.all(20.0),
    this.dragStartBehavior = DragStartBehavior.down,
    this.enableInteractiveSelection,
    this.onTap,    //点击输入框时的回调(){}
    this.buildCounter,
  })

1.6.2、多行文本框

image-20210907085755700
TextField(
  maxLines: 4,
  decoration: InputDecoration(
      hintText: '描述信息',
      border: OutlineInputBorder()
  ),
),

1.6.3、监听数据变化

监听数据变化: 即在TextEditingController的基础上添加监听即可

注意监听方法写在return前面,写在类里面会报错

_userEtController.addListener(() {
      print("controller的监听方法:"+_userEtController.text);
    });

1.6.4、赋值与set值

这里主要用到了TextField的controller属性以及TextEditingController控制器

首先TextField的数据是controller属性控制,输入框的值与TextEditingController的text字段双向绑定。

1,赋值:改变TextEditingController的text属性

2,set值:获取TextEditingController的text属性

Kapture 2021-09-01 at 14.10.03

源代码如下

import 'package:flutter/material.dart';

void main() => runApp(MaterialApp(
  home: TextFieldWidget(),
));
class TextFieldWidget extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _TextFieldState();
  }
}

class _TextFieldState extends State<TextFieldWidget> {
  TextEditingController _userEtController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("TextField"),
      ),
      body: Container(
        padding: EdgeInsets.all(10),
        child: Column(
          children: <Widget>[
            TextField(
              controller: _userEtController,
            ),
            RaisedButton(
              child: Text("赋值"),
              onPressed: () {
                setState(() {
                  _userEtController.text = "15937600635";
                });
              },
            ),
            RaisedButton(
              child: Text("获取值"),
              onPressed: () {
                setState(() {});
              },
            ),
            Text(_userEtController.text),
          ],
        ),
      ),
    );
  }
}

1.6.5、Overflow错误

flutter在使用TextField,软键盘弹出时候容易提示错误bottom overflowed by xxx PIXELS

image-20210901093733428

解决办法

SingleChildScrollView 包装一下,否则键盘弹出会报空间溢出

1.7、按钮组件

1.7.1、IconButton

展示icon的按钮

image-20210901173102134
IconButton(           //图标按钮
  icon: Icon(Icons.settings),
  onPressed: (){
  },
)

1.7.2、RaisedButton(过时)

设置文本的按钮 (过时,替代建议->ElevatedButton)

image-20210901171358566

常规属性有

RaisedButton(
  child: Text('RaisedButton'),
  //水波纹颜色
  splashColor: Colors.red,
  //背景颜色
  color: Colors.blue,
  //字体颜色
  textColor: Colors.white,
  //阴影
  elevation: 10,
  onPressed: () {},
),

另外可以设置圆角

RaisedButton(
  child: Text('圆角'),
  color: Colors.blue,
  textColor: Colors.white,
  shape: RoundedRectangleBorder(
      //圆角弧度
      borderRadius: BorderRadius.circular(10)),
  onPressed: () {},
),

也可以设置圆形,不过需要依赖于Container容器

Container(
  height: 80, //直径
  child: RaisedButton(
    child: Text('圆形'),
    color: Colors.blue,
    textColor: Colors.white,
    elevation: 20,
    shape: CircleBorder(side: BorderSide(color: Colors.white)),
    onPressed: () {},
  ),
),

设置按钮宽高

Container(
  //利用容器来设置按钮的宽度和高度
  height: 50,
  width: 300,
  color: Colors.blue,
  margin: EdgeInsets.all(50),    //外边距
  child: RaisedButton(
    child: Text('宽度高度宽度高度宽度高度宽度高度宽度高度宽度高度'),
    color: Colors.blue,
    textColor: Colors.white,
    elevation: 20,
    onPressed: () {},
  ),
),

1.7.3、ElevatedButton(替代上面)

image-20210903093227918
ElevatedButton(
  child: Text('ElevatedButton'),
  onPressed: () {},
),

1.7.4、RaisedButton.icon(过时)、ElevatedButton.icon

image-20210901172845301 image-20210903093110381

设置图标与文本的按钮 (过时,替代建议->ElevatedButton)

RaisedButton.icon(
  icon: Icon(Icons.search),
  label: Text('图标按钮'),
  color: Colors.blue,
  textColor: Colors.white,
  onPressed: (){
    print('图标按钮');
  },
),
ElevatedButton.icon(
  icon: Text('icon图标'),
  label: Text('label文本'),
  onPressed: () {},
)

1.7.6、FlatButton(过时)、TextButton

文本按钮 (过时,替代建议->TextButton)

image-20210903093855397
[
  TextButton(onPressed: () {}, child: Text('TextButton')),
  FlatButton(
    child: Text('扁平按钮'),
    color: Colors.blue,
    textColor: Colors.yellow,
    onPressed: () {},
  )
],

1.7.7、OutlineButton(过时)、OutlinedButton

带边框的文本按钮 (过时,替代建议->OutlinedButton)

Kapture 2021-09-03 at 09.45.39
[
  OutlineButton(
    child: Text('OutlineButton边框按钮'),
    onPressed: () {},
  ),
  OutlinedButton(
    child: Text('OutlinedButton边框按钮'), 
    onPressed: () {}
  ),
],

1.7.8、自定义按钮

自定义按钮主要是自己利用现有的组件封装

image-20210901173538811
class MyButton extends StatelessWidget {
  final text;
  final pressed;
  final double width;
  final double height;

  const MyButton(
      {this.text = "",
      this.pressed = null,
      this.width = 80.0,
      this.height = 30.0});

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

使用如下

MyButton(
  text: '自定义按钮',
  height: 60.0,
  width: 100,
  pressed: () {
    print('自定义按钮');
  })

1.8、AspectRatio组件(宽高比设定)

aspectRatio宽高比

AspectRatio(
  aspectRatio: 30/9,
  child: new Image.network(
'http://img5.mtime.cn/mg/2021/08/24/110937.63038065_285X160X4.jpg',
    fit: BoxFit.fill,
  ),
)

1.9、单选多选按钮

1.9.1、Radio单选按钮

Kapture 2021-09-07 at 09.15.15

Radio接收value(按钮值)、groupValue(当前外部数据)参数

import 'package:flutter/material.dart';

void main() => runApp(MaterialApp(
      home: FormDemoPage(),
    ));

class FormDemoPage extends StatefulWidget {
  @override
  _FormDemoPageState createState() => _FormDemoPageState();
}

class _FormDemoPageState extends State<FormDemoPage> {
  int sex = 1;

  //将单选组按钮的监听器抽离出来
  void _sexChanged(value) {
    setState(() {
      this.sex = value;
    });
  }

  List<Widget> _singleSelect() {
    List<Widget> tempList = [];
    tempList.add(Row(
      children: [
        Text('单选1'),
        Radio(
          value: 1,
          onChanged: this._sexChanged,
          groupValue: this.sex,
        ),
      ],
    ));
    tempList.add(Row(
      children: [
        Text('单选2'),
        Radio(
          value: 2,
          onChanged: this._sexChanged,
          groupValue: this.sex,
        )
      ],
    ));
    return tempList;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Radio单选按钮'),
      ),
      body: Padding(
        padding: EdgeInsets.all(20),
        child: Column(
          children: <Widget>[
            Wrap(
              children: this._singleSelect(),
            ),
          ],
        ),
      ),
    );
  }
}

1.9.2、RadioListTile单选按钮

Kapture 2021-09-07 at 10.50.00

RadioListTile在Radio基础上扩充了title、subtitle、secondary字段,代码:

import 'package:flutter/material.dart';

void main() => runApp(MaterialApp(
      home: RadioPage(),
    ));

class RadioPage extends StatefulWidget {
  @override
  _RadioPageState createState() => _RadioPageState();
}

class _RadioPageState extends State<RadioPage> {
  int singleSelect = 1;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('RadioListTile单选按钮'),
      ),
      body: Padding(
        padding: EdgeInsets.all(20),
        child: Column(
          children: <Widget>[
            RadioListTile(
              value: 1,
              onChanged: (v) {
                //Radio改变时,触发事件
                setState(() {
                  //重新渲染界面
                  this.singleSelect = v;
                });
              },
              groupValue: this.singleSelect,
              //如果这里的值是一样的,说明都是属于同一个人单选按钮组
              title: Text('标题'),
              subtitle: Text('这是二级标题'),
              secondary: Icon(Icons.settings),
              //设置:  图标
              selected: this.singleSelect == 1, //选中时,文字发亮
            ),
            RadioListTile(
              value: 2,
              onChanged: (v) {
                //Radio改变时,触发事件
                setState(() {
                  //重新渲染界面
                  this.singleSelect = v;
                });
              },
              groupValue: this.singleSelect,
              //如果这里的值是一样的,说明都是属于同一个人单选按钮组
              title: Text('标题'),
              subtitle: Text('这是二级标题'),
              secondary:
                  Image.network('https://tva1.sinaimg.cn/large/008i3skNly1gsz5k44d39j30ei0d2dfy.jpg'),
              //加载远程图片
              selected: this.singleSelect == 2, //选中时,文字发亮
            ),
          ],
        ),
      ),
    );
  }
}

1.9.3、CheckBox多选按钮

Kapture 2021-09-07 at 09.18.27
import 'package:flutter/material.dart';

void main() => runApp(MaterialApp(
      home: FormDemoPage(),
    ));

class FormDemoPage extends StatefulWidget {
  @override
  _FormDemoPageState createState() => _FormDemoPageState();
}

class _FormDemoPageState extends State<FormDemoPage> {
  int sex = 1; //默认1是男

  List multis = [
    {'checked': true, 'title': '多选1'},
    {'checked': false, 'title': '多选2'},
    {'checked': true, 'title': '多选3'},
  ];

  //多选
  List<Widget> _multiSelect() {
    List<Widget> tempList = [];
    for (var i = 0; i < this.multis.length; i++) {
      tempList.add(Row(
        children: <Widget>[
          Text(this.multis[i]['title'] + ":"),
          Checkbox(
            value: this.multis[i]['checked'],
            onChanged: (value) {
              setState(() {
                this.multis[i]['checked'] = value;
              });
            },
          )
        ],
      ));
    }
    return tempList;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Checkbox多选按钮'),
      ),
      body: Padding(
        padding: EdgeInsets.all(20),
        child: Column(
          children: <Widget>[
            Wrap(
              children: this._multiSelect(),
            ),
          ],
        ),
      ),
    );
  }
}

1.10、Switch开关

Switch控件接收value(boolean类型)、onChanged(数据改变回调)

Kapture 2021-09-07 at 10.56.52
import 'package:flutter/material.dart';

void main() => runApp(MaterialApp(
      home: RadioPage(),
    ));

class RadioPage extends StatefulWidget {
  @override
  _RadioPageState createState() => _RadioPageState();
}

class _RadioPageState extends State<RadioPage> {
  bool flag = true;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Switch开关'),
      ),
      body: Padding(
        padding: EdgeInsets.all(20),
        child: Column(
          children: <Widget>[
            Switch(
              //Android里的开关按钮
              value: this.flag,
              onChanged: (v) {
                setState(() {
                  print((v));
                  this.flag = v;
                });
              },
            )
          ],
        ),
      ),
    );
  }
}

二、布局

2.1、Row水平布局

Row水平布局组件:

1,子组件嵌套Expanded为灵活布局,子组件相当于加了权重1

2,子组件没有嵌套Expanded为不灵活布局,由子控件实际宽高决定大小

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Welcome to Flutter',
        home: Scaffold(
            appBar: AppBar(
              title: Text('水平布局'),
            ),
            body: new Row(
              children: [
                RaisedButton(
                  onPressed: () {},
                  color: Colors.redAccent,
                  child: new Text('red button'),
                ),
                Expanded(
                  child: RaisedButton(
                    onPressed: () {},
                    color: Colors.orangeAccent,
                    child: new Text('orange button'),
                  ),
                ),
                RaisedButton(
                  onPressed: () {},
                  color: Colors.redAccent,
                  child: new Text('red button'),
                ),
              ],
            )));
  }
}
image-20210824155249424

2.2、Column垂直布局

Column垂直布局组件:

1,与Row相反,用法一样

2,crossAxisAlignment:指定副轴对其方式

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Welcome to Flutter',
        home: Scaffold(
            appBar: AppBar(
              title: Text('垂直布局'),
            ),
            body: new Column(
              crossAxisAlignment: CrossAxisAlignment.end,
              children: [
                Text('I am Chinese.'),
                Expanded(child: Text('I am Chinese. I am Chinese.'),),
                Text('I am Chinese. I am Chinese. I am Chinese.'),
              ],
            )));
  }
}
image-20210824160640511

2.3、stack层叠布局

stack层叠布局,相当于css的position布局

1,这里alignment的FractionalOffset(0.5,0.5)等价于Alignment.center

2,CircleAvatar为圆形头像框

3,Positioned控件:用它包裹可以定位子组件位置

var stack = new Stack(
      // alignment: Alignment.center,
      alignment: const FractionalOffset(0.5, 0.5),
      children: [
        new CircleAvatar(
          backgroundImage: new NetworkImage(
              'http://img5.mtime.cn/mg/2021/08/24/110937.63038065_285X160X4.jpg'),
          radius: 100,
        ),
        new Container(
          decoration: new BoxDecoration(color: Colors.orangeAccent),
          padding: EdgeInsets.all(5),
          child: Text('头像测试'),
        ),
        new Positioned(
            bottom: 0,
            right: 0,
            child: new Text(
              '这个是第三层的Text组件',
              style: TextStyle(color: Colors.orange),
            ))
      ],
    );
image-20210824171701563

2.4、Card卡片布局

卡片布局

1,卡片布局也就是对布局左右加上了一点阴影

2,Divider()为横向的分割线

var card=Card(
      child: Column(
        children: [
          ListTile(
            title: Text('地址1',style: TextStyle(fontWeight: FontWeight.w500),),
            subtitle: Text('张三 13632432',style: TextStyle(fontWeight: FontWeight.w500),),
            leading: Icon(Icons.account_box),
          ),
          Divider(),
          ListTile(
            title: Text('地址1',style: TextStyle(fontWeight: FontWeight.w500),),
            subtitle: Text('张三 13632432',style: TextStyle(fontWeight: FontWeight.w500),),
            leading: Icon(Icons.account_box),
          ),
          Divider(),
          ListTile(
            title: Text('地址1',style: TextStyle(fontWeight: FontWeight.w500),),
            subtitle: Text('张三 13632432',style: TextStyle(fontWeight: FontWeight.w500),),
            leading: Icon(Icons.account_box),
          ),
          Divider(),
        ],
      ),
    );
image-20210824171614958

2.5、Drawer侧滑菜单

侧滑菜单用到了Drawer组件

脚手架组件Scaffold中添加drawer参数

import 'package:flutter/material.dart';

class SecondScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('drawer侧滑菜单'),
      ),
      body: new Container(
        child:new Center(
          child: new RaisedButton(
            onPressed: () {
              //关闭侧滑栏
              Navigator.pop(context);
            },
            child: new Text('返回'),
          ),
        ),
      ),
      drawer: new Drawer(
        child: new SecondScreen(),
      ),
    );
  }
}
Kapture 2021-08-31 at 19.45.47

三、路由导航

3.1、路由跳转

不带参数跳转

Navigator.push(context, MaterialPageRoute(builder: (context) => new SecondScreen()))

带参数跳转

final result = await Navigator.push(context, MaterialPageRoute(builder: (context) => ProductDetail(product: products[index])));

3.2、路由返回

不带参数返回

Navigator.pop(context);

带参数返回

Navigator.pop(context,"asdfasdfadsf");

demo示例:

import 'package:flutter/material.dart';

class Product {
  final String title;
  final String description;

  Product(this.title, this.description);
}

void main() {
  runApp(MaterialApp(
    title: '路由导航',
    home: ProductionList(
        products: List.generate(
            20, (index) => Product('商品$index', '这是一个商品详情,编号为$index'))),
  ));
}

class ProductionList extends StatelessWidget {
  final List<Product> products;

  const ProductionList({Key key, @required this.products}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('商品列表'),
      ),
      body: ListView.builder(
          itemCount: products.length,
          itemBuilder: (context, index) {
            return ListTile(
              title: Text(products[index].title),
              onTap: () async {
                String result = await Navigator.push(
                    context,
                    MaterialPageRoute(
                        builder: (context) =>
                            ProductDetail(product: products[index])));
                ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(result)));
              },
            );
          }),
    );
  }
}

class ProductDetail extends StatelessWidget {
  final Product product;

  const ProductDetail({Key key, @required this.product}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('${product.title}'),
      ),
      body: ListTile(
        title: Text('${product.description}'),
        onTap: () {
          Navigator.pop(context,'asdfadsf');
        },
      ),
    );
  }
}
Kapture 2021-08-25 at 11.13.59

四、安卓打包

4.1、androidstudio打包

使用androidstudio上的build打包,会生成apk、flutter-apk文件夹下的apk包65M

4.2、gradlew命令打包

使用gradlew命令打包,包大小也都是65M左右

./gradlew assembleDebug
./gradlew assembleRelease

4.3、flutter命令打包

使用flutter命令打包会生成apk,flutter-apk文件下的包18M

flutter build apk

五、toast与打印

5.1、打印

print('Hello world!');

[外链图片转存中…(img-W6wS4oiN-1631255381037)]

5.2、toast

pubspec.yaml添加dependencies依赖并拉去仓库代码

fluttertoast: ^8.0.8
flutter packages get

使用Toast提示与取消

Kapture 2021-09-03 at 09.57.21
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter Demo',
      home: new Scaffold(
        appBar: AppBar(
          title: Text('轮播图组件演示'),
        ),
        body: Column(
          children: [
            ElevatedButton(
              child: Text('toast'),
              onPressed: () {
                Fluttertoast.showToast(
                    msg: "This is Center Short Toast",
                    toastLength: Toast.LENGTH_SHORT,
                    gravity: ToastGravity.BOTTOM,
                    timeInSecForIosWeb: 1,
                    backgroundColor: Colors.black45,
                    textColor: Colors.white,
                    fontSize: 16.0);
              },
            ),
            ElevatedButton(
              child: Text('取消toast'),
              onPressed: () {
                Fluttertoast.cancel();
              },
            ),
          ],
        ),
      ),
    );
  }
}

六、事件通信

6.1、callback

我们可以通过传递一个callback给组件或者下一个页面,然后回调数据。例如在A页面传递callback函数

Navigator.push(
                    context,
                    MaterialPageRoute(
                        builder: (context) => ProductDetail(
                            product: products[index],
                            callback: (c, str) => {
                                  ScaffoldMessenger.of(c).showSnackBar(
                                      SnackBar(content: Text(str)))
                                })));

在B页面调用callback函数

callback(context, '123213');

全部代码

import 'package:flutter/material.dart';

class Product {
  final String title;
  final String description;

  Product(this.title, this.description);
}

void main() {
  runApp(MaterialApp(
    title: '路由导航',
    home: ProductionList(
        products: List.generate(
            20, (index) => Product('商品$index', '这是一个商品详情,编号为$index'))),
  ));
}

class ProductionList extends StatelessWidget {
  final List<Product> products;

  const ProductionList({Key key, @required this.products}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('商品列表'),
      ),
      body: ListView.builder(
          itemCount: products.length,
          itemBuilder: (context, index) {
            return ListTile(
              title: Text(products[index].title),
              onTap: () async {
                String result = await Navigator.push(
                    context,
                    MaterialPageRoute(
                        builder: (context) => ProductDetail(
                            product: products[index],
                            callback: (c, str) => {
                                  ScaffoldMessenger.of(c).showSnackBar(
                                      SnackBar(content: Text(str)))
                                })));
                ScaffoldMessenger.of(context)
                    .showSnackBar(SnackBar(content: Text(result)));
              },
            );
          }),
    );
  }
}

class ProductDetail extends StatelessWidget {
  final Product product;
  final Function callback;

  const ProductDetail(
      {Key key, @required this.product, @required this.callback})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('${product.title}'),
      ),
      body: ListTile(
        title: Text('${product.description}'),
        onTap: () {
          callback(context, '123213');
          Navigator.pop(context, 'asdfadsf');
        },
      ),
    );
  }
}

七、弹窗

flutter sdk中

1,dialog.dart提供了showDialog弹窗

2,bottom_sheet.dart提供了showModalBottomSheet弹窗

弹窗相当于一个页面,因此关闭弹窗的方法为

Navigator.pop(context, 'await回传数据');

7.1、dialog弹窗

Kapture 2021-09-05 at 18.14.56
_alertDialog() async {
  var result = await showDialog(
      //通过异步在外面获取值
      context: context,
      builder: (context) {
        return AlertDialog(
          //系统自带: 普通对话框
          title: Text('提示信息!'),
          content: Text('您确定要删除吗?'),
          actions: <Widget>[
            //监听器
            FlatButton(
              //确定监听
              child: Text('取消'),
              onPressed: () {
                print('取消');
                Navigator.pop(context, 'Cancle');
              },
            ),
            FlatButton(
              //取消监听
              child: Text('确定'),
              onPressed: () {
                print('确定');
                Navigator.pop(context, 'OK');
              },
            )
          ],
        );
      });

  print(result); //在外部获取数据并打印
}

7.2、bottom_sheet弹窗

Kapture 2021-09-05 at 18.31.42
_modelBottomSheet() async {
  var result = await showModalBottomSheet(
      context: context,
      builder: (context) {
        return Container(
          height: 250, //配置底部弹出框高度
          child: Column(
            children: <Widget>[
              ListTile(
                title: Text('分享 A'),
                onTap: () {
                  Navigator.pop(context, '分享A');
                },
              ),
              Divider(),
              ListTile(
                title: Text('分享 B'),
                onTap: () {
                  Navigator.pop(context, '分享B');
                },
              ),
              Divider(),
              ListTile(
                title: Text('分享 C'),
                onTap: () {
                  Navigator.pop(context, '分享C');
                },
              ),
            ],
          ),
        );
      });
  print(result);
}
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

流星雨在线

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值