flutter 非常用组件整理 第二篇
视频
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(),
);
}
}
点击后可以查看应用包使用详情,还是很有用的。
在这个例子中,我们创建了一个简单的 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(),
);
}
}
点击后打开版本模式框
在这个例子中,我们在 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(),
);
}
}
在这个例子中,我们创建了一个名为 AnimatedGridPage
的页面,它使用 AnimatedGrid
组件来显示一个动态的网格布局。
AnimatedGrid
组件有以下重要属性:
key
: 用于标识AnimatedGrid
实例,在本例中使用了GlobalKey<AnimatedGridState>
类型。initialItemCount
: 指定初始项目数量。gridDelegate
: 用于配置网格布局,在本例中使用了SliverGridDelegateWithFixedCrossAxisCount
。itemBuilder
: 定义每个网格项的构建方式,在本例中使用_buildItem
方法。
在 _addItem
和 _removeItem
方法中,我们分别调用 insertItem
和 removeItem
方法来添加和删除网格项目,同时触发相应的动画效果。
_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--;
});
}
}
在这个示例中:
- 我们创建了一个
BackButtonExample
页面,并在Scaffold
的AppBar
中使用了BackButton
组件。 - 我们通过跟踪
_currentPage
变量来决定是否显示返回按钮。当_currentPage
大于 0 时,我们会显示返回按钮。 - 当用户点击返回按钮时,它会触发应用程序的导航堆栈进行回退,从而返回到上一个页面。
- 我们还添加了两个按钮,分别用于导航到下一个页面和上一个页面。
通过使用 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(),
);
}
}
在这个示例中:
- 我们创建了一个
BadgeExample
页面,并在Center
组件中放置了一个Badge
和一个ElevatedButton
。 Badge
组件包裹了一个IconButton
。当用户点击这个按钮时,可以执行一些操作,例如打开通知列表。- 我们使用
badgeContent
属性来显示未读消息数量(_unreadCount
)。当未读消息数量增加时,Badge
组件会更新其外观,以反映最新的未读消息数量。 - 我们添加了一个
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(),
);
}
}
在这个示例中:
- 我们创建了一个
CloseButtonExample
页面,并在Scaffold
的body
中放置了一个ElevatedButton
和一个可选的模态窗口。 - 当用户点击 "Show Modal" 按钮时,我们会设置
_showModal
变量为true
,从而显示模态窗口。 - 在模态窗口的右上角,我们使用了
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;
}
}
在这个示例中:
- 我们创建了一个
FloatingButtonLayout
小部件,它包含了一个Scaffold
和一个Stack
。 - 在
Stack
中,我们添加了一个填充页面的Container
,并在其上放置了一个CustomSingleChildLayout
。 CustomSingleChildLayout
使用了一个自定义的_FloatingButtonLayoutDelegate
,它实现了三个关键方法:getSize
: 返回浮动按钮的大小。getPositionForChild
: 根据页面大小和按钮大小计算按钮的位置。在这个例子中,我们将它放在右下角。shouldRelayout
: 返回false
,因为这个布局不需要重新计算。
- 最后,我们在
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(),
);
}
}
在这个示例中:
- 我们创建了一个
MyApp
小部件,它包含了一个Scaffold
。 - 在
Scaffold
的body
中,我们使用了一个Directionality
小部件。 Directionality
的textDirection
属性设置为_textDirection
,这是一个TextDirection
类型的状态变量。- 在
Directionality
的子小部件中,我们放置了一个Text
小部件和两个切换按钮。 - 当用户点击"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(),
);
}
}
在这个示例中:
- 我们创建了一个
MyApp
小部件,它包含了一个Scaffold
。 - 在
Scaffold
的body
中,我们使用了一个EditableText
小部件。 EditableText
的controller
属性用于管理文本内容。在这个例子中,我们创建了一个TextEditingController
实例并将其传递给EditableText
。focusNode
属性用于管理文本输入框的焦点状态。在这个例子中,我们创建了一个新的FocusNode
实例。style
属性用于设置文本的样式,例如字体大小和颜色。cursorColor
和backgroundCursorColor
属性用于设置光标的颜色。onChanged
和onSubmitted
回调函数用于在文本发生变化或提交时执行自定义操作。
当用户与 EditableText
交互时,如输入、选择、剪切/复制/粘贴等操作,EditableText
会自动处理这些事件并更新文本内容。您可以通过 controller
属性访问和操作文本内容,并使用各种回调函数来监听和响应用户的输入。
EditableText
还提供了许多其他属性,如 obscureText
(用于实现密码输入框)、maxLines
和 maxLength
(用于控制输入长度)等。这些属性可以根据您的具体需求进行配置。
小结
本文从Flutter框架的视角,精选并介绍了几款鲜为人知却功能强大的UI组件,帮助开发者打造更优质的应用界面。包括AboutDialog、AnimatedGrid、Badge等隐藏宝藏,为您的Flutter项目注入新活力。
感谢阅读本文
如果有什么建议,请在评论中让我知道。我很乐意改进。
flutter 学习路径
- Flutter 优秀插件推荐 https://flutter.ducafecat.com
- Flutter 基础篇1 - Dart 语言学习 https://ducafecat.com/course/dart-learn
- Flutter 基础篇2 - 快速上手 https://ducafecat.com/course/flutter-quickstart-learn
- Flutter 实战1 - Getx Woo 电商APP https://ducafecat.com/course/flutter-woo
- Flutter 实战2 - 上架指南 Apple Store、Google Play https://ducafecat.com/course/flutter-upload-apple-google
- Flutter 基础篇3 - 仿微信朋友圈 https://ducafecat.com/course/flutter-wechat
- Flutter 实战3 - 腾讯即时通讯 第一篇 https://ducafecat.com/course/flutter-tim
- Flutter 实战4 - 腾讯即时通讯 第二篇 https://ducafecat.com/course/flutter-tim-s2
© 猫哥 ducafecat.com
end