Flutter自定义组件插件groovin_widgets的使用

发布于 1周前 作者 sinazl 来自 Flutter

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

1 回复

更多关于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,
            ),
          ],
        ),
      ),
    );
  }
}

注意事项

  1. 导入包:确保正确导入了groovin_widgets包。
  2. 使用组件:根据groovin_widgets文档中提供的组件和属性,配置和使用这些组件。
  3. 事件处理:为组件添加事件处理逻辑,例如按钮点击事件。

自定义组件扩展

如果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中的组件。

回到顶部