美文网首页
Flutter基础控件篇[1]

Flutter基础控件篇[1]

作者: zhangyu1991 | 来源:发表于2020-04-17 20:05 被阅读0次
    前言

    拖了好久终于开始看Flutter,为了加深印象巩固学习效果,现将每次学习的内容总结成笔记,巩固效果也方便以后查阅。同时,笔记相关的Demo项目已经上传到Github,这里是传送门,欢迎指正。

    正文
    Flutter相关文档

    1.官方文档
    2.Flutter中文网
    3.官方Demo(Github地址)

    基础控件目录

    官方基础控件目录

    常用基础控件

    不管在哪个前端平台,常用的基础控件都一样,大致包括:文本、图片、按钮、输入框、进度条、单选框和复选框、开关切换(Switch)、提示窗、对话框;布局用的控件(Layout)基本包含:横向布局、纵向布局、格子布局、重叠布局、各类包含不同约束条件的特定布局(内外间距,靠边居中,相对位置等);然后是一些根据常用程度封装的控件包括:列表控件、滑动控件(横纵方向),下拉刷新,抽屉(Drawer)等。

    然后在Flutter中,控件分为StatefulWidget和StatelessWidget(有状态控件和无状态控件),无状态控件是死的,不会动态更新,所以实际使用的时候大多数情况下都是封装自己的StatefulWidget,StatefulWidget的状态存储在对应的State类里面,需要更新的时候可以通过调用setState()方法来刷新页面。
    StatefulWidget基本代码模板如下:

    class DemoStatefulWidget extends StatefulWidget{
      @override
      State<StatefulWidget> createState() {
        return DemoState();
      }
    }
    
    class DemoState extends State<DemoStatefulWidget>{
      var data;
      @override
      Widget build(BuildContext context) {
        return Text(data);
      }
    
      void onDataChanged(newData){
        setState(() {//刷新控件
          data = newData;
        });
      }
    }
    

    接下来,按照上面梳理出的常用控件,我们一个一个来看。

    文本 Text

    Text官方文档
    没啥注意点,属性看文档基本都能看懂。
    基本使用

    Widget build(BuildContext context) {
        return new Text(
          "A text in container",
          style: new TextStyle(
              color: Color(0xFF0000CD), fontStyle: FontStyle.normal, fontSize: 15),
        );
      }
    
    图片 Image

    Image官方文档
    也没啥注意点。
    基本使用

    Widget build(BuildContext context) {
        return Image.network(//图片来自网络
          imageUrl,
          width: 200.0,
          height: 150.0,
        );
    //    Image.asset(name);//图片来自项目内的资源
    //    Image.file(file);//图片来自文件
    //    Image.memory(bytes);//图片来自内存
      }
    
    按钮 RaisedButton FlatButton

    这两个按钮除了风格不同以外没什么别的区别,只有个别属性彼此有区分。
    RaisedButton官方文档
    FlatButton官方文档

    Widget build(BuildContext context) {
        return RaisedButton(
          elevation: 5,
          color: Color(0xff87CEFA),
          child: Text("Print"),
          onPressed: () {}
        );
      }
    
    输入框 TextField

    TextField官方文档
    基本使用

    Widget build(BuildContext context) {
        return TextField(
          maxLines: 5,
          style: TextStyle(color: Colors.black),
          controller: editController,
          obscureText: false,
          decoration: InputDecoration(
            border: OutlineInputBorder(),
            labelText: 'Text',
          )
        );
    
    进度条 Slider

    Slider官方文档
    注意点:
    dividions属性,比如设置dividions属性为4,进度条被分为四等分,滑动时进度会停留在等分点上;
    label属性,设置之后,滑动时,标签将展示在进度条上;
    效果如下:

    Slider
    代码:
    Widget build(BuildContext context) {
        return Slider(
          label: 'slider',
          value: rating,
          divisions: 4,
          onChanged: (newValue) {
            setState(() {
              rating = newValue;
            });
            print('rating: ${rating}'); //打日志到控制台)
          },
        );
    
    CheckBox

    很简单没啥要注意的。
    CheckBox官方文档

    Widget build(BuildContext context) {
        return Container(
          padding: EdgeInsets.fromLTRB(0.0, 10, 0, 10),
          margin: EdgeInsets.fromLTRB(0, 10, 15, 10),
          alignment: Alignment(-1, 0),
          //min和max为最小进度值和最大进度值,不设置的话默认为0到1
          child: Slider(
            inactiveColor: Colors.cyan[100],
            activeColor: Colors.cyan[400],
            min: 0,
            max: 2,
            label: 'slider',
            value: rating,
            onChanged: (newValue) {
              setState(() {
                rating = newValue;
              });
              print('rating1: ${rating}'); //打日志到控制台)
            },
          ),
        );
      }
    
    Radio

    Radio官方文档
    这个看文档有点迷糊,而且这个使用和Android的不一样。
    这里要注意的是value和groupValue两个属性,value是当这个Radio选中的时候更新到onChange方法里的值,groupValue是,当它的值和value的值相同时,这个Radio就是选中状态,否则就是非选中状态。所以一般使用时都是把groupValue的值设定为一个动态变量,然后在onChange方法里更新这个动态变量。
    基本使用

    Widget build(BuildContext context) {
        
        return Column(
            mainAxisAlignment: MainAxisAlignment.start,
            mainAxisSize: MainAxisSize.max,
            crossAxisAlignment: CrossAxisAlignment.start,
            //靠左
            verticalDirection: VerticalDirection.down,
            children: <Widget>[
              Container(
                  margin: EdgeInsets.fromLTRB(0, 10, 15, 0),
                  child:
                  Text('Radio:')),
              Row(
                children: <Widget>[
                  Text('1'),
                  Radio(
                    value: '1',
                    groupValue: this.radioSelectedPosition,
                    onChanged: (radioChange) {
                      setState(() {
                        this.radioSelectedPosition = radioChange;
                      });
                      print('radioChange1: ${radioChange}'); //打日志到控制台)
    
                    },
                  ),
                ],
              ),
              Row(
                children: <Widget>[
                  Text('2'),
                  Radio(
                    value:'2',
                    groupValue: this.radioSelectedPosition,
                    onChanged: (radioChange) {
                      setState(() {
                        this.radioSelectedPosition = radioChange;
                      });
                      print('radioChange2: ${radioChange}'); //打日志到控制台)
                    },
                  ),
                ],
              ),
              Row(
                children: <Widget>[
                  Text('3'),
                  Radio<String>(
                    value: '3',
                    groupValue: this.radioSelectedPosition,
                    onChanged: (radioChange) {
                      setState(() {
                        this.radioSelectedPosition = radioChange;
                      });
                      print('radioChange3: ${radioChange}'); //打日志到控制台)
                    },
                  ),
                ],
              ),
            ]);
      }
    

    效果:


    Radio
    Switch

    Switch官方文档

    Widget build(BuildContext context) {
        return Switch(
          activeColor: Colors.deepOrange[300],
          activeTrackColor: Colors.deepOrange[600],
          inactiveTrackColor: Colors.blue[300],
          inactiveThumbColor: Colors.blue[100],
          inactiveThumbImage: NetworkImage(imageUrl),
          value: switchOn,
          onChanged: (switchOn){
            setState(() {
              this.switchOn = switchOn;
              print('switchOn: ${switchOn}'); //打日志到控制台)
            });
          },
        );
      }
    
    最后,有一个重要而且特别的属性

    在看第一个控件的时候,我就注意到这个属性,key,排在第一位。简单看文档看不明白到底是做什么用的,然后往下看的时候我注意到每一个控件都有key这个属性,而且都是排在第一位。于是我去查看了官方文档,结果我的个乖乖,开头就是一个整整10分钟的讲解视频,由于视频是全英文的并且字幕翻译的并不好,我反复看了三遍,才大致摸清楚了key的含义和用法。
    要理解这个key的使用必须要对Flutter的控件树刷新机制有简单的了解。Flutter在构建Widget树的时候,同时会构建一个Element树,这个Element树才是显示和刷新页面的时候真正起作用的东西,Widget里面只是存了一些控件的属性值而已。在刷新Element树的时候,Flutter会依次对比每个控件的改变状态,首先是检查type,如果两个控件是相同的类型,type就是一样的,然后是检查key,比如你交换了页面中两个Text的位置,改变了Widget树的结构,如果此时你对这个控件设置了key,它会检查出前后状态下控件的key不一样,会判定这里有修改,然后Flutter会去遍历和刷新Element树,将它调整到正确的交换后的状态,否则的话,由于两个Text的type是一样的,Flutter检查之后会认为Element树没有必要刷新,此时就会出现错误,你会发现你交换控件之后页面上两个文本没有丝毫改变,如果你不了解这个机制的话,这个错误会显得莫名其妙并且完全摸不着头脑。
    然后,key还包括ValueKey、LocalKey、GlobleKey,各种场景下适合使用的类型不相同,详细可见官方文档。然后后来找到一篇文章,基本很详细的把官方视频要阐述的内容解释清楚了,好文传送门

    尾声

    以上,第一部分暂时整理这么多,接下来空余时间再逐步梳理剩下的控件,预计整个常用控件的梳理大概要分3篇笔记。个人从零逐步学习Flutter,水平有限,如发现问题,欢迎斧正!

    相关文章

      网友评论

          本文标题:Flutter基础控件篇[1]

          本文链接:https://www.haomeiwen.com/subject/vjermhtx.html