美文网首页Android开发Android开发手机移动程序开发
Flutter第4天--基础控件(下)+Flex布局详解

Flutter第4天--基础控件(下)+Flex布局详解

作者: e4e52c116681 | 来源:发表于2018-12-19 20:06 被阅读10次

    Flutter七日游第四天:2018-12-19 天气:晴朗

    零、前言

    最近有些人问我怎么学的,操作这么6,有没有什么技巧。
    今天一开始借助Image来给大家说一个分析的小技巧,让你不到30行代码画出下图
    不要问有什么用,有用的时候自然会用到,有知识储备,留个印象也是好的

    图片的颜色混合模式.png

    Row和Column应该说是非常常用的控件,其中有几个属性挺重要,
    本文最后,我将对Flex布局(Row和Column的父类)进行细致的讲解,希望你不要错过。


    一、第一组控件:

    第一组.png
    1.图片Image
    图片的使用.png
    1.1源码一览:

    下面是我从源码里翻译的,仅供参考

      const Image({
        Key key,
    ImageProvider       @required this.image,----图片提供器
    double              this.width,----宽
    double              this.height,----高
    Color               this.color,----颜色
    BoxFit              this.fit,----适应模式
    colorBlendMode      this.colorBlendMode,----颜色混合模式
    AlignmentGeometry   this.alignment = Alignment.center,----对齐模式
    ImageRepeat         this.repeat = ImageRepeat.noRepeat,----重复模式
    String              this.semanticLabel,----语义标签
    bool                this.excludeFromSemantics = false,----是否从语义中排除该图像
    Rect                this.centerSlice,----.9图的中心区域切片
    bool                this.matchTextDirection = false,----是否匹配文字分析
    bool                this.gaplessPlayback = false,----图片提供器改变
    FilterQuality       this.filterQuality = FilterQuality.low,---过滤器品质
    

    1.2:优雅地查看:图片的适应模式--BoxFit

    也许你为了查看模式,改一次,看一次,千万不要这样,即费时间,比较的效果又差
    你需要学会用数组或map去动态生成,让变化去应对变化,才能以不变应万变。
    下面的效果呈现,也就用了十几行代码而已,而且准确地表述了BoxFit的各种情况

    图片的适应模式.png
    var fitMode = [BoxFit.none,BoxFit.contain, BoxFit.cover,
      BoxFit.fill, BoxFit.fitHeight,BoxFit.fitWidth,BoxFit.scaleDown];
    
    //循环生成Image控件
    formImgs() {
      var imgLi = <Widget>[];
      fitMode.forEach((fit) {
        imgLi.add(Container(
            width: 100,
            height: 50,
            color: randomRGB(),
            child: Image(
              image: AssetImage("images/wy_200x300.jpg"),
              fit: fit,
            )));
      });
      return imgLi;
    }
    
    var imgBox = Row(
      children: formImgs(),
    );
    

    1.3:优雅地查看:颜色混合模式--colorBlendMode

    晕死---29种叠合模式,Android一共也才18个,Flutter还真会找事...
    那么多情况,Row肯定不够使,想想昨天的卡片,Wrap能当此大任

    //叠合模式数组
    var colorBlendMode = [
      BlendMode.clear,BlendMode.src,BlendMode.dst,
      BlendMode.srcOver,BlendMode.dstOver,BlendMode.srcIn,
      BlendMode.dstIn,BlendMode.srcOut,BlendMode.dstOut,
      BlendMode.srcATop,BlendMode.dstATop,BlendMode.xor,
      BlendMode.plus, BlendMode.modulate,BlendMode.screen,
      BlendMode.overlay,BlendMode.darken,BlendMode.lighten, 
      BlendMode.colorDodge,BlendMode.colorBurn,BlendMode.hardLight,
      BlendMode.softLight,BlendMode.difference,BlendMode.exclusion,
      BlendMode.multiply,BlendMode.hue,BlendMode.saturation,
      BlendMode.color, BlendMode.luminosity,
    ];
    
    //循环生成Image控件
    formImgsColorBlendMode() {
      var imgLi = <Widget>[];
      colorBlendMode.forEach((mode) {
        imgLi.add(Column(children: <Widget>[
          Padding( child:Image(
            width: 60,
            height: 60,
            image: AssetImage("images/icon_90.png"),
            color: Colors.red,
            colorBlendMode: mode,
          ), padding: EdgeInsets.all(5),),
          Text(mode.toString().split(".")[1])
        ]));
      });
      return imgLi;
    }
    
    var imgBox = Wrap(
      children: formImgsColorBlendMode(),
    );
    

    一共就这些代码,就能实现下面的效果,Android也好,Flutter也好,套路都是一样的
    当你遇到很多种情况的问题时,都可以用这个套路,多分析,你才能巩固自己的知识库

    图片的颜色混合模式.png

    重复模式,脑子想想也就知道了,这里就不演示了


    1.4:使用Image的方法加载图片

    这个等到文件读取再提一下,基本字段和Image是一样的,所以不用担心。

    资源:Image.asset(String name,
    文件:Image.file(File file,
    网络:Image.network(String src,
    内存:Image.memory(Uint8List bytes,
    

    2.IconButton
    2.1源码一览:
      const IconButton({
    double                  this.iconSize = 24.0,
    EdgeInsetsGeometry      this.padding = const EdgeInsets.all(8.0),
    AlignmentGeometry       this.alignment = Alignment.center,
    Widget                  @required this.icon,
    Color                   this.color,
    Color                   this.highlightColor,
    Color                   this.splashColor,
    Color                   this.disabledColor,
    VoidCallback            @required this.onPressed,
    String                  this.tooltip
    

    2.2简单操作
    IconButton.gif
    var iconBtn = IconButton(
      padding: EdgeInsets.only(),
      onPressed: () {
        print("clicked");
      },
      icon: Icon(Icons.android, size: 40, color: Colors.deepPurpleAccent),
      tooltip: "android",
      highlightColor: Colors.red,//点击时间稍长的时候背景渐变到这个颜色
      splashColor: Colors.blue,//点击时一闪而过的颜色
      disabledColor: Colors.blueGrey,
    );
    

    3.ButtonBar
    3.1源码一览:
    const ButtonBar({
        Key key,
        this.alignment = MainAxisAlignment.end,
        this.mainAxisSize = MainAxisSize.max,
        this.children = const <Widget>[],
    

    3.2简单操作
    BottonBar使用.png
    var btnBar = ButtonBar(
      alignment: MainAxisAlignment.center,
      children: <Widget>[iconBtn,iconBtn,iconBtn,iconBtn],
    );
    
    卡片拆包:
    - - -

    二、第二组控件:

    第二组.png

    这一组都继承自MaterialButton,所以属性几乎一致,这里看一下MaterialButton
    经历了这么多控件,属性基本上都差不多,看到名字也知道大概意思。

      const MaterialButton({
        @required this.onPressed,----点击事件----VoidCallback
        this.onHighlightChanged,
        this.textTheme,----按钮文字主题----ButtonTextTheme
        this.textColor,----文字颜色----Color
        this.disabledTextColor,----不可用时文字颜色----Color
        this.color,----背景颜色----Color
        this.disabledColor,----
        this.highlightColor,----
        this.splashColor,----
        this.colorBrightness,
        this.elevation,-----阴影高----
        this.highlightElevation,
        this.disabledElevation,
        this.padding,-----内边距----
        this.shape,-----形状----
        this.clipBehavior = Clip.none,
        this.materialTapTargetSize,
        this.animationDuration,
        this.minWidth,
        this.height,
        this.child,
    

    1.RaisedButton--凸起的按钮

    RaisedButton和Android的内置Button基本上是一致的

    1.1源码一览:
      const RaisedButton({
        @required VoidCallback onPressed,
        ValueChanged<bool> onHighlightChanged,
        ButtonTextTheme textTheme,
        Color textColor,
        Color disabledTextColor,
        Color color,
        Color disabledColor,
        Color highlightColor,
        Color splashColor,
        Brightness colorBrightness,
        double elevation,
        double highlightElevation,
        double disabledElevation,
        EdgeInsetsGeometry padding,
        ShapeBorder shape,
        Clip clipBehavior = Clip.none,
        MaterialTapTargetSize materialTapTargetSize,
        Duration animationDuration,
        Widget child,
    

    1.2简单操作
    RaisedButton
    var raisedButton = RaisedButton(
      onPressed: () {},
      child: Text("Toly"),
      color: Color(0xffF88B0A),
      highlightColor: Colors.blue,
    );
    
    

    2.FlatButton--平的按钮

    FlatButton相当于精简版的RaisedButton,没有阴影凸起效果
    可见源码里关于elevation都被过滤了

    2.1源码一览:
      const FlatButton({
        Key key,
        @required VoidCallback onPressed,
        ValueChanged<bool> onHighlightChanged,
        ButtonTextTheme textTheme,
        Color textColor,
        Color disabledTextColor,
        Color color,
        Color disabledColor,
        Color highlightColor,
        Color splashColor,
        Brightness colorBrightness,
        EdgeInsetsGeometry padding,
        ShapeBorder shape,
        Clip clipBehavior = Clip.none,
        MaterialTapTargetSize materialTapTargetSize,
        @required Widget child,
    

    2.2简单操作
    FlatButton.gif
    var flatButton = FlatButton(
      onPressed: () {},
      child: Text("Toly"),
      color: Color(0xffF88B0A),
      highlightColor: Colors.blue,
      textColor: Color(0xffFfffff),
    );
    

    3.OutlineButton--框按钮

    OutlineButton是一个框型按钮

    3.1源码一览:
     const OutlineButton({
        Key key,
        @required VoidCallback onPressed,
        ButtonTextTheme textTheme,
        Color textColor,
        Color disabledTextColor,
        Color color,
        Color highlightColor,
        Color splashColor,
        double highlightElevation,
        this.borderSide,
        this.disabledBorderColor,
        this.highlightedBorderColor,
        EdgeInsetsGeometry padding,
        ShapeBorder shape,
        Clip clipBehavior = Clip.none,
        Widget child,
    

    3.2简单操作
    OutlineButton.gif
    var outLineButton = OutlineButton(
      onPressed: () {},
      child: Text("Toly"),
      color: Color(0xffF88B0A),
      highlightColor: Colors.blue,
      textColor: Color(0xff000000),
      borderSide: BorderSide(color: Color(0xff0A66F8), width: 2),
    );
    
    卡片拆包:
    - - -

    三、第三组控件:

    第三组.png

    这组效果如下:好像听到:
    汽车人变形,然后AppBar说:我来组成头部;TabBarView说:我来组成身体,BottomNavigationBar说:我来组成脚部


    1.TabBar--标签Bar

    RaisedButton和Android的内置Button基本上是一致的

    1.1源码一览:
      const TabBar({
        Key key,
        @required this.tabs,
        this.controller,
        this.isScrollable = false,
        this.indicatorColor,
        this.indicatorWeight = 2.0,
        this.indicatorPadding = EdgeInsets.zero,
        this.indicator,
        this.indicatorSize,
        this.labelColor,
        this.labelStyle,
        this.labelPadding,
        this.unselectedLabelColor,
        this.unselectedLabelStyle,
    

    1.2:实现方法
    TabBar测试.png
    var tabBar = TabBar(
      labelStyle: TextStyle(fontSize: 20),
      labelColor: Color(0xffF64C19),
      unselectedLabelColor: Colors.white,
      tabs: chartLi.map((item) {
        return Container(
          alignment: AlignmentDirectional.center,
          child: Text(item),
          height: 40,
        );
      }).toList(),
    );
    
    //注意一点:主页的Scaffold标签要让DefaultTabController包一下,否则会报错
       home: new DefaultTabController(
            child:scaffold, 
            length: 4))
    
    //并且我将tabBar放在了AppBar的下面,这样好看一点(当然你可以随意放)
        var scaffold= Scaffold(
          appBar: AppBar(
              title: Text("张风捷特烈"),
              bottom:tabBar,
              backgroundColor: Color(0xff54C5F8),
              elevation: 12,
              centerTitle: true,
              toolbarOpacity: .4), //透明度
        );
    

    2.TabBarView
    2.1源码一览:
      const TabBarView({
        Key key,
        @required this.children,
        this.controller,
        this.physics,
    

    2.2简单操作
    var chartLi = ["About", "Ball", "Card", "Dog"];
    
    var tabBarView = new TabBarView(
      children: chartLi.map((text) {
        return new Center(
            child: new Text(text, style: TextStyle(fontSize: 20),
        ));
      }).toList(),
    );
    

    3.BottomNavigationBar--底部Bar

    OutlineButton是一个框型按钮

    3.1源码一览:
      BottomNavigationBar({
        Key key,
        @required this.items,
        this.onTap,
        this.currentIndex = 0,
        BottomNavigationBarType type,
        this.fixedColor,
        this.iconSize = 24.0,
    

    3.2简单操作
    底栏.png
    var bottomNavigationBar = BottomNavigationBar(
      items: () {
        var items = <BottomNavigationBarItem>[];
        iconInfoMap.forEach((k, v) {
          items.add(BottomNavigationBarItem(
              title: Text(k), icon: v, backgroundColor: Color(0xff49B1FB)));
        });
        return items;
      }(),
      currentIndex: 1,
      onTap: (position) {
        print(position);
      },
    );
    
    //由脚手架将汽车人组合
        var scaffold= Scaffold(
          appBar: AppBar(title: Text("张风捷特烈"),
              bottom:tabBar), 
          body: tabBarView,
          bottomNavigationBar: bottomNavigationBar,
        );
    
    - - -

    第四组:这组有点坑

    第四组.png
    1.Drawer:我来组成左臂
    1.1源码一览:
      const Drawer({
        Key key,
        this.elevation = 16.0,
        this.child,
        this.semanticLabel,
    

    1.2:实现方法
    drawer.gif
    var draw = Drawer(
        elevation: 5,
        child: Container(
          alignment: AlignmentDirectional.center,
          color: Color(0xff99C6F9),
          child: Text(
            "张风捷特烈",
            style: TextStyle(fontSize: 30),
          ),
        ));
    
    
    //Scaffold组合
    var scaffold= Scaffold(
      appBar: AppBar(title: Text("张风捷特烈"),
          bottom:tabBar), 
      body: tabBarView,
      drawer: draw,
      bottomNavigationBar: bottomNavigationBar,
    );
    

    2.SnackBar
    2.1源码一览:
      const SnackBar({
        Key key,
        @required this.content,
        this.backgroundColor,
        this.action,
        this.duration = _kSnackBarDisplayDuration,
        this.animation,
    

    2.2简单操作
    SnackBar.gif
    var snackBar = SnackBar(
        backgroundColor: Color(0xffFB6431),
        content: Text('Hello!'),
        duration: Duration(seconds: 1),
        action: SnackBarAction(
            label: '确定',
            onPressed: () {
              print("张风捷特烈");
            }));
    
    //坑点来了,笔记记好---------------
    //一开始打开总是报错,貌似是context的锅,百度了一下,已经有人填坑了,
    //需要Scaffold的context,而不是我认为的那个context
    
      var scContext;//先声明一下Scaffold的context
      
      @override
      Widget build(BuildContext context) {
        var scaffold = Scaffold(
          appBar: AppBar(//同前,略...),
          //Scaffold的context通过Builder来获取
          body: Builder(builder: (context) {
            scContext = context;
            return tabBarView;
          }),
          drawer: draw,
          bottomNavigationBar: bottomNavigationBar,
    
          floatingActionButton: FloatingActionButton(
            onPressed: () {
              Scaffold.of(scContext).showSnackBar(snackBar);//这样就行了
            },
            tooltip: 'Increment',
            child: Icon(Icons.add),
          ),
        );
    

    3.BottomSheet
    3.1源码一览:
      const BottomSheet({
        Key key,
        this.animationController,
        this.enableDrag = true,
        this.elevation = 0.0,
        @required this.onClosing,
        @required this.builder
    

    3.2简单操作
    BottomSheet.gif
    var bottomSheet = BottomSheet(
        onClosing: () {},
        builder: (context) => (Container(
            color: Color(0xffABF5E0),
            child:Wrap(
              children: <Widget>[
                Center(child: Text('绝域从军计惘然,')),
                Center(child: Text('东南幽恨满词笺。')),
                Center(child: Text('一箫一剑平生意,')),
                Center(child: Text('负尽狂名十五年。')),
              ],
            ))));
    
    //点击打开BottomSheet
    floatingActionButton: FloatingActionButton(
      onPressed: () {
        Scaffold.of(scContext).showBottomSheet(bottomSheet.builder);
      },
      tooltip: 'Increment',
      child: Icon(Icons.add),
    ),
    
    - - -

    五、第五组

    第五组.png
    1.TextField:

    Flutter版EditText

    1.1源码一览:
      const TextField({
        Key key,
        this.controller,----TextEditingController
        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,
        this.onChanged,
        this.onEditingComplete,
        this.onSubmitted,
        this.inputFormatters,
        this.enabled,
        this.cursorWidth = 2.0,
        this.cursorRadius,
        this.cursorColor,
        this.keyboardAppearance,
        this.scrollPadding = const EdgeInsets.all(20.0),
        this.enableInteractiveSelection = true,
        this.onTap,
    

    1.2:实现方法
    TextField测试.png
    var textField = TextField(
      keyboardType: TextInputType.number,
      textAlign: TextAlign.center,
      maxLines: 1,
      cursorColor: Colors.black,
      cursorWidth: 10,
      style: TextStyle(fontSize: 20, color: Colors.lightBlue),
      onChanged: (str) {
        print(str);
      },
      onEditingComplete: () {
        print("onEditingComplete");
      },
      onSubmitted: (str) {
        print("onSubmitted:" + str);
      },
      onTap: () {
        print("onTap");
    
      },
    );
    

    2.Checkbox:

    Flutter版CheckBox

    2.1源码一览:
      const Checkbox({
        Key key,
        @required this.value,
        this.tristate = false,
        @required this.onChanged,
        this.activeColor,
        this.materialTapTargetSize,
    

    2.2:实现方法
    Checkbox.png
    var checkbox = Checkbox(
      value: true,
      activeColor: Colors.blue,
      onChanged: (value) {
        print(value);
      },
    );
    

    3.Slider:
    3.1源码一览:
      const Slider({
        @required this.value,
        @required this.onChanged,
        this.onChangeStart,
        this.onChangeEnd,
        this.min = 0.0,
        this.max = 1.0,
        this.divisions,
        this.label,
        this.activeColor,
        this.inactiveColor,
        this.semanticFormatterCallback,
    

    3.2:实现方法
    Slider.png
    var slider = Slider(
      min: 100,
      max: 200,
      value: 180,
      activeColor: Colors.green,
      inactiveColor: Colors.grey,
      onChanged: (value) {
        print(value);
      },
      onChangeStart: (v) {},
      onChangeEnd: (v) {},
    );
    
    - - -

    六、第六组

    第六组.png
    1.Switch:
    1.1源码一览:
      const Switch({
        Key key,
        @required this.value,
        @required this.onChanged,
        this.activeColor,
        this.activeTrackColor,
        this.inactiveThumbColor,
        this.inactiveTrackColor,
        this.activeThumbImage,
        this.inactiveThumbImage,
        this.materialTapTargetSize,
    

    1.2:实现方法
    Switch.png
    var switch_ = Switch(
      value: true,
      activeColor: Colors.greenAccent,
      activeTrackColor: Colors.black,
      activeThumbImage: AssetImage("images/icon_90.png"),
      onChanged: (bool value) {
        print(value);
      },
    );
    

    2.Radio:
    2.1源码一览:
      const Radio({
        Key key,
        @required this.value,
        @required this.groupValue,
        @required this.onChanged,
        this.activeColor,
        this.materialTapTargetSize,
    

    2.2:实现方法
    Radio测试.png
    var numLi = [1, 2, 3, 4, 5, 6, 7];
    var radios=Wrap(children: numLi.map((i) {
      return Radio<int>(value: i, groupValue: 5, onChanged: (int value) {},);
    }).toList());
    

    3.Chip + CircleAvatar:
    Chip + CircleAvatar.png
    var chip = Chip(
      backgroundColor: Color(0xffE5E5E5),
      padding: EdgeInsets.all(3),
      avatar: CircleAvatar(
          backgroundColor: Colors.lightBlue.shade400,
          child: new Text(
            'Toly',
            style: TextStyle(fontSize: 10.0, color: Colors.white),
          )),
      label: Text('张风捷特烈'),
    );
    

    - - -

    Flutter的控件好多啊,常用的差不多也就这样吧


    七、Flex布局详解

    Flex是什么?是RowColumn的老爸,现在先忘掉RowColumn
    等你认清Flex怎么玩的,RowColumn 也就清楚了

    1.先看Flex的的属性

    可以看出direction是必须的,类型和枚举都在下面列出了
    有必要普及几个单词:mainAxis(主轴) Alignment对齐 CrossAxis主轴的交错轴
    什么是主轴:direction的方向为主轴,垂直方向为交错轴

      Flex({
        Key key,
        @required this.direction,
        ----Axis.|----horizontal,
                 |----vertical,
                 
        this.mainAxisAlignment = MainAxisAlignment.start,
        ----MainAxisAlignment.|----start,
                              |----end,
                              |----center,
                              |----spaceBetween,
                              |----spaceAround,
                              |----spaceEvenly,   
        
        this.mainAxisSize = MainAxisSize.max,
        ----MainAxisSize.|----max
                         |----min 
                         
        this.crossAxisAlignment = CrossAxisAlignment.center,
        ----CrossAxisAlignment.|----start,
                               |----end,
                               |----center,
                               |----stretch,
                               |----baseline,
        
        this.textDirection,
        this.verticalDirection = VerticalDirection.down,
        this.textBaseline,
        List<Widget> children = const <Widget>[],
    

    2.布局测试1:水平默认状态
    水平默认状态.png
    var c1 = Container(width: 50, height: 50, color: Colors.blue);
    var c2 = Container(width: 50, height: 80, color: Colors.red);
    var c3 = Container(width: 150, height: 50, color: Colors.yellow);
    
    var flex_test = Flex(
      direction: Axis.horizontal,
      children: <Widget>[c1, c2, c3],
    );
    

    3.水平时主轴的布局行为:默认:MainAxisAlignment.start

    控制属性:mainAxisAlignment

    水平时主轴的布局行为.png
    4.水平时交错轴(纵轴)的布局行为:默认:CrossAxisAlignment.center
    水平时交错轴的布局行为.png
    5.Flex盒主轴尺寸:mainAxisSize--默认:MainAxisSize.max

    就两个值有啥好怕的,max已经测试完了,就剩一个min了
    这min更简单,主轴方向的Flex盒就等于内容尺寸,而不是外部容器
    这就意味着主轴的布局行为无效,也就像warp_content

    如果是主轴水平向的,主轴行为就在水平方向进行,也就是:Row
    如果是主轴纵向的,主轴行为就在竖直方向进行,也就是:Column

    6.Expanded与Flex的搭配

    Expanded,它能与Flex布局进行沟通,来让孩子尺寸变更

    我量了一下,如果同时Expanded--c2和c3,最终c2和c3的长度是一样的
    如果同时Expanded--c1,c2和c3,最终c1,c2,c3长度都是一样的
    
    expaned.png

    好了,今天就是这样,基本上也就这么多,明天找几个经典布局练练手


    后记:捷文规范

    1.本文成长记录及勘误表
    项目源码 日期 备注
    V0.1-github 2018-12-19 Flutter第4天--基础控件(下)+Flex布局详解
    2.更多关于我
    笔名 QQ 微信 爱好
    张风捷特烈 1981462002 zdl1994328 语言
    我的github 我的简书 我的掘金 个人网站
    3.声明

    1----本文由张风捷特烈原创,转载请注明
    2----欢迎广大编程爱好者共同交流
    3----个人能力有限,如有不正之处欢迎大家批评指证,必定虚心改正
    4----看到这里,我在此感谢你的喜欢与支持


    icon_wx_200.png

    相关文章

      网友评论

        本文标题:Flutter第4天--基础控件(下)+Flex布局详解

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