首页 > 其他分享 >如何在Flutter中构建自定义Widget

如何在Flutter中构建自定义Widget

时间:2023-06-07 09:11:24浏览次数:45  
标签:Widget const 自定义 Text 代码 部件 Flutter

Flutter 最近越来越流行。您可以使用它来构建可在 MacOS、Windows 和 Linux 上顺畅运行的复杂应用程序。

但是构建这些应用程序并不总是一个简单的过程。您经常需要重构代码以保持应用程序的性能。

一种这样的重构技术是提取重复的代码和组件并在多个地方重用它们。

在本教程中,您将学习如何通过在 Flutter 中构建自定义小部件来替换重复的组件。

(更多优质教程:java567.com)

什么是自定义小部件?

在 Flutter 中,自定义小部件是指用户定义的小部件,它封装了一组特定的功能或视觉表示。

自定义小部件是 Flutter 应用程序的构建块。它们允许开发人员创建可在整个应用程序中使用的可重用 UI 组件。

如果您从 React Native 切换过来,您可以将自定义小部件视为自定义 React 组件。而我们props在 React 中调用的在 Flutter 中调用parameters。

为什么使用自定义小部件?

自定义小部件可帮助您封装复杂的 UI 元素。它们还提高了代码的可重用性并增强了 Flutter 应用程序的可维护性。

在 Flutter 中构建自定义小部件有很多原因。让我们看看其中的一些。

代码重用性

自定义小部件允许开发人员将复杂的功能和外观封装到可重用的组件中。

创建后,自定义小部件可以在整个应用程序中多次使用,从而减少代码重复并促进模块化开发方法。

可维护性

自定义小部件有助于代码库的可维护性。通过封装特定功能或可视化表示,自定义小部件创建关注点分离。这种分离使得查找、修改和调试与特定 UI 组件相关的代码变得更加容易。

一致的用户界面

它们还使开发人员能够在其应用程序中定义一致且统一的 UI 设计。

抽象

最后,自定义小部件提供了一个抽象级别,隐藏了特定 UI 元素的实现细节和复杂性。

您可以创建公开简化界面并处理内部逻辑的高级小部件。这允许其他开发人员使用该小部件而无需担心其内部运作。这种抽象促进了模块化,使代码更易于理解、测试和维护。

如何在 Flutter 中构建自定义 Widget

让我们开始构建我们的自定义小部件。

克隆回购

我没有从头开始,而是在GitHub中创建了一个 Flutter 应用程序,并在该存储库中添加了重复的代码/组件。让我们从那里开始。

通过运行以下命令从 GitHub 中提取代码:

 git clone https://github.com/5minslearn/Flutter-Custom-Widget.git
 ​
 or
 ​
 git clone [email protected]:5minslearn/Flutter-Custom-Widget.git

克隆回购

从 GitHub 克隆 Flutter Custom Widget 仓库

默认情况下,它将在master分支中。我正在切换到一个refactor分支(你不需要),因为我希望你们都看看我的初始和最终代码。初始代码将在master分支中,最终代码将在refactor分支中。

运行以下命令以安装所有依赖项:

 cd Flutter-Custom-Widget/
 flutter pub get

安装应用程序依赖项

安装 Flutter 依赖项

运行应用

在 Visual Studio Code 中打开存储库并启动您的模拟器(您也可以连接您的移动设备)。模拟器启动并运行后,按F5以在模拟器中运行该应用程序。

这是您的应用首次运行时的视图。

初始应用程序运行屏幕

如果你已经走到这一步,那就太好了。

分析代码

让我们看一下代码。打开lib/main.dart文件。

我们有一个MyApp名为开头的类。这反过来调用MyHomePage类。

这是我们在类中定义的整个 UI 的代码_MyHomePageState:

 class _MyHomePageState extends State<MyHomePage> {
   @override
   Widget build(BuildContext context) {
     return Scaffold(
       appBar: AppBar(
         title: Text(widget.title),
      ),
       body: Center(
         child: Column(
           mainAxisAlignment: MainAxisAlignment.center,
           children: [
             const Text('Welcome to Flutter Refactoring Tutorial',
                 style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20)),
             const SizedBox(height: 16),
             const Text('Press the below button to follow me on Twitter'),
             ElevatedButton(
               onPressed: () {
                 ScaffoldMessenger.of(context).showSnackBar(
                   const SnackBar(
                     content: Text("Pressed Follow on Twitter button"),
                     duration: Duration(seconds: 1),
                  ),
                );
                 // Open Twitter app
              },
               child: const Text("Follow on Twitter"),
            ),
             const SizedBox(height: 16),
             const Text('Press the below button to follow me on Instagram'),
             ElevatedButton(
               onPressed: () {
                 ScaffoldMessenger.of(context).showSnackBar(
                   const SnackBar(
                     content: Text("Pressed Follow on Instagram button"),
                     duration: Duration(seconds: 1),
                  ),
                );
                 // Open Instagram app
              },
               child: const Text("Follow on Instagram"),
            ),
          ],
        ),
      ),
    );
  }
 }

应用程序界面的代码

因此您可以参考行号,这是一个视觉效果:

应用程序界面的代码

如果你是一个喜欢写干净代码的人,你肯定会说这是丑陋的代码。

这是它的原因。仔细查看代码——第 44 到 56 行和第 58 到 70 行完全重复,除了极少数精心挑选的单词。例如,“Twitter”一词已被替换为“Instagram”一词。

干净的编码器肯定会在添加新特性/功能之前重构此代码。让我们现在也遵循那些干净的编码实践。

重构代码并构建自定义小部件

我们必须将文本和按钮提取到一个单独的组件中。该组件应接受platform和onPressed作为其参数。我们可以从中模板化出通用文本。

因此,我们构建自定义小部件的代码如下所示:

 class CustomButton extends StatelessWidget {
   final String platform;
   final VoidCallback onPressed;
   const CustomButton(
      {super.key, required this.platform, required this.onPressed});
   @override
   Widget build(BuildContext context) {
     return Center(
         child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [
       Text("Press the below button to follow me on $platform"),
       ElevatedButton(
         onPressed: () {
           ScaffoldMessenger.of(context).showSnackBar(
             SnackBar(
               content: Text("Pressed Follow on $platform button"),
               duration: const Duration(seconds: 1),
            ),
          );
           onPressed();
        },
         child: Text("Follow on $platform"),
      )
    ]));
  }
 }

创建自定义小部件

正如我们上面讨论的,模板文本和接受platform和onPressed参数。我们platform在需要的地方替换并调用该onPressed方法作为显示小吃店的扩展。

在文件的最后添加上面的代码main.dart。

集成自定义小部件

让我们将自定义小部件集成到我们的代码中。

从第 44 行到第 56 行选择第一个代码块,如下所示

             const Text('Press the below button to follow me on Twitter'),
             ElevatedButton(
               onPressed: () {
                 ScaffoldMessenger.of(context).showSnackBar(
                   const SnackBar(
                     content: Text("Pressed Follow on Twitter button"),
                     duration: Duration(seconds: 1),
                  ),
                );
                 // Open Twitter app
              },
               child: const Text("Follow on Twitter"),
            ),

重构第一段代码

将其替换为以下代码:

 CustomButton(
   platform: 'Twitter',
   onPressed: () {
     // Open Twitter App
  },
 ),

将我们的自定义小部件用于 Twitter 按钮

同样,从第 58 行到第 70 行选择下一个代码块,如下所示

             const Text('Press the below button to follow me on Instagram'),
             ElevatedButton(
               onPressed: () {
                 ScaffoldMessenger.of(context).showSnackBar(
                   const SnackBar(
                     content: Text("Pressed Follow on Instagram button"),
                     duration: Duration(seconds: 1),
                  ),
                );
                 // Open Instagram app
              },
               child: const Text("Follow on Instagram"),
            ),

重构第二块代码

将其替换为以下代码:

 CustomButton(
   platform: 'Instagram',
   onPressed: () {
     // Open Instagram App
  },
 ),

使用我们的 Instagram 按钮自定义小部件

_MyHomePageState这是我们完成重构过程后类的最终代码。

 class _MyHomePageState extends State<MyHomePage> {
   @override
   Widget build(BuildContext context) {
     return Scaffold(
       appBar: AppBar(
         title: Text(widget.title),
      ),
       body: Center(
         child: Column(
           mainAxisAlignment: MainAxisAlignment.center,
           children: [
             const Text('Welcome to Flutter Refactoring Tutorial',
                 style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20)),
             const SizedBox(height: 16),
             CustomButton(
               platform: 'Twitter',
               onPressed: () {
                 // Open Twitter App
              },
            ),
             const SizedBox(height: 16),
             CustomButton(
               platform: 'Instagram',
               onPressed: () {
                 // Open Instagram App
              },
            ),
          ],
        ),
      ),
    );
  }
 }

重构代码后

同样,这里是行号参考的屏幕截图:

重构代码后

立即运行您的应用程序。

遗憾的是,您不会注意到 UI 有任何变化。但是你的底层代码已经改变了。这正是重构的意义所在。

引用 Martin Fowler 的话,

重构是一种规范的技术,用于重构现有代码体,改变其内部结构而不改变其外部行为。

最终应用

看完上面的代码后,您可能想知道一些事情。第 43 和 50 行也包含相同的代码 ( const SizedBox(height: 16),)。那么我们为什么不将其包含到组件中呢?

如果你有这个问题,那就太好了。

自定义小部件组件不需要包含该SizedBox组件。这是因为SizedBox在主页中添加组件是为了在每个组件之间留出一些空间。但是,每当我们使用这个按钮时,我们都没有必要在小部件的顶部/底部留出一个空间。

不过,如果出现这种情况,您可以SizedBox在自定义小部件中添加小部件。

为什么要构建自定义小部件?

您可能不会立即看到直接的好处。但你可能会在未来体验到它。这是一个简单的例子。

假设您已经为客户构建了这个应用程序。它已成为一个复杂的应用程序,您已经在应用程序中大约 20 个地方使用了这个自定义小部件。该应用程序已发布,人们喜欢使用它。

大约 6 个月后,您的客户会带着下一个版本的更改返回给您。庞大清单中的一项是,“我们正在对主题进行轻微更改。替换所有社交媒体推荐按钮,使它们成为轮廓形状并将颜色更改为绿色”。

这是自定义小部件中的一个简单配置更改。但是想象一下,如果您没有构建自定义小部件并且必须在所有 20 个位置复制/粘贴相同的代码。然后你必须仔细查看每个地方并小心地替换每个实例而不触及其他代码段。

在此示例中,我们必须在自定义小部件中更改仅有的两行:

 OutlinedButton(
         style: OutlinedButton.styleFrom(foregroundColor: Colors.green),

根据上述要求对自定义小部件进行代码更改

我们自定义小部件的更改

但是,如果您没有重构代码,则必须在 20 个地方进行此更改。

小变化处处体现

我已将我的代码推送到同一个GitHub 存储库。master非重构代码参考分支,refactor重构代码参考分支。

自定义小部件的用例

始终针对其特定用例使用自定义小部件。例如,在我们的例子中,它用于社交媒体重定向。此小部件不应在与其上下文无关的地方使用。

如果这样做,请记住上面的案例,其中客户要求仅更改社交媒体推荐按钮的设计……但我们的更改将应用于使用此小部件的所有其他地方。这会导致意想不到的错误。

您应该始终为自定义小部件编写单元测试用例,这将帮助您更早地缓解任何错误。

还有一个技巧是以更易读的方式命名您的组件。这有助于其他开发人员仅通过阅读其名称就了解该小部件的作用。

在我们的例子中,我给它命名CustomButton是没有意义的。相反,一些好的替代方案是SocialMediaButton、SocialButton等等,它们适合我们的用例。

结论

在本教程中,您了解了如何通过删除重复的代码/组件来构建自定义小部件。

在 Flutter 中构建自定义小部件可提高代码的可重用性、可维护性、一致性、抽象性、灵活性和社区协作性。

自定义小部件是 Flutter 开发者工具包中的一个强大工具,使您能够创建美观实用的用户界面,同时最大限度地提高效率和可维护性。

(更多优质教程:java567.com)

标签:Widget,const,自定义,Text,代码,部件,Flutter
From: https://www.cnblogs.com/web-666/p/17462307.html

相关文章

  • 自定义上传图片,动态拼接html元素,node插入/替换指定位置旧元素
    <!DOCTYPEhtml><head>  <metaname="viewport"    content="width=device-width,initial-scale=0.5,maximum-scale=1.0,minimum-scale=0.5,user-scalable=yes">  <title>上传图片</title></head><bo......
  • Docker(二)自定义镜像
    Dockerfile是生成镜像脚本的应答文件,Dockerfile是比commit更强大的镜像编排方式Dockerfile语法格式:FROM:基础镜像MAINTAINER:镜像创建者信息EXPOSE:开放的端口ENV:设置变量ADD:复制文件到镜像RUN:制作镜像时执行的命令,可以有多个WORKDIR:定义容器默认工作目录CMD:容器启......
  • DjangoUeditor ImportError: No module named ‘widgets’的解决办法
    http://ojdbc.com/djangoueditor-importerror-no-module-named-widgets/最近在学习Django框架,按照网上教程集成DjangoUeditor时,出现错误,错误提示为:fromwidgetsimportUEditorWidget,AdminUEditorWidgetImportError:Nomodulenamed‘widgets’经查发现,DjangoUeditor是基于Pyt......
  • EasyExcel实战 自定义动态化导出excel
    1.Java操作excel表格,除了运用POI技术,阿里开发一个工具简易操作EasyExcel,接下来我们来实战操作下自定义动态化导出excel,自定义动态化为自定义标题,合并单元格引入pom<dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId>......
  • CKEditor (Toolbar Definition)工具栏自定义配置
    CKEditor中的工具栏默认显示所有功能按钮。出于安全的原因、或者是简化的原因,需要对这个工具栏进行自定义设置。CKEditor工具栏自定义配置非常简单。编辑ckeditor目录下的的config.js文件,默认的是下面的工具栏代码,注意工具按钮是分组的,一个name内的大括号就是一个工具按钮......
  • Flutter音频播放之just_audio
    just_audio的使用just_audio,它是一个用于播放音频的Flutter插件。安装和导入just_audio要使用just_audio库,需要将其添加到项目的pubspec.yaml文件中:dependencies:just_audio:^0.9.34然后运行以下命令以安装该库:flutterpubget要使用just_audio,需要在代码中......
  • flutter系列之:做一个会飞的菜单
    简介flutter中自带了drawer组件,可以实现通用的菜单功能,那么有没有一种可能,我们可以通过自定义动画来实现一个别样的菜单呢?答案是肯定的,一起来看看吧。定义一个菜单项目因为这里的主要目的是实现菜单的动画,所以这里的菜单比较简单,我们的menu是一个StatefulWidget,里面就是一个Co......
  • ubuntu自定义服务
    ubuntu自定义服务,以SRT Server为例① 创建编辑sudovi/etc/systemd/system/srt.service1[Unit]2Description=SRTServerService3After=network.targetsyslog.target4Wants=network.target56[Service]7Type=simple8ExecStart=/home/vikin/sr......
  • 《深度剖析CPython解释器》19. Python类机制的深度解析(第三部分): 自定义类的底层实
    https://www.cnblogs.com/traditional/p/13593927.html楔子Python除了给我提供了很多的类之外,还支持我们定义属于自己的类,那么Python底层是如何做的呢?我们下面就来看看。自定义class老规矩,如果想知道底层是怎么做的,那么就必须要通过观察字节码来实现。classGirl:nam......
  • SpringMVC里通过ResponseBodyAdvice接口实现统一自定义返回逻辑
    这个org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice接口。publicinterfaceResponseBodyAdvice<T>{//返回true代表走自定义逻辑booleansupports(MethodParameterreturnType,Class<?extendsHttpMessageConverter<?>>converte......