1

flutter 非常用组件整理 第二篇

视频

https://youtu.be/fS_4ZxJvaX0

https://www.bilibili.com/video/BV1jS421R7vJ/

前言

原文 https://ducafecat.com/blog/lesser-known-flutter-widgets-02

本文是Flutter非常用组件第二篇,从开发者的视角出发,精选并深入剖析了AboutDialog、AnimatedGrid、Badge等鲜为人知却功能强大的隐藏组件,为读者提供了一份全面的Flutter UI组件使用指南。无论您是初学者还是有经验的开发者,相信本文都能为您的Flutter项目注入新的活力,助力打造出色的应用界面。

Flutter,UI组件,界面设计,隐藏组件,高级组件,应用开发

参考

正文

AboutDialog

AboutDialog 组件用于显示应用程序的"关于"对话框。它通常包含应用程序的名称、版本、版权信息以及其他相关细节。让我们来看一个使用 AboutDialog 的例子:

import 'package:flutter/material.dart';

class WidgetPage extends StatefulWidget {
  const WidgetPage({super.key});

  @override
  State<WidgetPage> createState() => _WidgetPageState();
}

class _WidgetPageState extends State<WidgetPage> {
  Widget _mainView() {
    return Center(
      child: Column(
        children: [
          IconButton(
            icon: const Icon(Icons.info),
            onPressed: () {
              showAboutDialog(
                context: context,
                applicationName: '猫哥App',
                applicationVersion: '1.0.0',
                applicationIcon: Image.asset(
                  'assets/app_icon.png',
                  width: 100,
                ),
                applicationLegalese: '© 2024 Ducafecat. All rights reserved.',
              );
            },
          )
        ],
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('非常用组件'),
      ),
      body: _mainView(),
    );
  }
}

showAboutDialog

点击后可以查看应用包使用详情,还是很有用的。

App Licenses

在这个例子中,我们创建了一个简单的 Flutter 应用程序,包含一个 AppBar 和一个居中的文本。在 AppBar 的操作图标中,我们添加了一个 IconButton,当点击时会显示 AboutDialog。

showAboutDialog() 函数用于显示 AboutDialog。我们为其提供了以下属性:

  • applicationName: 应用程序的名称
  • applicationVersion: 应用程序的版本号
  • applicationIcon: 应用程序的图标
  • applicationLegalese: 应用程序的版权信息

当用户点击 AppBar 上的信息图标时,AboutDialog 将显示应用程序的基本信息。这种对话框通常用于向用户提供有关应用程序的更多详细信息。

AboutListTile

AboutListTile 是一个 ListTile 组件的特殊版本,用于在应用程序的设置或信息页面上显示应用程序的"关于"信息。它结合了 AboutDialog 的功能,并将其集成到一个可以轻松添加到 ListView 中的 ListTile 小部件中。

下面是一个使用 AboutListTile 的例子:

import 'package:flutter/material.dart';

class WidgetPage extends StatefulWidget {
  const WidgetPage({super.key});

  @override
  State<WidgetPage> createState() => _WidgetPageState();
}

class _WidgetPageState extends State<WidgetPage> {
  Widget _mainView() {
    return ListView(
      children: [
        AboutListTile(
          icon: Image.asset(
            'assets/app_icon.png',
            width: 100,
          ),
          applicationName: '猫哥App',
          applicationVersion: '1.0.0',
          applicationIcon: Image.asset(
            'assets/app_icon.png',
            width: 100,
          ),
          applicationLegalese: '© 2024 Ducafecat. All rights reserved.',
          aboutBoxChildren: const [
            Text('This is a sample Flutter app.'),
            SizedBox(height: 8.0),
            Text('Developed by My Company.'),
          ],
        ),
        ListTile(
          title: const Text('Privacy Policy'),
          onTap: () {
            // Navigate to privacy policy page
          },
        ),
        ListTile(
          title: const Text('Terms of Service'),
          onTap: () {
            // Navigate to terms of service page
          },
        ),
      ],
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('非常用组件'),
      ),
      body: _mainView(),
    );
  }
}

AboutListTile

点击后打开版本模式框

AboutDialog

在这个例子中,我们在 SettingsPage 的 ListView 中使用了 AboutListTile 组件。与 AboutDialog 不同,AboutListTile 直接集成到 ListTile 中,可以轻松地添加到 ListView 中。

我们为 AboutListTile 提供了以下属性:

  • icon: 应用程序的图标
  • applicationName: 应用程序的名称
  • applicationVersion: 应用程序的版本号
  • applicationIcon: 应用程序的图标 (与 icon 属性不同)
  • applicationLegalese: 应用程序的版权信息
  • aboutBoxChildren: 可以添加到 AboutDialog 中的额外 Widget

当用户点击 AboutListTile 时,它会弹出一个 AboutDialog,其中包含应用程序的基本信息和自定义的 aboutBoxChildren 部分。

这种方式可以让您轻松地在设置页面或信息页面中添加应用程序的"关于"信息,为用户提供更好的体验。

AnimatedGrid

AnimatedGrid 是 Flutter 提供的一个强大的组件,用于创建可滚动的网格布局,并在添加、删除或重新排序项目时提供动画效果。它通常用于构建动态和交互性强的列表或网格界面。

下面是一个使用 AnimatedGrid 的示例:

import 'package:flutter/material.dart';

class WidgetPage extends StatefulWidget {
  const WidgetPage({super.key});

  @override
  State<WidgetPage> createState() => _WidgetPageState();
}

class _WidgetPageState extends State<WidgetPage> {
  final GlobalKey<AnimatedGridState> _gridKey = GlobalKey();
  final List<int> _items = [];

  void _addItem() {
    int index = _items.length;
    _items.add(index);
    _gridKey.currentState?.insertItem(index);
  }

  void _removeItem(int index) {
    if (index >= 0 && index < _items.length) {
      _gridKey.currentState?.removeItem(
        index,
        (_, animation) => _buildItem(index, animation),
      );
      _items.removeAt(index);
    }
  }

  Widget _buildItem(int item, Animation<double> animation) {
    return ScaleTransition(
      scale: animation,
      child: GestureDetector(
        onDoubleTap: () => _removeItem(item),
        child: Container(
          margin: const EdgeInsets.all(8.0),
          color: Colors.blue,
          child: Center(
            child: Text(
              '$item',
              style: Theme.of(context).textTheme.headlineMedium,
            ),
          ),
        ),
      ),
    );
  }

  Widget _mainView() {
    return AnimatedGrid(
      key: _gridKey,
      initialItemCount: _items.length,
      gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisCount: 3,
        mainAxisSpacing: 8.0,
        crossAxisSpacing: 8.0,
      ),
      itemBuilder: (context, index, animation) {
        return _buildItem(_items[index], animation);
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('非常用组件'),
        actions: [
          IconButton(
            icon: const Icon(Icons.add),
            onPressed: _addItem,
          ),
        ],
      ),
      body: _mainView(),
    );
  }
}

AnimatedGrid

在这个例子中,我们创建了一个名为 AnimatedGridPage 的页面,它使用 AnimatedGrid 组件来显示一个动态的网格布局。

AnimatedGrid 组件有以下重要属性:

  • key: 用于标识 AnimatedGrid 实例,在本例中使用了 GlobalKey<AnimatedGridState> 类型。
  • initialItemCount: 指定初始项目数量。
  • gridDelegate: 用于配置网格布局,在本例中使用了 SliverGridDelegateWithFixedCrossAxisCount
  • itemBuilder: 定义每个网格项的构建方式,在本例中使用 _buildItem 方法。

_addItem_removeItem 方法中,我们分别调用 insertItemremoveItem 方法来添加和删除网格项目,同时触发相应的动画效果。

_buildItem 方法返回一个 ScaleTransition 组件,它根据动画的值来缩放每个网格项,从而产生添加或删除时的动画效果。

通过使用 AnimatedGrid,您可以在 Flutter 应用程序中创建动态且富有交互性的网格布局,并提供平滑的动画效果。这对于构建像联系人列表、图库等需要频繁更新的界面非常有用。

BackButton

BackButton 是一个Flutter 小部件,用于在 Flutter 应用程序中添加返回按钮。它通常用于在应用程序的顶部导航栏或应用程序页面的左上角添加一个返回按钮。当用户点击这个按钮时,它会触发应用程序的导航堆栈进行回退。

下面是一个简单的示例,演示如何在 Flutter 应用程序中使用 BackButton:

import 'package:flutter/material.dart';

class BackButtonExample extends StatefulWidget {
  @override
  _BackButtonExampleState createState() => _BackButtonExampleState();
}

class _BackButtonExampleState extends State<BackButtonExample> {
  int _currentPage = 0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Back Button Example'),
        leading: _currentPage > 0 ? BackButton() : null,
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(
              onPressed: _navigateToNextPage,
              child: Text('Go to Next Page'),
            ),
            SizedBox(height: 16.0),
            if (_currentPage > 0)
              ElevatedButton(
                onPressed: _navigateToPreviousPage,
                child: Text('Go to Previous Page'),
              ),
          ],
        ),
      ),
    );
  }

  void _navigateToNextPage() {
    setState(() {
      _currentPage++;
    });
  }

  void _navigateToPreviousPage() {
    setState(() {
      _currentPage--;
    });
  }
}

BackButton

在这个示例中:

  1. 我们创建了一个 BackButtonExample 页面,并在 ScaffoldAppBar 中使用了 BackButton 组件。
  2. 我们通过跟踪 _currentPage 变量来决定是否显示返回按钮。当 _currentPage 大于 0 时,我们会显示返回按钮。
  3. 当用户点击返回按钮时,它会触发应用程序的导航堆栈进行回退,从而返回到上一个页面。
  4. 我们还添加了两个按钮,分别用于导航到下一个页面和上一个页面。

通过使用 BackButton,您可以在 Flutter 应用程序中轻松地添加返回功能,使用户可以方便地在应用程序中导航。这有助于提高应用程序的可用性和用户体验。

需要注意的是,BackButton 会自动处理设备上的硬件返回按钮,并在导航堆栈中进行回退。这可以确保您的应用程序在不同设备上保持一致的行为。

Badge

Badge 是 Flutter 提供的一个小部件,用于在其他小部件上添加一个小的标记或标识。这通常用于在应用程序的图标或其他用户界面元素上显示未读消息数量、购物车商品数量等信息。

下面是一个简单的示例,演示如何在 Flutter 应用程序中使用 Badge 组件:

import 'package:flutter/material.dart';

class WidgetPage extends StatefulWidget {
  const WidgetPage({super.key});

  @override
  State<WidgetPage> createState() => _WidgetPageState();
}

class _WidgetPageState extends State<WidgetPage> {
  int _unreadCount = 0;

  Widget _mainView() {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Badge(
            label: Text('$_unreadCount'),
            offset: const Offset(-5, 5),
            child: IconButton(
              icon: const Icon(
                Icons.notifications,
                size: 32,
              ),
              onPressed: () {
                // Handle notification button press
              },
            ),
          ),
          const SizedBox(height: 16.0),
          ElevatedButton(
            onPressed: _incrementUnreadCount,
            child: const Text('Increment Unread Count'),
          ),
        ],
      ),
    );
  }

  void _incrementUnreadCount() {
    setState(() {
      _unreadCount++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('非常用组件'),
      ),
      body: _mainView(),
    );
  }
}

Badge

在这个示例中:

  1. 我们创建了一个 BadgeExample 页面,并在 Center 组件中放置了一个 Badge 和一个 ElevatedButton
  2. Badge 组件包裹了一个 IconButton。当用户点击这个按钮时,可以执行一些操作,例如打开通知列表。
  3. 我们使用 badgeContent 属性来显示未读消息数量(_unreadCount)。当未读消息数量增加时,Badge 组件会更新其外观,以反映最新的未读消息数量。
  4. 我们添加了一个 ElevatedButton,当用户点击它时,会触发 _incrementUnreadCount 函数,从而增加未读消息计数。

通过使用 Badge 组件,您可以在应用程序的各种用户界面元素上显示小标记或标识,以向用户提供重要的上下文信息。这有助于提高应用程序的可用性和用户体验。

Badge 组件提供了许多自定义选项,如自定义背景颜色、文本样式、位置等,您可以根据需要进行调整,以匹配应用程序的设计风格。

CloseButton

好的,让我为您介绍一下 Flutter 中的 CloseButton 组件。

CloseButton 是一个 Flutter 小部件,用于在应用程序的用户界面中添加一个关闭按钮。它通常用于在对话框、模态页面或其他类型的弹出窗口的顶部或角落添加一个关闭按钮。当用户点击这个按钮时,它会关闭当前页面或对话框,并返回到应用程序的上一个状态。

下面是一个简单的示例,演示如何在 Flutter 应用程序中使用 CloseButton:

import 'package:flutter/material.dart';

class WidgetPage extends StatefulWidget {
  const WidgetPage({super.key});

  @override
  State<WidgetPage> createState() => _WidgetPageState();
}

class _WidgetPageState extends State<WidgetPage> {
  bool _showModal = false;

  void _showModalBottomSheet() {
    setState(() {
      _showModal = true;
    });
  }

  void _closeModal() {
    setState(() {
      _showModal = false;
    });
  }

  Widget _mainView() {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          ElevatedButton(
            onPressed: _showModalBottomSheet,
            child: const Text('Show Modal'),
          ),
          if (_showModal)
            Container(
              height: 300,
              color: Colors.white,
              child: Stack(
                children: [
                  Positioned(
                    top: 8,
                    right: 8,
                    child: CloseButton(
                      onPressed: _closeModal,
                    ),
                  ),
                  Center(
                    child: Text(
                      'This is a modal window',
                      style: Theme.of(context).textTheme.headlineSmall,
                    ),
                  ),
                ],
              ),
            ),
        ],
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('非常用组件'),
      ),
      body: _mainView(),
    );
  }
}

CloseButton

在这个示例中:

  1. 我们创建了一个 CloseButtonExample 页面,并在 Scaffoldbody 中放置了一个 ElevatedButton 和一个可选的模态窗口。
  2. 当用户点击 "Show Modal" 按钮时,我们会设置 _showModal 变量为 true,从而显示模态窗口。
  3. 在模态窗口的右上角,我们使用了 CloseButton 组件。当用户点击这个按钮时,它会调用 _closeModal 函数,将 _showModal 变量设置为 false,从而关闭模态窗口。

通过使用 CloseButton,您可以在应用程序的各种模态页面或弹出窗口中添加一个标准的关闭按钮。这有助于提高应用程序的一致性和可用性,让用户能够轻松地关闭不需要的页面或窗口。

CloseButton 组件提供了一些自定义选项,如自定义图标和颜色,您可以根据需要进行调整,以匹配应用程序的设计风格。

CustomSingleChildLayout

CustomSingleChildLayout 是一个强大的 Flutter 小部件,它允许您自定义单个子小部件的布局。与其他布局小部件不同,CustomSingleChildLayout 不使用预定义的布局规则,而是提供了一个回调函数,您可以在其中实现自己的布局逻辑。这使您可以创建复杂的、动态变化的用户界面元素,并将其集成到更广泛的应用程序布局中。

下面是一个示例,演示如何使用 CustomSingleChildLayout 来创建一个自定义的浮动按钮:

import 'package:flutter/material.dart';

class FloatingButtonLayout extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Custom Single Child Layout'),
      ),
      body: Stack(
        children: [
          // Your main content goes here
          Container(
            color: Colors.grey[200],
            child: Center(
              child: Text('Scroll to see the floating button'),
            ),
          ),
          CustomSingleChildLayout(
            delegate: _FloatingButtonLayoutDelegate(),
            child: ElevatedButton(
              onPressed: () {
                // Handle floating button press
              },
              child: Icon(Icons.add),
            ),
          ),
        ],
      ),
    );
  }
}

class _FloatingButtonLayoutDelegate extends SingleChildLayoutDelegate {
  @override
  Size getSize(BoxConstraints constraints) {
    return Size(60, 60);
  }

  @override
  Offset getPositionForChild(Size size, Size childSize) {
    return Offset(size.width - childSize.width - 16, size.height - childSize.height - 16);
  }

  @override
  bool shouldRelayout(covariant SingleChildLayoutDelegate oldDelegate) {
    return false;
  }
}

CustomSingleChildLayout

在这个示例中:

  1. 我们创建了一个 FloatingButtonLayout 小部件,它包含了一个 Scaffold 和一个 Stack
  2. Stack 中,我们添加了一个填充页面的 Container,并在其上放置了一个 CustomSingleChildLayout
  3. CustomSingleChildLayout 使用了一个自定义的 _FloatingButtonLayoutDelegate,它实现了三个关键方法:

    • getSize: 返回浮动按钮的大小。
    • getPositionForChild: 根据页面大小和按钮大小计算按钮的位置。在这个例子中,我们将它放在右下角。
    • shouldRelayout: 返回 false,因为这个布局不需要重新计算。
  4. 最后,我们在 CustomSingleChildLayout 中放置了一个 ElevatedButton,作为浮动按钮。

通过使用 CustomSingleChildLayout,您可以创建各种自定义的布局效果,如浮动按钮、悬浮菜单、自定义对话框等。这为您提供了更大的灵活性和控制权,以满足应用程序的特定需求。

CustomSingleChildLayout 的主要优点是它允许您完全控制子小部件的布局,而不受其他布局小部件的约束。但同时也需要您编写更多的自定义代码来实现所需的布局逻辑。

Directionality

Directionality 是一个非常有用的 Flutter 小部件,它可以帮助您管理应用程序中的文本方向。在某些情况下,您的应用程序可能需要支持从右到左(RTL)或从左到右(LTR)的文本方向,这取决于用户的语言和区域设置。

Directionality 组件可以为其子小部件提供文本方向信息,从而使它们能够正确地呈现和布局内容。这对于支持国际化和本地化非常重要,因为不同的语言可能需要不同的文本方向。

下面是一个示例,展示如何使用 Directionality 来创建一个简单的 RTL 和 LTR 切换器:

import 'package:flutter/material.dart';

class WidgetPage extends StatefulWidget {
  const WidgetPage({super.key});

  @override
  State<WidgetPage> createState() => _WidgetPageState();
}

class _WidgetPageState extends State<WidgetPage> {
  TextDirection _textDirection = TextDirection.ltr;

  Widget _mainView() {
    return Directionality(
      textDirection: _textDirection,
      child: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Text('This is some text.'),
            const SizedBox(height: 16.0),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                ElevatedButton(
                  onPressed: () {
                    setState(() {
                      _textDirection = TextDirection.ltr;
                    });
                  },
                  child: const Text('Left to Right'),
                ),
                const SizedBox(width: 16.0),
                ElevatedButton(
                  onPressed: () {
                    setState(() {
                      _textDirection = TextDirection.rtl;
                    });
                  },
                  child: const Text('Right to Left'),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('非常用组件'),
      ),
      body: _mainView(),
    );
  }
}

Directionality

在这个示例中:

  1. 我们创建了一个 MyApp 小部件,它包含了一个 Scaffold
  2. Scaffoldbody 中,我们使用了一个 Directionality 小部件。
  3. DirectionalitytextDirection 属性设置为 _textDirection,这是一个 TextDirection 类型的状态变量。
  4. Directionality 的子小部件中,我们放置了一个 Text 小部件和两个切换按钮。
  5. 当用户点击"Left to Right"或"Right to Left"按钮时,我们会更新 _textDirection 状态变量的值,从而改变文本方向。

通过使用 Directionality,您可以确保您的应用程序中的文本和布局正确地适应用户的语言和区域设置。这对于提高应用程序的可访问性和国际化非常重要。

Directionality 组件还可以嵌套使用,以便为应用程序的特定部分设置不同的文本方向。这使您可以在同一个应用程序中混合使用 RTL 和 LTR 文本,并确保它们都能正确显示。

EditableText

好的,让我为您介绍一下 Flutter 中的 EditableText 组件。

EditableText 是 Flutter 框架提供的一个强大的小部件,用于创建可编辑的文本输入框。它提供了许多有用的功能,如光标控制、选择和剪切/复制/粘贴操作。

下面是一个示例,展示如何使用 EditableText 来创建一个简单的文本编辑器:

import 'dart:ui';

import 'package:flutter/material.dart';

class WidgetPage extends StatefulWidget {
  const WidgetPage({super.key});

  @override
  State<WidgetPage> createState() => _WidgetPageState();
}

class _WidgetPageState extends State<WidgetPage> {
  final TextEditingController _controller = TextEditingController();

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  Widget _mainView() {
    return Padding(
      padding: const EdgeInsets.all(16.0),
      child: EditableText(
        controller: _controller,
        focusNode: FocusNode(),
        style: const TextStyle(
          fontSize: 18,
          color: Colors.black,
        ),
        cursorColor: Colors.blue,
        backgroundCursorColor: Colors.yellow,
        onChanged: (text) {
          // Handle text changes
          print('Text changed: $text');
        },
        onSubmitted: (text) {
          // Handle text submission
          print('Text submitted: $text');
        },
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('非常用组件'),
      ),
      body: _mainView(),
    );
  }
}

EditableText

在这个示例中:

  1. 我们创建了一个 MyApp 小部件,它包含了一个 Scaffold
  2. Scaffoldbody 中,我们使用了一个 EditableText 小部件。
  3. EditableTextcontroller 属性用于管理文本内容。在这个例子中,我们创建了一个 TextEditingController 实例并将其传递给 EditableText
  4. focusNode 属性用于管理文本输入框的焦点状态。在这个例子中,我们创建了一个新的 FocusNode 实例。
  5. style 属性用于设置文本的样式,例如字体大小和颜色。
  6. cursorColorbackgroundCursorColor 属性用于设置光标的颜色。
  7. onChangedonSubmitted 回调函数用于在文本发生变化或提交时执行自定义操作。

当用户与 EditableText 交互时,如输入、选择、剪切/复制/粘贴等操作,EditableText 会自动处理这些事件并更新文本内容。您可以通过 controller 属性访问和操作文本内容,并使用各种回调函数来监听和响应用户的输入。

EditableText 还提供了许多其他属性,如 obscureText(用于实现密码输入框)、maxLinesmaxLength(用于控制输入长度)等。这些属性可以根据您的具体需求进行配置。

小结

本文从Flutter框架的视角,精选并介绍了几款鲜为人知却功能强大的UI组件,帮助开发者打造更优质的应用界面。包括AboutDialog、AnimatedGrid、Badge等隐藏宝藏,为您的Flutter项目注入新活力。

感谢阅读本文

如果有什么建议,请在评论中让我知道。我很乐意改进。


flutter 学习路径


© 猫哥
ducafecat.com

end


独立开发者_猫哥
669 声望128 粉丝