Flutter自定义组件插件groovin_widgets的使用
Flutter自定义组件插件groovin_widgets的使用
🍪 groovin_widgets
groovin_widgets
是一个由GroovinChip创建和编辑的Flutter包,它包含了一系列的Widget和实用工具。这些组件和工具可以帮助开发者更轻松地构建美观且功能丰富的Flutter应用。
包含的Widgets
- ModalDrawerHandle: 用于在modalBottomSheets中添加高度可定制的抽屉手柄。
- OutlineDropdownButton: 带有边框的下拉按钮,支持更多的自定义选项。
- OutlineDropdownButtonFormField: 类似于OutlineDropdownButton,但为表单进行了优化。
- GroovinExpansionTile: 可以自定义外观的展开瓷砖。
- SplitColorBackground: 实现分色背景效果,适合模仿设计网站上的样式。
- AvatarBackButton: 创建带有用户头像的返回按钮。
- ScrollControllerBuilder: 提供一个ScrollController给子widget,使需要ScrollController的widget可以完全声明式地工作。
包含的Utilities
- HexColor类: 根据十六进制字符串值返回颜色。
- textLuminance函数: 根据给定的背景颜色帮助确定文本颜色。
- printFormattedJson函数: 将格式化的JSON打印到控制台。
示例代码
以下是groovin_widgets
库的一个完整示例demo:
import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:groovin_widgets/groovin_widgets.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'GroovinWidgets demo',
theme: ThemeData(
brightness: Brightness.light,
primaryColor: Colors.indigo,
visualDensity: VisualDensity.adaptivePlatformDensity,
colorScheme: ColorScheme.fromSwatch().copyWith(
brightness: Brightness.light,
secondary: Colors.indigoAccent,
),
),
darkTheme: ThemeData(
brightness: Brightness.dark,
primaryColor: Colors.indigo,
visualDensity: VisualDensity.adaptivePlatformDensity,
colorScheme: ColorScheme.fromSwatch().copyWith(
surface: ThemeData.dark().canvasColor,
onSurface: const ColorScheme.dark().onSurface,
brightness: Brightness.dark,
secondary: Colors.indigoAccent,
),
),
themeMode: ThemeMode.system,
home: const GroovinWidgetsDemo(),
debugShowCheckedModeBanner: false,
);
}
}
class GroovinWidgetsDemo extends StatefulWidget {
const GroovinWidgetsDemo({super.key});
@override
State<GroovinWidgetsDemo> createState() => _GroovinWidgetsDemoState();
}
class _GroovinWidgetsDemoState extends State<GroovinWidgetsDemo> {
String? value;
bool isExpanded = false;
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth >= 700) {
// Tablet layout
return Scaffold(
appBar: AppBar(
elevation: 0,
automaticallyImplyLeading: false,
title: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
AvatarBackButton(
backButton: const AdaptiveBackIcon(),
avatar:
'https://avatars.githubusercontent.com/u/4250470?s=460&u=ba3546d38c6f3dcc65d7451e3f6d7893ca4dfde8&v=4',
onPressed: () => debugPrint('tap'),
),
const SizedBox(width: 8),
const Text('GroovinWidgets'),
],
),
),
body: ScrollControllerBuilder(
builder: (_, controller) {
return SingleChildScrollView(
controller: controller,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(16.0),
child: OutlineDropdownButton(
items: const [
DropdownMenuItem(
value: 'Test Item',
child: Text('Test Item'),
),
],
isExpanded: true,
hint: const Text('Test Hint'),
value: value,
onChanged: (value) => debugPrint(value),
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: GroovinExpansionTile(
defaultTrailingIconColor: Colors.indigoAccent,
leading: const CircleAvatar(
backgroundColor: Colors.indigoAccent,
child: Icon(
Icons.person,
color: Colors.white,
),
),
title: const Text('Test Person'),
subtitle: const Text('123-456-7890'),
onExpansionChanged: (value) {
setState(() => isExpanded = value);
},
inkwellRadius: !isExpanded
? const BorderRadius.all(Radius.circular(8.0))
: const BorderRadius.only(
topRight: Radius.circular(8.0),
topLeft: Radius.circular(8.0),
),
children: <Widget>[
ClipRRect(
borderRadius: const BorderRadius.only(
bottomLeft: Radius.circular(5.0),
bottomRight: Radius.circular(5.0),
),
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 4.0),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: <Widget>[
IconButton(
icon: const Icon(Icons.delete),
onPressed: () {},
),
IconButton(
icon: const Icon(Icons.notifications),
onPressed: () {},
),
IconButton(
icon: const Icon(Icons.edit),
onPressed: () {},
),
IconButton(
icon: const Icon(Icons.comment),
onPressed: () {},
),
IconButton(
icon: const Icon(Icons.phone),
onPressed: () {},
),
],
),
),
],
),
),
],
),
),
Padding(
padding: const EdgeInsets.all(16.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Container(
color: Colors.indigo,
padding: const EdgeInsets.all(16.0),
child: Center(
child: Text(
'Luminance',
style: TextStyle(
color: textLuminance(Colors.indigo),
),
),
),
),
Container(
color: Colors.grey.shade300,
padding: const EdgeInsets.all(16.0),
child: Center(
child: Text(
'Luminance',
style: TextStyle(
color: textLuminance(Colors.grey.shade300),
),
),
),
),
],
),
),
],
),
);
},
),
floatingActionButton: FloatingActionButton(
child: const Icon(Icons.drag_handle),
onPressed: () => showModalBottomSheet(
context: context,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(8),
topRight: Radius.circular(8),
),
),
builder: (builder) {
return const SizedBox(
height: 250.0,
child: Column(
children: <Widget>[
Padding(
padding: EdgeInsets.all(8.0),
child: ModalDrawerHandle(
handleColor: Colors.indigoAccent,
),
),
],
),
);
},
),
),
);
} else {
// Mobile layout
return SplitColorBackground(
headerColor: Colors.indigo,
appBar: AppBar(
elevation: 0,
automaticallyImplyLeading: false,
title: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
AvatarBackButton(
backButton: const AdaptiveBackIcon(),
avatar:
'https://avatars.githubusercontent.com/u/4250470?s=460&u=ba3546d38c6f3dcc65d7451e3f6d7893ca4dfde8&v=4',
onPressed: () => debugPrint('tap'),
),
const SizedBox(width: 8),
const Text('GroovinWidgets'),
],
),
),
header: const SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'SplitColorBackground Header',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
],
),
),
body: Center(
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(16.0),
child: OutlineDropdownButton<String?>(
items: const [
DropdownMenuItem(
value: 'Test Item',
child: Text('Test Item'),
),
],
isExpanded: true,
hint: const Text('Test Hint'),
value: value,
onChanged: (value) => debugPrint(value),
),
),
Padding(
padding: const EdgeInsets.only(
left: 16.0,
right: 16.0,
),
child: GroovinExpansionTile(
defaultTrailingIconColor: Colors.indigoAccent,
leading: const CircleAvatar(
backgroundColor: Colors.indigoAccent,
child: Icon(
Icons.person,
color: Colors.white,
),
),
title: const Text(
'Test Person',
),
subtitle: const Text('123-456-7890'),
onExpansionChanged: (value) {
setState(() => isExpanded = value);
},
inkwellRadius: !isExpanded
? const BorderRadius.all(Radius.circular(8.0))
: const BorderRadius.only(
topRight: Radius.circular(8.0),
topLeft: Radius.circular(8.0),
),
children: <Widget>[
ClipRRect(
borderRadius: const BorderRadius.only(
bottomLeft: Radius.circular(5.0),
bottomRight: Radius.circular(5.0),
),
child: Column(
children: <Widget>[
Padding(
padding:
const EdgeInsets.symmetric(horizontal: 4.0),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: <Widget>[
IconButton(
icon: const Icon(Icons.delete),
onPressed: () {},
),
IconButton(
icon: const Icon(Icons.notifications),
onPressed: () {},
),
IconButton(
icon: const Icon(Icons.edit),
onPressed: () {},
),
IconButton(
icon: const Icon(Icons.comment),
onPressed: () {},
),
IconButton(
icon: const Icon(Icons.phone),
onPressed: () {},
),
],
),
),
],
),
),
],
),
),
Padding(
padding: const EdgeInsets.all(16.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Container(
color: Colors.indigo,
padding: const EdgeInsets.all(16.0),
child: Center(
child: Text(
'Luminance',
style: TextStyle(
color: textLuminance(Colors.indigo),
),
),
),
),
Container(
color: Colors.grey.shade300,
padding: const EdgeInsets.all(16.0),
child: Center(
child: Text(
'Luminance',
style: TextStyle(
color: textLuminance(Colors.grey.shade300),
),
),
),
),
],
),
),
],
),
),
bodyFlex: 4,
floatingActionButton: FloatingActionButton(
child: const Icon(Icons.drag_handle),
onPressed: () => showModalBottomSheet(
context: context,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(8),
topRight: Radius.circular(8),
),
),
builder: (builder) {
return const SizedBox(
height: 250.0,
child: Column(
children: <Widget>[
Padding(
padding: EdgeInsets.all(8.0),
child: ModalDrawerHandle(
handleColor: Colors.indigoAccent,
),
),
],
),
);
},
),
),
);
}
},
);
}
}
class AdaptiveBackIcon extends StatelessWidget {
const AdaptiveBackIcon({super.key});
@override
Widget build(BuildContext context) {
if (kIsWeb) {
return const Icon(Icons.arrow_back);
}
if (Platform.isIOS || Platform.isMacOS) {
return const Icon(CupertinoIcons.back);
} else {
return const Icon(Icons.arrow_back);
}
}
}
这个示例展示了如何使用groovin_widgets
中的各个组件,并且根据屏幕宽度调整布局(平板和手机)。你可以将此代码复制到你的项目中进行测试和学习。
更多关于Flutter自定义组件插件groovin_widgets的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter自定义组件插件groovin_widgets的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,下面是一个关于如何在Flutter中使用自定义组件插件groovin_widgets
的代码示例。为了简化,假设groovin_widgets
插件提供了一些预定义的自定义组件,我们将展示如何集成并使用这些组件。
首先,确保你已经在pubspec.yaml
文件中添加了groovin_widgets
依赖:
dependencies:
flutter:
sdk: flutter
groovin_widgets: ^最新版本号 # 替换为实际版本号
然后运行flutter pub get
来安装依赖。
示例代码
接下来,我们编写一个简单的Flutter应用,展示如何使用groovin_widgets
中的自定义组件。假设groovin_widgets
包含一个名为CustomButton
的按钮组件,我们可以这样使用它:
import 'package:flutter/material.dart';
import 'package:groovin_widgets/groovin_widgets.dart'; // 导入groovin_widgets包
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Groovin Widgets Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Groovin Widgets Demo'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
// 使用groovin_widgets中的CustomButton组件
CustomButton(
onPressed: () {
// 按钮点击事件处理
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Button Clicked!')),
);
},
text: 'Click Me',
color: Colors.blue,
textColor: Colors.white,
),
],
),
),
);
}
}
注意事项
- 导入包:确保正确导入了
groovin_widgets
包。 - 使用组件:根据
groovin_widgets
文档中提供的组件和属性,配置和使用这些组件。 - 事件处理:为组件添加事件处理逻辑,例如按钮点击事件。
自定义组件扩展
如果groovin_widgets
中的组件不满足需求,你还可以基于现有组件进行扩展和自定义。例如,假设你想要一个带有图标和文本的按钮,可以这样扩展:
import 'package:flutter/material.dart';
import 'package:groovin_widgets/groovin_widgets.dart';
class IconTextButton extends StatelessWidget {
final String text;
final IconData icon;
final VoidCallback onPressed;
final Color color;
final Color textColor;
const IconTextButton({
Key key,
this.text,
this.icon,
this.onPressed,
this.color = Colors.blue,
this.textColor = Colors.white,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: onPressed,
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(color),
foregroundColor: MaterialStateProperty.all(textColor),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Icon(icon),
SizedBox(width: 8), // 添加图标和文本之间的间距
Text(text),
],
),
);
}
}
// 使用自定义的IconTextButton组件
class MyHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Groovin Widgets Demo'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
IconTextButton(
icon: Icons.thumb_up,
text: 'Like',
onPressed: () {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Like Button Clicked!')),
);
},
),
],
),
),
);
}
}
以上代码展示了如何自定义一个带有图标和文本的按钮,并在Flutter应用中使用它。根据你的具体需求,你可以进一步扩展和自定义groovin_widgets
中的组件。