美文网首页
学习Flutter的第七天(组件5)

学习Flutter的第七天(组件5)

作者: 囧rg | 来源:发表于2023-04-24 22:30 被阅读0次

    组件1:MaterialApp、Container、Text、Image、Icon
    组件2:ListView、GridView
    组件3:Padding、Row 、Column、Stack、Align、Positioned
    组件4:AspectRatio、Row 、Button
    组件5:Wrap、StatelessWidget 、StatefulWidget、Dialog、PageView、TextField

    3.16 Wrap

    Wrap可以为子控件进行水平或者垂直方向布局,且当空间用完时,Wrap会自动换行,也是常说的流式布局

    名称 功能
    direction 排列方向,默认水平方向排列
    alignment 子控件在主轴上的对齐方式
    spacing 主轴上子控件中间的间距
    runAlignment 子控件在交叉轴上的对齐方式
    runSpacing 交叉轴上子控件之间的间距
    crossAxisAlignment 交叉轴上子控件的对齐方式
    textDirection textDirection水平方向上子控件的起始位置
    verticalDirection 垂直方向上子控件的其实位置
    children

    3.17 StatelessWidget 和 StatefulWidget

    参考:https://blog.csdn.net/qq_30963589/article/details/112561639

    在Flutter开发中,我们一般都不用直接继承Widget类来实现一个新组件,相反,我们通常会通过继承StatelessWidget或StatefulWidget来间接继承Widget类来实现。
    StatelessWidget和StatefulWidget都是直接继承自Widget类,而这两个类也正是Flutter中非常重要的两个抽象类,它们引入了两种Widget模型.

    3.17.1 StatelessWidget

    StatelessWidget继承于Widget类,他重写了creatElement()方法。

    @override
    StatelessElement createElement() => new StatelessElement(this);
    
    

    StatelessWidget用于不需要维护状态的场景,它通常在build方法中通过嵌套其它Widget来构建UI,在构建过程中会递归的构建其嵌套的Widget

    我们一般构建静态的UI的时候会使用StatelessWidget

    3.17.2 StatefulWidget

    StatefulWidget也是继承于Widget类,内部也重写了creatElement(),不过与StatelessWidget不同的是返回的Element 对象并不相同;
    另外StatefulWidget类中添加了一个新的接口createState()

    abstract class StatefulWidget extends Widget {
      // 为子类初始化[key]。
      const StatefulWidget({ Key key }) : super(key: key);
    
      //创建一个[StatefulElement]来管理此小部件在树中的位置。
      @override
      StatefulElement createElement() => StatefulElement(this);
    
      // 在树中的给定位置为此小部件创建可变状态
      @protected
      @factory
      State createState();
    }
    
    

    StatefulWidget来说,State是核心,State表示与其对应的StatefulWidget要维护的状态.一个StatefulWidget对应一个State.

    State保存的信息:

    在widget 构建时可以被同步读取。
    在widget生命周期中可以被改变,当State被改变时,可以手动调用其setState()方法通知Flutter framework状态发生改变,Flutter framework在收到消息后,会重新调用其build方法重新构建widget树,从而达到更新UI的目的。

    每次 setState() 的时候都会重新调用 build方法,所以有些组件前面加 const 关键字,是为了再次build的时候,不会重新创建该组件。虽然不加const也不会有错误,但是对性能会有影响。

    动态添加列表代码

    import 'package:flutter/material.dart';
    
    void main() {
      runApp(const MaterialApp(
        home: HomePage(),
      ));
    }
    
    class HomePage extends StatefulWidget {
      const HomePage({super.key});
    
      @override
      State<HomePage> createState() => _HomePageState();
    }
    
    class _HomePageState extends State<HomePage> {
      final List _dataList = [];
      int _count = 0;
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: const Text("Demo"),
          ),
          body: ListView(
            children: _dataList.map((e) {
              return ListTile(
                title: e,
              );
            }).toList(),
          ),
          floatingActionButton: FloatingActionButton(
            onPressed: () {
              setState(() {
                _count++;
                _dataList.add(Text("列表项 $_count"));
              });
            },
            child: const Icon(Icons.add),
          ),
        );
      }
    }
    
    

    3.18 Dialog

    3.18.1 AlertDialog

    AlertDialog 是一个用于向用户传递信息的弹出层

    import 'package:flutter/material.dart';
    
    class Category extends StatefulWidget {
      const Category({super.key});
    
      @override
      State<Category> createState() => _CategoryState();
    }
    
    class _CategoryState extends State<Category> {
      void _alertDialog() async {
        var result = await showDialog(
            context: context,
            builder: ((context) {
              return AlertDialog(
                title: const Text("提示信息!"),
                content: const Text("这是提示的信息内容"),
                actions: [
                  TextButton(
                      onPressed: () {
                        Navigator.of(context).pop("ok"); // 点击按钮让AlertDialog消失
                      },
                      child: const Text("确定")),
                  TextButton(
                      onPressed: () {
                        Navigator.of(context).pop("cancel");
                      },
                      child: const Text("取消"))
                ],
              );
            }));
        print(result);
      }
    
      @override
      Widget build(BuildContext context) {
        return Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton( onPressed: _alertDialog, child: const Text("AlertDialog"))
          ],
        );
      }
    }
    
    

    3.18.2 SimpleDialog

    为用户几个提供选项,可选标题,标题在选项上不边的信息弹出窗.

    import 'package:flutter/material.dart';
    
    class Category extends StatefulWidget {
      const Category({super.key});
    
      @override
      State<Category> createState() => _CategoryState();
    }
    
    class _CategoryState extends State<Category> {
    
      void _simpleDialog() async {
        var result = await showDialog(
            // 点击背景灰色dialog消失
            barrierDismissible: true,
            context: context,
            builder: ((context) {
              return SimpleDialog(
                title: const Text("请选择语言"),
                children: [
                  SimpleDialogOption(
                    onPressed: () {
                      Navigator.pop(context, "chinese");
                    },
                    child: const Text("汉语"),
                  ),
                  const Divider(),
                  SimpleDialogOption(
                    onPressed: () {
                      Navigator.pop(context, "english");
                    },
                    child: const Text("英语"),
                  ),
                  const Divider(),
                  SimpleDialogOption(
                    onPressed: () {
                      Navigator.pop(context, "Janese");
                    },
                    child: const Text("日语"),
                  ),
                ],
              );
            }));
        print(result);
      }
    
      @override
      Widget build(BuildContext context) {
        return Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton( onPressed: _simpleDialog, child: const Text("SimpleDialog"))
          ],
        );
      }
    }
    
    

    3.18.3 showModalBottomSheet

    底部面板,相当于弹出了一个新页面默认点击消失,可以给子组件外面包一层GestureDetector并设置onTap返回false,拦截点击事件使点击底部面板区域,面板不消失。底部面板的高度是有限制的,不能设置全屏高度

    import 'package:flutter/material.dart';
    
    class Category extends StatefulWidget {
      const Category({super.key});
    
      @override
      State<Category> createState() => _CategoryState();
    }
    
    class _CategoryState extends State<Category> {
      
      void _modelBottomSheet() async {
        var result = await showModalBottomSheet(
            context: context,
            builder: ((context) {
              return SizedBox(
                height: 200,
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.center,
                  children: [
                    ListTile(
                      title: const Text("分享"),
                      onTap: () {
                        Navigator.of(context).pop("share");
                      },
                    ),
                    Divider(),
                    ListTile(
                      title: const Text("收藏"),
                      onTap: () {
                        Navigator.of(context).pop("shoucang");
                      },
                    ),
                    Divider(),
                    ListTile(
                      title: const Text("取消"),
                      onTap: () {
                        Navigator.of(context).pop("cancel");
                      },
                    )
                  ],
                ),
              );
            }));
        print(result);
      }
    
      @override
      Widget build(BuildContext context) {
        return Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton( onPressed: _modelBottomSheet, child: const Text("BottomSheet")),
          ],
        );
      }
    }
    
    

    3.19 PageView

    名称 功能
    scrollDirection Axis.horizontal水平方向,Axis.vertical垂直方向
    children
    allowImplicitScrolling 缓存前2页

    PageView控件可以实现一个“图片轮播”的效果,PageView不仅可以水平滑动也可以垂直滑动,简单用法如下:

    PageView(
        children: <Widget>[
            MyPage1(),    
            MyPage2(), 
            MyPage3(),    
        ],
    )
    

    使用 PageView.builder

    import 'package:flutter/material.dart';
    
    class BannerBuilder extends StatefulWidget {
      const BannerBuilder({super.key});
    
      @override
      State<BannerBuilder> createState() => _BannerBuilderState();
    }
    
    class _BannerBuilderState extends State<BannerBuilder> {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: const Text("pageViewBuileer"),
          ),
          body: PageView.builder(
              //当页面选中后回调此方法
              //参数[index]是当前滑动到的页面角标索引 从0开始
              onPageChanged: (int index) {
                print("当前的页面是 $index");
              },
              //值为flase时 显示第一个页面 然后从左向右开始滑动
              //值为true时 显示最后一个页面 然后从右向左开始滑动
              reverse: false,
              //滑动到页面底部无回弹效果
              physics: BouncingScrollPhysics(),
              itemCount: 10,
              //纵向滑动切换
              scrollDirection: Axis.vertical,
              itemBuilder: (context, index) {
                return Center(
                    child: Text(
                  "第${index + 1}屏",
                  style: Theme.of(context).textTheme.bodyText1,
                ));
              }),
        );
      }
    }
    
    

    使用pageController 和 timer 控制自动轮播

    import 'package:flutter/material.dart';
    import 'dart:async';
    
    class BannerBuilder extends StatefulWidget {
      const BannerBuilder({super.key});
    
      @override
      State<BannerBuilder> createState() => _BannerBuilderState();
    }
    
    class _BannerBuilderState extends State<BannerBuilder> {
      late PageController _pageController;
      late Timer timer;
    
      @override
      void initState() {
        // TODO: implement initState
        super.initState();
            // 初始化并设置
        _pageController = PageController(initialPage: 0);
        timer = Timer.periodic(const Duration(seconds: 5), (timer) {
          // 参数1:跳到索引,参数2:动画时间,参数3:动画模式
          _pageController.animateToPage(2,
              duration: const Duration(milliseconds: 200), curve: Curves.linear);
        });
      }
    
      @override
      void dispose() {
        // 销毁组件
        super.dispose();
        timer.cancel();
        _pageController.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: const Text("pageViewBuileer"),
          ),
          body: PageView.builder(
              // 设置controller
              controller: _pageController,
              // ...
        );
      }
    }
    
    

    3.20 TextField

    const TextField({
        Key key,
        this.controller,//控制器
        this.focusNode,//焦点
        this.obscureText = false,//是否隐藏文本,即显示密码类型
        this.maxLines = 1,//最多行数,高度与行数同步
        this.autofocus = false,//自动聚焦
        this.decoration = const InputDecoration(),//装饰
        TextInputType keyboardType,//键盘类型,即输入类型
        this.onChanged,//输入改变回调
    
        //以下属性不常用,用到再来查看
        this.textInputAction,//键盘按钮
        this.textCapitalization = TextCapitalization.none,//大小写
        this.style,//样式
        this.strutStyle,
        this.textAlign = TextAlign.start,//对齐方式
        this.textDirection,
        this.autocorrect = true,//自动更正
        this.minLines,//最小行数
        this.expands = false,
        this.maxLength,//最多输入数,有值后右下角就会有一个计数器
        this.maxLengthEnforced = true,
        this.onEditingComplete,//输入完成时,配合TextInputAction.done使用
        this.onSubmitted,//提交时,配合TextInputAction
        this.inputFormatters,//输入校验
        this.enabled,//是否可用
        this.cursorWidth = 2.0,//光标宽度
        this.cursorRadius,//光标圆角
        this.cursorColor,//光标颜色
        this.keyboardAppearance,
        this.scrollPadding = const EdgeInsets.all(20.0),
        this.dragStartBehavior = DragStartBehavior.start,
        this.enableInteractiveSelection,
        this.onTap,//点击事件
        this.buildCounter,
        this.scrollPhysics,
      }) 
    

    其中decoration接收一个InputDecoration类型的值,主要用于控制TextField的外观以及提示信息等 这里介绍下这个重要的Widget,

    InputDecoration({
        this.icon,    //位于装饰器外部和输入框前面的图片
        this.labelText,  //用于描述输入框,例如这个输入框是用来输入用户名还是密码的,当输入框获取焦点时默认会浮动到上方,
        this.labelStyle,  // 控制labelText的样式,接收一个TextStyle类型的值
        this.helperText, //辅助文本,位于输入框下方,如果errorText不为空的话,则helperText不会显示
        this.helperStyle, //helperText的样式
        this.hintText,  //提示文本,位于输入框内部
        this.hintStyle, //hintText的样式
        this.hintMaxLines, //提示信息最大行数
        this.errorText,  //错误信息提示
        this.errorStyle, //errorText的样式
        this.errorMaxLines,   //errorText最大行数
        this.hasFloatingPlaceholder = true,  //labelText是否浮动,默认为true,修改为false则labelText在输入框获取焦点时不会浮动且不显示
        this.isDense,   //改变输入框是否为密集型,默认为false,修改为true时,图标及间距会变小
        this.contentPadding, //内间距
        this.prefixIcon,  //位于输入框内部起始位置的图标。
        this.prefix,   //预先填充的Widget,跟prefixText同时只能出现一个
        this.prefixText,  //预填充的文本,例如手机号前面预先加上区号等
        this.prefixStyle,  //prefixText的样式
        this.suffixIcon, //位于输入框后面的图片,例如一般输入框后面会有个眼睛,控制输入内容是否明文
        this.suffix,  //位于输入框尾部的控件,同样的不能和suffixText同时使用
        this.suffixText,//位于尾部的填充文字
        this.suffixStyle,  //suffixText的样式
        this.counter,//位于输入框右下方的小控件,不能和counterText同时使用
        this.counterText,//位于右下方显示的文本,常用于显示输入的字符数量
        this.counterStyle, //counterText的样式
        this.filled,  //如果为true,则输入使用fillColor指定的颜色填充
        this.fillColor,  //相当于输入框的背景颜色
        this.errorBorder,   //errorText不为空,输入框没有焦点时要显示的边框
        this.focusedBorder,  //输入框有焦点时的边框,如果errorText不为空的话,该属性无效
        this.focusedErrorBorder,  //errorText不为空时,输入框有焦点时的边框
        this.disabledBorder,  //输入框禁用时显示的边框,如果errorText不为空的话,该属性无效
        this.enabledBorder,  //输入框可用时显示的边框,如果errorText不为空的话,该属性无效
        this.border, //正常情况下的border
        this.enabled = true,  //输入框是否可用
        this.semanticCounterText,  
        this.alignLabelWithHint,
      })
    

    修改下划线颜色,要同时修改2个样式

    enabledBorder: UnderlineInputBorder(
      borderSide: BorderSide(color: Color(0xffeeeeee)),
    ),
    focusedBorder: UnderlineInputBorder(
      borderSide: BorderSide(color: Colors.blue),
    ),
    

    无边框

    TextField(
      decoration: InputDecoration(border: InputBorder.none),
    )
    

    相关文章

      网友评论

          本文标题:学习Flutter的第七天(组件5)

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