Flutter不常用组件(一)

Flutter 目前拥有400多个组件,其中常用的也就那么几个。大家学习 Flutter 一般都是看的其他人的教程,或者官网的文档教程,这些教程里用到的组件只有那些常用的,更多的组件需要我们自己去看 api 文档。这里列出一些不太常使用的组件,或许可以在你需要的时候帮助你。

AboutDialog

这是一个对话框,其中包含应用程序的图标、名称、版本号和版权,以及一个自定生成的显示应用程序使用的软件许可的按钮和界面。

要想使用AboutDialog我们只需调用showAboutDialog方法就行:

Scaffold(
  appBar: AppBar(title: const Text("AboutDialog")),
  body: Center(
    child: ElevatedButton(
      onPressed: () {
        showAboutDialog(context: context);
      },
      child: const Text("显示AboutDialog"),
    ),
  ),
);

image

showAboutDialog一共有以下几个参数:

  • BuildContext context:BuildContext 对象
  • String? applicationName:程序名称
  • String? applicationVersion:程序版本
  • Widget? applicationIcon:程序图标
  • String? applicationLegalese:程序版权声明
  • List<Widget>? children:子组件
  • bool useRootNavigator = true:是否使用根导航
  • RouteSettings? routeSettings:路由设置
  • Offset? anchorPoint:锚点位置
showAboutDialog(
  context: context,
  applicationName: "Flutter冷门组件",
  applicationVersion: "0.0.1",
  applicationIcon: const FlutterLogo(),
  applicationLegalese: "没有版权声明",
  children: [
    Container(height: 12, color: Colors.blue),
    Container(height: 12, color: Colors.red),
    Container(height: 12, color: Colors.green),
  ],
  useRootNavigator: true,
  routeSettings: null,
  anchorPoint: Offset.zero,
);

image

当我们点击VIEW LICENSES按钮时,会自动跳转到系统生成的软件许可证界面,里面列出了程序所使用的的所有包的证书:

image

AboutListTile

适合用在Drawer中显示AboutDialog的组件。

该组件的使用很简单,直接使用不用传参就有效果:

return Scaffold(
    body: SafeArea(
        child: AboutListTile(),
    ),
);

image

不仅有效果,还有附带点击事件:

image

该组件有以下几个属性,大部分是设置AboutDialog

  • Key? key:标识键
  • Widget? icon:左边显示的图标
  • Widget? child:子组件
  • String? applicationName:程序名称
  • String? applicationVersion:程序版本号
  • Widget? applicationIcon:程序图标
  • String? applicationLegalese:程序版权声明
  • List<Widget>? aboutBoxChildren:弹窗显示的子组件
  • bool? dense:是否是垂直密集列表的一部分

我们使用以上几个属性看一下:

return Scaffold(
  body: SafeArea(
    child: AboutListTile(
      icon: const Icon(Icons.perm_device_info),
      applicationName: "Flutter冷门组件",
      applicationVersion: "0.0.1",
      applicationIcon: const FlutterLogo(),
      applicationLegalese: "没有版权声明",
      aboutBoxChildren: [
        Container(height: 12, color: Colors.blue),
        Container(height: 12, color: Colors.red),
        Container(height: 12, color: Colors.green),
      ],
      dense: false,
      child: const Text("这是一个AboutListTitle"),
    ),
  ),
);

image

再贴一个dense不同值得情况下的对比:

image

当然,你也可以直接使用LicensePage这个组件。

AbsorbPointer

使子组件不再触发命中测试/事件。

该组件有以下几个属性:

  • Key? key:标识键
  • bool absorbing:是否会在命中测试中吸收指针。默认为true
  • Widget? child:子组件
  • bool? ignoringSemantics:编译语义树时是否忽略此渲染对象的语义

我有以下一个组件:

Center(
  child: InkWell(
    onTap: () {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text("点击了")),
      );
    },
    child: Container(width: 250, height: 250, color: Colors.blue),
  ),
)

每次点击时都会弹出一个 SnackBar:

image

现在在外面套个AbsorbPointer

AbsorbPointer(
  child: Center(
    child: InkWell(
      onTap: () {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(content: Text("点击了")),
        );
      },
      child: Container(width: 250, height: 250, color: Colors.blue),
    ),
  ),
)

image

若想重新使子组件能接受点击事件,只要把absorbing属性设置为false就行。

Accumulator

整数的可变包装器,可以通过引用传递来在递归堆栈中跟踪值。

准确来说这不是组件,就是 Flutter 中的一个类。它只有一个int类型的属性value,默认值是0。有两个比较重要的实例方法:valueincrement

下面通过一个简单的例子来使用以下:

// 先实例化一下
Accumulator accumulator = Accumulator();
Center(
  child: Column(
    mainAxisAlignment: MainAxisAlignment.center,
    children: [
      Text("${accumulator.value}", style: const TextStyle(fontSize: 24)),
      ElevatedButton(
        onPressed: () {
          accumulator.increment(5);
          setState(() {});
        },
        child: const Text("+5"),
      ),
    ],
  ),
)

image

AnnotatedRegion

在某个页面中单独修改状态栏和导航栏主题

  • Key? key:标识键
  • Widget child:子组件
  • SystemUiOverlayStyle value`:SystemUiOverlayStyle属性
  • bool sized:推入树中的层是否提供大小。默认为true
 AnnotatedRegion(
    value: SystemUiOverlayStyle(
      statusBarColor: Colors.white,
        statusBarIconBrightness: Brightness.dark,
        systemNavigationBarColor: Colors.white,
        systemNavigationBarIconBrightness: Brightness.dark,
    ),
    child: Scaffold(
       // ...
    )
  )

image

有两点需要注意:

  • 该组件最好是在没有使用官方AppBar时使用,因为AppBarsystemOverlayStyle属性会覆盖状态栏的样式(AppBarsystemOverlayStyle无法修改系统导航栏的样式)。当然,可以两个混合使用:

    AnnotatedRegion(
          value: SystemUiOverlayStyle(
            systemNavigationBarColor: _colors[_index],
            systemNavigationBarIconBrightness: _flag ? Brightness.light : Brightness.dark,
          ),
          child: Scaffold(
            appBar: AppBar(
              title: Text(
                "AnnotatedRegion",
                style: TextStyle(color: _flag ? Colors.white : Colors.black),
              ),
              leading: BackButton(color: _flag ? Colors.white : Colors.black),
              backgroundColor: _colors[_index],
              systemOverlayStyle: SystemUiOverlayStyle(
                statusBarColor: _colors[_index],
                statusBarIconBrightness: _flag ? Brightness.light : Brightness.dark,
              ),
            ),
            body: ...
          ),
        )
    

image

  • 使用该组件修改的样式会运用到全局,最好的方法是在返回或进入的另一个界面也对SystemUiOverlayStyle进行设置

ButtonBar

用来对齐一系列按钮

  • Key? key:标识键
  • MainAxisAlignment? alignment:主轴对齐方式。默认为MainAxisAlignment.end
  • MainAxisSize? mainAxisSize:水平空间的宽度。默认为MainAxisSize.max
  • ButtonTextTheme? buttonTextTheme:按钮文本主题
  • double? buttonMinWidth:按钮最小宽度
  • double? buttonHeight:按钮高度
  • EdgeInsetsGeometry? buttonPadding:按钮内边距
  • bool? buttonAlignedDropdown:定义DropdownButton菜单的宽度是否与按钮的宽度匹配。默认值为 false
  • ButtonBarLayoutBehavior? layoutBehavior:定义ButtonBar是否应使用最小尺寸约束或填充来调整自身大小。默认值为 ButtonBarLayoutBehavior.padded
  • VerticalDirection? overflowDirection:定义子项(如果溢出)的垂直方向。默认为VerticalDirection.down
  • double? overflowButtonSpacing:按钮栏溢出时按钮之间的间距
  • List children = const []:子按钮
Center(
  child: ButtonBar(
    mainAxisSize: MainAxisSize.max,
    alignment: MainAxisAlignment.center,
    buttonPadding: const EdgeInsets.symmetric(horizontal: 12),
    overflowDirection: VerticalDirection.up,
    children: [
      const BackButton(),
      const CloseButton(),
      DropdownButton(
        value: "语文",
        items: const [
          DropdownMenuItem(value: "语文", child: Text("语文")),
          DropdownMenuItem(value: "数学", child: Text("数学")),
          DropdownMenuItem(value: "英语", child: Text("英语")),
        ],
        onChanged: (value) {},
      ),
      TextButton(onPressed: () {}, child: const Text("按钮")),
      ElevatedButton(onPressed: () {}, child: const Text("按钮")),
      OutlinedButton(onPressed: () {}, child: const Text("按钮")),
      MaterialButton(onPressed: () {}, child: const Text("按钮")),
    ],
  ),
),

image

这样看起来这个组件是不是很鸡肋。其实这种用法是错误的,官方推荐在弹窗中使用该组件:

TextButton(
  onPressed: () {
    showDialog(
      context: context,
      builder: (context) {
        return SimpleDialog(
          title: const Text("弹窗"),
          children: [
            const Padding(
              padding: EdgeInsets.symmetric(horizontal: 16.0),
              child: Text("ButtonBar的使用"),
            ),
            ButtonBar(
              children: [
                OutlinedButton(onPressed: () {}, child: const Text("确认")),
                OutlinedButton(onPressed: () {}, child: const Text("取消")),
              ],
            ),
          ],
        );
      },
    );
  },
  child: const Text("按钮"),
)

image

BackdropFilter

对子元素应用滤镜。

  • Key? key:标识键
  • ImageFilter filter:在绘制子项之前应用于现有绘制内容的图像过滤器
  • Widget? child:子组件
  • BlendMode blendMode:用于将过滤的背景内容应用到背景表面的混合模式。默认值为BlendMode.srcOver
Stack(
  children: [
    Image.asset("assets/images/sxt.jpg", fit: BoxFit.cover),
    BackdropFilter(
      filter: ImageFilter.blur(sigmaX: 50, sigmaY: 50),
      child: ColoredBox(color: Colors.white.withOpacity(.2)),
    ),
  ],
),

image

posted @ 2022-12-01 17:26  菠萝橙子丶  阅读(364)  评论(0编辑  收藏  举报