当前位置: 首页 > news >正文

【Flutter学习笔记】10.2 组合现有组件

参考资料: 《Flutter实战·第二版》 10.2 组合现有组件


在Flutter中页面UI通常都是由一些低级别组件组合而成,当我们需要封装一些通用组件时,应该首先考虑是否可以通过组合其他组件来实现,如果可以,则应优先使用组合,因为直接通过现有组件拼装会非常简单、灵活、高效。

10.2.1 实例:自定义渐变按钮

Flutter中自带的按钮组件不支持渐变背景,这里自定义一个GradientButton组件,具有下面的功能:

  1. 背景支持渐变色
  2. 手指按下时有涟漪效果
  3. 可以支持圆角
    自带的按钮组件是下面的效果:
    在这里插入图片描述
    其实除了不是渐变色背景其它都满足了。在Flutter中,ElevatedButton组件默认不具有圆角。然而,可以通过自定义其形状来为其添加圆角。可以在ElevatedButtonstyle属性中设置shape属性来实现:
ElevatedButton(  onPressed: () {  print('Button pressed!');  },  child: Text('Press Me'),  style: ElevatedButton.styleFrom(  primary: Colors.blue, // 设置按钮的主色  onPrimary: Colors.white, // 设置按钮上文字的颜色  shape: RoundedRectangleBorder( // 设置按钮的形状为圆角矩形  borderRadius: BorderRadius.circular(20.0), // 设置圆角的大小  ),  ),  )

在这里插入图片描述
想有渐变背景的话,不能通过style属性设置背景色,因为数据类型是有限制的。可以利用DecoratedBoxInkWell组合来实现,前者能够设置圆角和渐变背景色,后者可以提供涟漪效果。下面是实现代码,思路比较简单,主要是UI的绘制逻辑:

class GradientButton extends StatelessWidget {const GradientButton({Key? key, this.colors,this.width,this.height,this.onPressed,this.borderRadius,required this.child,}) : super(key: key);// 渐变色数组final List<Color>? colors;// 按钮宽高final double? width;final double? height;final BorderRadius? borderRadius;//点击回调final GestureTapCallback? onPressed;final Widget child;Widget build(BuildContext context) {ThemeData theme = Theme.of(context);//确保colors数组不空List<Color> _colors =colors ?? [theme.primaryColor, theme.primaryColorDark];return DecoratedBox(decoration: BoxDecoration(gradient: LinearGradient(colors: _colors),borderRadius: borderRadius,//border: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20.0)),),child: Material(type: MaterialType.transparency,child: InkWell(splashColor: _colors.last,highlightColor: Colors.transparent,borderRadius: borderRadius,onTap: onPressed,child: ConstrainedBox(constraints: BoxConstraints.tightFor(height: height, width: width),child: Center(child: Padding(padding: const EdgeInsets.all(8.0),child: DefaultTextStyle(style: const TextStyle(fontWeight: FontWeight.bold),child: child,),),),),),),);}
}

需要注意组件的输入属性,按钮点击的回调为GestureTapCallback类型,其属性除了child之外,均为可选属性。其具有默认样式,如果没有传入color属性,则默认为主题色主色调和暗色调。通过ConstrainedBox可以定义按钮的大小,还可以设置默认的字体样式(这里可以按需求去掉)。
定义好之后就可以使用了,这里定义了三个不同的按钮,代码和效果如下:

import 'dart:ui';import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';void main() {runApp(const MyApp());
}class MyApp extends StatelessWidget {const MyApp({super.key});// This widget is the root of your application.Widget build(BuildContext context) {return MaterialApp(title: 'Flutter Demo',theme: ThemeData(colorScheme: ColorScheme.fromSeed(seedColor: Colors.teal),useMaterial3: true,),home: const MyHomePage(title: 'TEAL WORLD'),);}
}class MyHomePage extends StatefulWidget {const MyHomePage({super.key, required this.title});final String title;State<MyHomePage> createState() => _MyHomePageState();
}class _MyHomePageState extends State<MyHomePage> {Widget build(BuildContext context) {return Scaffold(appBar: AppBar(backgroundColor: Theme.of(context).colorScheme.inversePrimary,title: Text(widget.title,style: TextStyle(color: Colors.teal.shade800, fontWeight: FontWeight.w900),),actions: [ElevatedButton(child: const Icon(Icons.refresh),onPressed: () {setState(() {});},)],),body: const ComponentTestRoute(),floatingActionButton: FloatingActionButton(onPressed: () {},tooltip: 'Increment',child: Icon(Icons.add_box,size: 30,color: Colors.teal[400],),), // This trailing comma makes auto-formatting nicer for build methods.);}
}class ComponentTestRoute extends StatefulWidget {const ComponentTestRoute({Key? key}) : super(key: key);ComponentTestRouteState createState() => ComponentTestRouteState();
}class ComponentTestRouteState extends State<ComponentTestRoute> {Widget build(BuildContext context) {return Row(children: [Expanded(child: Padding(padding: const EdgeInsets.only(top: 80),child: Column(children: [GradientButton(colors: const [Colors.purple, Colors.red],height: 50.0,child: const Text("Submit"),onPressed: () {},),GradientButton(height: 50.0,colors: [Colors.yellow, Colors.green.shade700],child: const Text("Submit"),onPressed: () {},),GradientButton(height: 50.0,//borderRadius: const BorderRadius.all(Radius.circular(5)),colors: const [Colors.cyanAccent, Colors.blueAccent],child: const Text("Submit"),onPressed: () {},),],),))],);}
}class GradientButton extends StatelessWidget {const GradientButton({Key? key,this.colors,this.width,this.height,this.onPressed,this.borderRadius,required this.child,}) : super(key: key);// 渐变色数组final List<Color>? colors;// 按钮宽高final double? width;final double? height;final BorderRadius? borderRadius;//点击回调final GestureTapCallback? onPressed;final Widget child;Widget build(BuildContext context) {ThemeData theme = Theme.of(context);//确保colors数组不空List<Color> _colors =colors ?? [theme.primaryColor, theme.primaryColorDark];return DecoratedBox(decoration: BoxDecoration(gradient: LinearGradient(colors: _colors),borderRadius: borderRadius,//border: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20.0)),),child: Material(type: MaterialType.transparency,child: InkWell(splashColor: _colors.last,highlightColor: Colors.transparent,borderRadius: borderRadius,onTap: onPressed,child: ConstrainedBox(constraints: BoxConstraints.tightFor(height: height, width: width),child: Center(child: Padding(padding: const EdgeInsets.all(8.0),child: DefaultTextStyle(style: const TextStyle(fontWeight: FontWeight.bold),child: child,),),),),),),);}
}

按下之后涟漪的颜色为colors中最后一个颜色:
在这里插入图片描述
虽然实现起来较为容易,但是在抽离出单独的组件时要考虑代码规范性,如必要参数要用required关键词标注,对于可选参数在特定场景需要判空设置默认值等。为了保证代码健壮性,我们需要在用户错误地使用组件时能够兼容或报错提示(使用assert断言函数)。

在Dart语言中,assert 是一种用于在开发过程中捕获错误的工具。assert 语句用于在调试模式下测试某个条件是否为真。如果条件为假,那么 assert 语句将抛出一个 AssertionError 异常,并停止程序的执行。这主要用于在开发过程中捕捉不应该发生的错误情况,从而帮助开发者定位问题。
assert 语句在发布模式(即生产环境)下会被忽略,因此不会影响最终用户的体验。这使得 assert 成为开发过程中进行条件测试的理想工具,而无需担心在最终应用中引入额外的性能开销或错误处理逻辑。

下面是assert在Dart中的基本用法:

void main() {  int number = 5;  // 使用 assert 语句检查 number 是否大于 0  assert(number > 0, 'number should be greater than 0');  // 如果条件为真,程序继续执行  print('Number is positive.');  // 如果条件为假,抛出 AssertionError,并显示提供的错误消息  // assert(number < 0, 'number should be less than 0'); // 这会抛出 AssertionError  
}

相关文章:

【Flutter学习笔记】10.2 组合现有组件

参考资料&#xff1a; 《Flutter实战第二版》 10.2 组合现有组件 在Flutter中页面UI通常都是由一些低级别组件组合而成&#xff0c;当我们需要封装一些通用组件时&#xff0c;应该首先考虑是否可以通过组合其他组件来实现&#xff0c;如果可以&#xff0c;则应优先使用组合&…...

C++的vector类(一):vector类的常见操作

目录 前言 Vector类 遍历与初始化vector ​vector的扩容机制 vector的对象操作 find与insert 对象数组 前言 string类中还有一些内容需要注意&#xff1a; STL 的string类怎么啦&#xff1f; C面试中string类的一种正确写法 C STL string的Copy-On-Write技术 C的st…...

SpringBoot注解

Spring Boot 中常用的一些注解及其作用如下所示&#xff1a; SpringBootApplication&#xff1a;标注一个主程序类&#xff0c;用于启动 Spring Boot 应用&#xff0c;通常放在包的最顶层。 RestController&#xff1a;结合 Controller 和 ResponseBody&#xff0c;用于定义 R…...

每日三个JAVA经典面试题(十九)

1.Java Concurrency API 中的 Lock 接口(Lock interface)是什么&#xff1f;对比同步它有什么优势&#xff1f;Java并发API中的Lock接口提供了一种比传统synchronized块或方法更灵活、更强大的线程同步机制。Lock接口允许更细粒度的锁控制&#xff0c;通过它可以实现更复杂的线…...

springboot企业级抽奖项目业务一(登录模块)

开发流程 该业务基于rouyi生成好了mapper和service的代码&#xff0c;现在需要在controller层写接口 实际操作流程&#xff1a; 看接口文档一>controller里定义函数一>看给出的工具类一>补全controller里的函数一>运行测试 接口文档 在登录模块有登录和登出方…...

【Python + Django】启动简单的文本页面

前言&#xff1a; 为了应付&#xff08;bushi&#xff09;毕业论文&#xff0c;总要自己亲手搞一个像模像样的项目出来吧 ~ ~ 希望自己能在新的连载中学到项目搭建的知识&#xff0c;这也算是为自己的测试经历增添光彩吧&#xff01;&#xff01;&#xff01; 希望、希望大家…...

Docker——问题解决:服务器端和Windows端IP互通

踩了大坑&#xff0c;特此记录&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; 我在服务器端部署了服务&#xff0c;但是在本地端Windows机器上无法访问&#xff0c;因此卡了一天。 1. 双向Ping通 防火墙导致只能单向Ping通 首先需要解决双向ping通的问题&…...

HTTP跨域

1. 简介 HTTP跨域是指不同域名下的网页请求资源时&#xff0c;由于浏览器同源策略限制&#xff0c;导致请求被阻止。为解决这一问题&#xff0c;开发者常采用跨域资源共享&#xff08;CORS&#xff09;等技术来允许合法跨域请求&#xff0c;确保网站功能正常运行。 同源 协议…...

用Python的turtle库绘制皮卡丘

turtle库的简介 turtle(海龟)库是turtle绘图体系的python实现&#xff0c;turtle库是一种标准库&#xff0c;是python自带的。 turtle(海龟)是一种真实的存在&#xff0c;有一个海龟在窗口的正中心&#xff0c;在画布上游走&#xff0c;走过的轨迹形成了绘制的图形&#xff0…...

C语言打印当前时间

#include <time.h> void print_current_time(char* func_name) { // 获取当前的时间 time_t current_time; time(&current_time); // 将时间转换为本地时间格式 struct tm *local_time localtime(&current_time); // 打印当前的时间 …...

(一)基于IDEA的JAVA基础4

注释文本&#xff0c;注释模版 单行注释://开头放在代码前面&#xff0c;对少部分。 多行注释:快捷方式ctrlshift/,对段落代码注 释。 文档注释:/**……**/&#xff0c;用于声明作者或创作时 间。 文档注释如何设置&#xff0c;首先找到File中…...

【Python】复习12:标准库与第三方库

目录 概念标准库第三方库总结Python 标准库`os` 模块`sys` 模块`json` 模块`re` 模块`datetime` 模块代码示例`os` 模块例子`sys` 模块例子`json` 模块例子`re` 模块例子`datetime` 模块例子第三方库`numpy``pandas``requests`安装第三方库使用第三方库其他一些流行的Python库数…...

CUDA 12介绍

CUDA&#xff08;Compute Unified Device Architecture&#xff09;是由 NVIDIA 开发的并行计算平台和应用程序编程接口&#xff08;API&#xff09;。CUDA 使开发人员能够使用 NVIDIA GPU 进行通用目的的并行计算。CUDA 通过利用 GPU 的大规模并行计算能力来加速各种类型的计算…...

旅游系统-软件与环境

运行 1.下载软件并进行环境配置 2.导入项目包以及SQL文件 (1)VsCode 管理员运行打开 a.新建terminal 注意&#xff1a; 1.执行 npm config set registry https://registry.npm.taobao.org 2.执行 npm install 3.执行 $env:NODE_OPTIONS“–openssl-legacy-provider” b.输入…...

AI基础知识(2)--决策树,神经网络

1.什么是决策树&#xff1f; 决策树是一类常见的机器学习方法&#xff0c;决策树是基于树的结构来进行决策。决策过程中提出的每一个问题都是对于属性的“测试”&#xff0c;决策的最终结论对应了我们希望的判定结果。一个决策树包含一个根节点&#xff0c;若干个内部节点和若…...

蓝桥杯C++大学B组一个月冲刺记录2024/3/21

蓝桥杯C大学B组一个月冲刺记录2024/3/20 规则&#xff1a;每日三题 今日的题很简单┗|&#xff40;O′|┛ 嗷~~ 1.奶酪 现有一块大奶酪&#xff0c;它的高度为 h &#xff0c;它的长度和宽度我们可以认为是无限大的&#xff0c;奶酪中间有许多半径相同的球形空洞。 我们可以在…...

由浅到深认识C语言(14):枚举

该文章Github地址&#xff1a;https://github.com/AntonyCheng/c-notes 在此介绍一下作者开源的SpringBoot项目初始化模板&#xff08;Github仓库地址&#xff1a;https://github.com/AntonyCheng/spring-boot-init-template & CSDN文章地址&#xff1a;https://blog.csdn…...

速盾cdn:cdn节点缓存内容不一致怎么办?

在使用CDN服务时&#xff0c;有时候可能会遇到CDN节点缓存内容不一致的情况。这种情况会导致用户访问网站时获取到的内容不一致&#xff0c;给用户带来困惑和不良体验。那么当遇到这种情况时&#xff0c;我们应该如何解决呢&#xff1f; 首先&#xff0c;我们需要了解CDN是如何…...

【LAMMPS学习】三、构建LAMMPS(6)在构建中包含软件包

3. 构建 LAMMPS 3.6.在构建中包含软件包 在 LAMMPS 中&#xff0c;包是一组启用一组特定功能的文件。例如&#xff0c;分子系统的力场或刚体约束都在封装中。在 src 目录中&#xff0c;每个包都是一个子目录&#xff0c;包名称为大写字母。 包文档页面上给出了包的概述。每…...

apache commons-dbcp Apache Commons DBCP 软件实现数据库连接池 commons-dbcp2

DBCP组件 许多Apache项目支持与关系型数据库进行交互。为每个用户创建一个新连接可能很耗时&#xff08;通常需要多秒钟的时钟时间&#xff09;&#xff0c;以执行可能需要毫秒级时间的数据库事务。对于一个公开托管在互联网上的应用程序&#xff0c;在同时在线用户数量可能非…...

vscode里如何用git

打开vs终端执行如下&#xff1a; 1 初始化 Git 仓库&#xff08;如果尚未初始化&#xff09; git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...

工业安全零事故的智能守护者:一体化AI智能安防平台

前言&#xff1a; 通过AI视觉技术&#xff0c;为船厂提供全面的安全监控解决方案&#xff0c;涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面&#xff0c;能够实现对应负责人反馈机制&#xff0c;并最终实现数据的统计报表。提升船厂…...

使用分级同态加密防御梯度泄漏

抽象 联邦学习 &#xff08;FL&#xff09; 支持跨分布式客户端进行协作模型训练&#xff0c;而无需共享原始数据&#xff0c;这使其成为在互联和自动驾驶汽车 &#xff08;CAV&#xff09; 等领域保护隐私的机器学习的一种很有前途的方法。然而&#xff0c;最近的研究表明&…...

iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版​分享

平时用 iPhone 的时候&#xff0c;难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵&#xff0c;或者买了二手 iPhone 却被原来的 iCloud 账号锁住&#xff0c;这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...

【磁盘】每天掌握一个Linux命令 - iostat

目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat&#xff08;I/O Statistics&#xff09;是Linux系统下用于监视系统输入输出设备和CPU使…...

Java - Mysql数据类型对应

Mysql数据类型java数据类型备注整型INT/INTEGERint / java.lang.Integer–BIGINTlong/java.lang.Long–––浮点型FLOATfloat/java.lang.FloatDOUBLEdouble/java.lang.Double–DECIMAL/NUMERICjava.math.BigDecimal字符串型CHARjava.lang.String固定长度字符串VARCHARjava.lang…...

基础测试工具使用经验

背景 vtune&#xff0c;perf, nsight system等基础测试工具&#xff0c;都是用过的&#xff0c;但是没有记录&#xff0c;都逐渐忘了。所以写这篇博客总结记录一下&#xff0c;只要以后发现新的用法&#xff0c;就记得来编辑补充一下 perf 比较基础的用法&#xff1a; 先改这…...

令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍

文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结&#xff1a; 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析&#xff1a; 实际业务去理解体会统一注…...

LLM基础1_语言模型如何处理文本

基于GitHub项目&#xff1a;https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken&#xff1a;OpenAI开发的专业"分词器" torch&#xff1a;Facebook开发的强力计算引擎&#xff0c;相当于超级计算器 理解词嵌入&#xff1a;给词语画"…...

多种风格导航菜单 HTML 实现(附源码)

下面我将为您展示 6 种不同风格的导航菜单实现&#xff0c;每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...