美文网首页
Flutter开发3:UI功能控件集合

Flutter开发3:UI功能控件集合

作者: 十二栗子 | 来源:发表于2022-05-05 13:34 被阅读0次

    一、SafeArea

    用于在屏幕安全区中显示布局。当我们没有使用Scaffold或未设置AppBar时,页面的布局会伸展到系统状态栏下,如果我们不需要这种沉浸式状态栏效果,那么就可以使用SafeArea跳过状态栏区域(包括底部导航栏)。
    用法就是,用SafeArea包裹展示容器

    SafeArea(
            child: Container()
    )
    

    二、显示与隐藏

    • Offstage 具有简单的隐藏功能,属性为true时表示隐藏,且不占用空间
    • Visibility 比Offstage 具有更多功能,visible属性为false时表示隐藏
    • Opacity 该控件提供透明度的设置能力,当完全透明时,亦可实现隐藏控件的效果

    Visibility 属性

    属性名 类型 简介
    replacement Widget 不可见时显示的控件,仅当maintainState为false时有效
    visible bool 子控件是否可见
    maintainState bool 不可见时是否维持状态
    maintainAnimation bool 不可见时是否维持子控件动画
    maintainSize bool 不可见时是否保留空间
    maintainInteractivity bool 不可见时是否保留交互性
     Wrap(
                  children: [
                    Offstage(offstage: true, child: TextButton(onPressed: (){}, child: const Text('社会心理学'))),
                    Visibility(visible: false, child: TextButton(onPressed: (){}, child: const Text('发展心理学'))),
                    TextButton(onPressed: (){}, child: const Text('变态心理学')),
                    TextButton(onPressed: (){}, child: const Text('健康心理学')),
                    TextButton(onPressed: (){}, child: const Text('咨询心理学')),
                  ],
                ),
    

    三、裁剪

    • ClipOval 子控件为正方形时剪裁为内切圆,若为矩形时,剪裁为内切椭圆
    • ClipRRect 将子控件剪裁为圆角矩形
    • ClipRect 剪裁溢出部分【?】
    • ClipPath 路径裁剪,可配合CustomClipper实现各种不规则效果
      除此外,还有一个控件CircleAvatar也具有类似的功能,但这是一个视图控件,而不是功能控件,用于头像显示。
    //剪裁为内切椭圆
    ClipOval(
                  child: Image.asset('assets/img/nezha1.jpeg'),
                ),
    //剪裁为圆角矩形
    ClipRRect(borderRadius: BorderRadius.circular(15),child: Image.asset('assets/img/nezha1.jpeg'),),
                const SizedBox(height: 10,),
    
    //圆形头像
    const Center(
                  child: CircleAvatar(
                    backgroundImage: NetworkImage(
                        'https://c-ssl.duitang.com/uploads/item/201810/07/20181007131933_qhjkl.thumb.1000_0.jpg'),
                    maxRadius: 100,
                  ),
                ),
                const SizedBox(height: 10,),
    
    //昵称头像
    const Center(
                  child: CircleAvatar(
                    child: Text('洋哥'),
                    backgroundColor: Colors.blueAccent,
                    maxRadius: 30,
                  ),
                ),
    
    20220429113053.jpg

    路径剪裁

    ClipPath(
                  clipper: MyClipper(),
                  child: Container(
                    width: 400,
                    height: 300,
                    decoration: const BoxDecoration(
                        color: Color(0xff622F74),
                        gradient: LinearGradient(
                            colors: [Colors.red, Colors.yellow],
                            begin: Alignment.centerRight,
                            end: Alignment(-1.0, -1.0))),
                  ),
                ),
    
    class MyClipper extends CustomClipper<Path> {
      @override
      Path getClip(Size size) {
        var path = Path();
        path.lineTo(0, 300);
        path.lineTo(400, 150);
        path.lineTo(400, 0);
        path.close();
        return path;
      }
    
      @override
      bool shouldReclip(covariant CustomClipper oldClipper) {
        return false;
      }
    }
    
    20220429113521.jpg

    四、变换 Transform

    Transform可以对子控件做一系列变换操作。需要注意的是,它的变换是在绘制阶段进行的,而不是布局(layout)阶段,因此无论对子控件应用何种变换,其占用空间的大小和在屏幕上的位置都是在一开始确定的,不会变化的。

    常用变换

    • 平移
    • 旋转
    • 缩放
    • 斜切
      Transform控件通常有两种使用方式,一种使用默认构造方法,另一种则使用命名构造方法。默认构造方法更强大灵活,命名构造方法则更简单。

    命名构造方法如下

    • Transform.translate
    • Transform.scale
    • Taransform.rotate

    平移

      double dx = 0;
      double dy = 0;
    
    Container(
                  color: Colors.purpleAccent,
                  child: Transform.translate(offset: Offset(dx, dy),
                    child: const Text("走么No加油💪🏻"),
    
                  ),
                ),
                TextButton(onPressed: (){
                  setState(() {
                    dx++;
                    dy++;
                  });
                }, child: const Text('点我移动')),
                TextButton(onPressed: (){
                  setState(() {
                    dx--;
                    dy--;
                  });
                }, child: const Text('点我回位')),
    
    

    旋转

    double PI = 2;
    
    Container(
                  color: Colors.yellow,
                  child: Transform.rotate(angle:pi/PI,
                    child: const Text("看我旋转"),
    
                  ),
                ),
                TextButton(onPressed: (){
                  setState(() {
                    PI++;
                  });
                }, child: const Text('点我旋转')),
                TextButton(onPressed: (){
                  setState(() {
                    PI--;
                  });
                }, child: const Text('点我旋转')),
    

    使用默认构造方法时,transform属性是必传,此时需要使用 Matrix4 类作为 4D 矩阵

    import 'package:vector_math/vector_math_64.dart' as v;
    
    Container(
                  color: Colors.blue,
                  child: Transform(
                    transform: Matrix4.translation(v.Vector3(5,5,0)),
                    child: const Text('会当凌绝顶,一览众山小'),
                  ),
                ),
    

    Matrix4 的常用构造方法

    • scale 缩放
    • transform 平移
    • rotationZ 绕z轴旋转
    • rotationX 绕x轴旋转
    • rotationY 绕y轴旋转
    • skewX 沿x轴方向斜切
    • skewY 沿y轴方向斜切
    • skew 沿x、y轴共同矩阵斜切

    直接使用Matrix4 的命名构造方法还是有些繁琐,还涉及到导入一些数学库,因此真正推荐的写法是使用identity构造方法来初始化一个Matrix4对象,然后调用对应的功能方法,示例如下

    Container(
                  color: Colors.pinkAccent,
                  child: Transform(
                    transform: Matrix4.identity()
                      ..translate(5.0,5.0,0.0),
                    child: const Text('会当凌绝顶,一览众山小'),
                  ),
                ),
    

    通过这种链式调用,在后面连续调用其他变换方法,可同时组合多种变换。
    需要注意,斜切变换只能使用命名构造方法实现

    Container(
                  color: Colors.lightBlue,
                  child: Transform(
                    transform: Matrix4.skewY(-pi/18),
                    child: const Text('会当凌绝顶,一览众山小'),
                  ),
                ),
    

    注意,除了直接使用Transform控件,还可以通过设置Container的transform属性来实现同样的变换功能,其用法与Transform相同。

    20220429143223.jpg

    五、MediaQuery

    MediaQuery主要用于查询媒体相关的数据,使用MediaQuery.of(context)可返回一个MediaQueryData类型的数据,通常不会直接将MediaQuery作为一个控件使用,但它也可以作为Widget控件树中的控件使用。

    MediaQueryData 的属性
    属性名 类型 简介
    size Size 获取屏幕宽、高。单位为逻辑像素,非物理像素。物理像素 = size*devicePixelRatio
    devicePixelRatio double 设备像素比(密度)。单位逻辑像素对应的物理像素数量
    textScaleFactor double 单位逻辑像素的字体像素数,若设为1.5,则放大50%
    platformBrightness Brightness 平台当前亮度模式(iOS夜间模式、安卓9以上支持)
    viewInsets EdgeInsets 被系统遮挡的部分,通常指键盘。viewInsets.bottom表示键盘的高度
    padding EdgeInsets 被系统遮挡的部分,此处指“刘海屏”和安卓底部导航栏高度
    viewPadding EdgeInsets 被系统遮挡的部分,独立于padding和viewInsets,通常是全屏
    systemGestureInsets EdgeInsets 沿着屏幕边缘的区域,系统在这里消耗某些输入事件,并阻止将这些事件传递给APP。APP应避免将手势检测器定位在系统手势识别的区域内
    physicalDepth double 设备的最大深度(主要在Fuchsia系统上设置)
    alwaysUse24HourFormat bool 是否是24小时制
    accessibleNavigation bool 否使用TalkBack或VoiceOver等辅助功能与程序进行交互
    invertColors bool 是否支持颜色反转
    highContrast bool 仅iOS 13以上支持。通过“设置”->“辅助功能”->“增加对比度”
    disableAnimations bool 平台是否要求尽可能禁用或减少动画
    boldText bool 平台是否要求使用粗体
    orientation Orientation 是横屏还是竖屏

    需要注意,MediaQuery必须在MaterialApp的作用域下使用,即在MaterialApp控件之后使用。

    下面是iPhone 12 mini的模拟器打印数据

        // 屏幕大小
        Size mSize = MediaQuery.of(context).size;
        debugPrint(mSize.width.toString()); // 375.0
        debugPrint(mSize.height.toString()); // 812.0
    
        // 密度
        double mRatio = MediaQuery.of(context).devicePixelRatio;
        debugPrint(mRatio.toString()); // 3.0
    
        // 设备真实像素
        double width = mSize.width * mRatio;
        double heigth = mSize.height * mRatio;
        debugPrint(width.toString()); // 1125.0
        debugPrint(heigth.toString()); // 2436.0
    
        //上下边距 (状态栏 和 内置导航键)
        double topPadding = MediaQuery.of(context).padding.top;
        double bottomPadding = MediaQuery.of(context).padding.bottom;
        debugPrint(topPadding.toString()); // 50.0
        debugPrint(bottomPadding.toString()); // 34.0
    

    六、返回拦截 WillPopScope*

    Flutter中可以通过WillPopScope来实现返回按钮(iOS上的滑动返回)拦截。

    WillPopScope中的onWillPop属性是一个回调函数,当用户点击返回按钮时会被调用(或手势操作)。该回调需要返回一个Future对象,如果返回的Future最终值为false时,则当前路由不出栈(不会返回);最终值为true时,当前路由出栈退出。可以通过这个回调来决定是否退出。

    WillPopScope(
            onWillPop: () async {
              if (_lastPressedAt == null ||
                  DateTime.now().difference(_lastPressedAt) > Duration(seconds: 1)) {
                //两次点击间隔超过1秒则重新计时
                _lastPressedAt = DateTime.now();
                return false;
              }
              return true;
            },
            child: Container(
              alignment: Alignment.center,
              child: Text("1秒内连续点击两次返回键才退出"),
            )
        );
    

    七、Builder

    使用一个闭包来创建Widget。它的主要用途有两个

    获取某个控件中的上下文对象(BuildContext)
    使用一个函数来构建Widget,这样可以在构建前做一些初始化操作

    // 以下局部主题修改不生效,则需要使用Builder获取正确的上下文对象。
    MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            primarySwatch: Colors.orange,
            primaryColor: Colors.orange,
          ),
          home: Scaffold(
            appBar: AppBar(
              title: Text(
                "Flutter",
                style: TextStyle(color: Theme.of(context).accentColor),
              ),
            ),
            body: Container(
              alignment: Alignment.center,
              child: Theme(
                data: Theme.of(context).copyWith(primaryColor: Colors.red),
                child: Text(
                  "测试",
                  style: TextStyle(color: Theme.of(context).primaryColor),
                ),
              ),
            ),
          ),
        );
    
    

    八、模糊处理 BackdropFilter

    该控件主要用于模糊处理,它不仅可以处理图片,也可以处理任意的其他控件。但通常不建议使用模糊处理,对渲染性能影响很大。

    模糊图层使用 ImageFilter.blur 设置模糊度,一般是在 0.0-10.0 之间,数值越大模糊度越高,超过 10.0 时完全不可见。另外蒙层还需要设置一个色值,通常可使用 withOpacity 方法设置透明度,一般是在 0.0-1.0 之间。

    Stack(
                  alignment: Alignment.center,
                  children: <Widget>[
                    SizedBox(
                      width: 300,
                      height: 400,
                      child: Image.network('https://c-ssl.duitang.com/uploads/item/201810/07/20181007131933_qhjkl.thumb.1000_0.jpg'),
                    ),
                    BackdropFilter(
                      filter: ImageFilter.blur(sigmaX: 2.0,sigmaY: 1.0),
                      child: Center(
                        child: Container(
                          height: 200,
                          width: 100,
                          color: Colors.red.withOpacity(0),
                        ),
                      ),
                    )
                  ],
                ),
    

    九、截图 RepaintBoundary*

    可用于截取当前屏幕的Widget的截图,只需要套在想要截图的控件的外层。如要获取全屏截图,将RepaintBoundary包裹在最外层即可。

    十、主题 Theme

    Theme 控件为Material APP 定义了主题数据(ThemeData)。在Flutter 中已预定义了一系列的主题,许多控件或部分或全部应用了这些主题,因此当更改了预定义主题后,所有使用了这些主题的Widget也都会发生相应的变化。

    Theme 主要描述了应用程序的颜色和排版选择。主题分为两种:

    • 全局 Theme 是由应用程序根MaterialApp创建的主题
    MaterialApp(
        title: title,
        theme: ThemeData(
             primaryColor: Colors.red,
             ///...
        ),
    );
    
    • 局部 Theme 在应用程序某个区域范围中用于覆盖全局主题,实现灵活的差异化
    // 对于修改主题的控件,使用Theme包裹
    Theme(
        data: ThemeData(
            accentColor: Colors.yellow,
            //...
        ),
        child: Text('Hello World'),
    );
    

    如需获取主题,可使用如下方式

    Container(
        color: Theme.of(context).accentColor,
        chile: Text(
            'Text with a background color',
            style: Theme.of(context).textTheme.title,
        ),
    );
    

    有时候我们不想要覆盖所有的主题属性,这时候可以扩展父主题

    Theme(
      /// 使用 copyWith 找到并扩展父主题
      data: Theme.of(context).copyWith(accentColor: Colors.yellow),
      child: FloatingActionButton(
        onPressed: null,
        child: Icon(Icons.add),
      ),
    );
    

    Flutter 中主要通过ThemeData去保存应用的主题及样式等信息,因此需要重点了解该类的属性。

    属性名 类型 简介
    brightness Brightness 应用的整体主题亮度(可用于适配夜间模式)
    primarySwatch MaterialColor Material 定义的主题颜色样本。它是具有十种颜色阴影的颜色样本
    primaryColor Color 主色,决定导航栏颜色
    primaryColorBrightness Brightness primaryColor的亮度
    primaryColorLight Color primaryColor的较浅版本
    primaryColorDark Color primaryColor的较深版本
    accentColor Color 小控件的前景色(按钮、文本、覆盖边缘效果等)
    accentColorBrightness Brightness accentColor的亮度
    canvasColor Color MaterialType.canvas 的默认颜色
    scaffoldBackgroundColor Color 为Scaffold下的Material默认色,用于app的背景色
    bottomAppBarColor Color bottomAppBarColor的默认颜色
    cardColor Color 用在卡片(Card)上的Material的颜色
    dividerColor Color Divider和PopupMenuDivider的颜色,也用于ListTile之间、DataTable的行之间等
    highlightColor Color 用于溅墨动画或指示菜单被选中时的高亮颜色
    splashColor Color 溅墨效果颜色(水波纹)
    splashFactory InteractiveInkFeatureFactory 定义InkWall和InkResponse的外观
    selectedRowColor Color 高亮选定行的颜色
    unselectedWidgetColor Color 用于处于非活动(但已启用)状态的小控件的颜色。例如未选中的复选框
    disabledColor Color 禁用状态下小控件的颜色
    buttonColor Color RaisedButtons使用的默认填充色
    buttonTheme ButtonThemeData 定义按钮部件的默认配置
    secondaryHeaderColor Color 选定行时PaginatedDataTable标题的颜色
    textSelectionColor Color 文本框(如TextField)中文本被选中的颜色
    cursorColor Color 文本框中光标的颜色
    textSelectionHandleColor Color 用于调整当前选定文本部分的句柄的颜色
    backgroundColor Color 与primaryColor形成对比的颜色,例如用作进度条的剩余部分
    dialogBackgroundColor Color Dialog的背景色
    indicatorColor Color TabBar中选中的指示器颜色
    hintColor Color 用于提示文本或占位符文本的颜色,例如在TextField中
    errorColor Color 用于输入验证错误的颜色,例如在TextField中
    toggleableActiveColor Color 用于突出显示Switch、Radio和Checkbox等可切换小部件的活动状态的颜色
    fontFamily String 字体类型
    textTheme TextTheme 与卡片和画布对比的文本颜色
    primaryTextTheme TextTheme 与primaryColor形成对比的文本主题
    accentTextTheme TextTheme 与accentColor形成对比的文本主题
    inputDecorationTheme InputDecorationTheme InputDecorator、TextField和TextFormField的默认InputDecoration值基于此主题
    iconTheme IconThemeData 与卡片和画布颜色形成对比的图标主题
    primaryIconTheme IconThemeData 与primaryColor形成对比的图标主题
    accentIconTheme IconThemeData 与accentColor形成对比的图标主题
    sliderTheme SliderThemeData 用于呈现Slider的颜色和形状
    tabBarTheme TabBarTheme 用于自定义选项卡指示器的大小、形状和颜色的主题
    cardTheme CardTheme Card的颜色和样式
    chipTheme ChipThemeData Chip的颜色和样式
    platform TargetPlatform 小控件应该适应目标的平台,应该被用来根据平台的约定来样式化UI元素
    materialTapTargetSize MaterialTapTargetSize 配置某些Material部件的命中测试大小
    pageTransitionsTheme PageTransitionsTheme 每个目标平台的默认MaterialPageRoute转换
    appBarTheme AppBarTheme 用于自定义Appbar的颜色、高度、亮度、iconTheme和textTheme的主题
    bottomAppBarTheme BottomAppBarTheme 自定义BottomAppBar的形状、高度和颜色的主题
    colorScheme ColorScheme 一组13种颜色,可用于配置大多数组件的颜色属性
    dialogTheme DialogTheme 自定义Dialog的主题形状
    typography Typography 用于配置TextTheme、primaryTextTheme和accentTextTheme的颜色和几何文本主题值
    cupertinoOverrideTheme CupertinoThemeData 用来覆盖Cupertino主题的样式
    /// 判断当前是否是夜间模式
    bool isDarkMode(BuildContext context){
        return Theme.of(context).brightness == Brightness.dark;
    }
    

    十一、异步 UI*

    1.FutureBuilder
    2.StreamBuilder

    相关文章

      网友评论

          本文标题:Flutter开发3:UI功能控件集合

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