Flutter 实现验证码输入框学习

学习flutter代码 实现一个用于输入验证码的自定义组件,它允许用户输入固定长度的验证码,并在输入完成时触发回调。

前置知识点学习

TextStyle

`TextStyle` 是 Flutter 中用于定义文本样式的类。它提供了一组属性来控制文本的外观,如字体大小、颜色、粗细、字间距等。`TextStyle` 是 Flutter 应用中处理文本样式的核心部分,通过它可以实现丰富的文本展示效果。

`TextStyle` 的主要属性

1.`color`: 设置文本的颜色。可以使用 `Colors` 类提供的颜色常量或自定义颜色。

2.`fontSize`: 设置文本的字号大小,以逻辑像素为单位。

3.`fontWeight`: 定义文本的粗细程度。可以使用 `FontWeight` 枚举,如 `FontWeight.bold`。

4.`fontStyle`: 设置文本的样式(正常或斜体)。可以使用 `FontStyle` 枚举,如 `FontStyle.italic`。

5.`letterSpacing`: 设置字母之间的间距。

6.`wordSpacing`: 设置单词之间的间距。

7.`fontFamily`: 指定文本所使用的字体系列。可以是系统字体,也可以是自定义字体。

8.`backgroundColor`: 文本的背景颜色。

9.`decoration`: 为文本添加装饰,如下划线、上划线或删除线。可以使用 `TextDecoration` 枚举。

10.`decorationColor`: 文本装饰的颜色。

11.`decorationStyle`: 定义装饰线的样式,如实线、虚线等。可以使用 `TextDecorationStyle` 枚举。

12.`height`: 行高,相对于字体大小的倍数。

示例代码

以下是一个使用 `TextStyle` 的示例,展示了如何应用各种样式属性:



import 'package:flutter/material.dart';

class TextStyleExample extends StatelessWidget {
  const TextStyleExample({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('TextStyle Example'),
      ),
      body: const Center(
        child: Text(
          'Hello, Flutter!',
          style: TextStyle(
            color: Colors.blue,
            fontSize: 24.0,
            fontWeight: FontWeight.bold,
            fontStyle: FontStyle.italic,
            letterSpacing: 2.0,
            wordSpacing: 4.0,
            fontFamily: 'Roboto',
            decoration: TextDecoration.underline,
            decorationColor: Colors.red,
            decorationStyle: TextDecorationStyle.dashed,
          ),
        ),
      ),
    );
  }

}

代码解析

  • 颜色与大小:`color: Colors.blue` 和 `fontSize: 24.0` 分别设置了文本的颜色和字号。
  • 字体粗细与样式:使用 `fontWeight: FontWeight.bold` 使文本加粗,`fontStyle: FontStyle.italic` 设置为斜体。
  • 字间距与单词间距:`letterSpacing: 2.0` 增加字母间距,`wordSpacing: 4.0` 增加单词间距。
  • 字体系列:`fontFamily: 'Roboto'` 指定文本使用 Roboto 字体系列。
  • 文本装饰:`decoration: TextDecoration.underline` 添加下划线,`decorationColor: Colors.red` 和 `decorationStyle: TextDecorationStyle.dashed` 分别设置装饰线的颜色和样式。
  • 字体加载:当使用自定义字体时,确保在 `pubspec.yaml` 文件中正确配置字体资源,并在项目中包含字体文件。这将确保在所有平台上正确加载和显示自定义字体。
flutter:
  fonts:
    - family: Roboto
      fonts:
        - asset: fonts/Roboto-Regular.ttf
        - asset: fonts/Roboto-Bold.ttf
          weight: 700

  • 性能考虑:在大量文本或频繁更新文本样式的情况下,尽量减少不必要的样式变化,以提高性能。使用相同的 `TextStyle` 实例可以减少构建时间。
  • 继承与覆盖:`TextStyle` 支持通过 `copyWith` 方法创建一个新的样式对象,可以在现有样式的基础上进行局部修改:
TextStyle baseStyle = TextStyle(fontSize: 20.0, color: Colors.black);
TextStyle newStyle = baseStyle.copyWith(color: Colors.red);

这在需要在不同部分稍微调整样式时非常有用。

  • 样式优先级:如果 `TextStyle` 被应用于 `Text` 小部件,而 `Text` 小部件又嵌套在一个使用 `DefaultTextStyle` 的父小部件中,那么 `Text` 小部件的 `TextStyle` 将覆盖 `DefaultTextStyle` 的样式。

实际应用中的建议

  • 使用主题:在大型应用中,使用 `ThemeData` 来统一管理文本样式,可以通过 `Theme.of(context).textTheme` 获取预定义的文本样式。这样可以保持应用风格的一致性。
Text(
  'Themed Text',
  style: Theme.of(context).textTheme.headline6,
);
  • 响应式设计:在处理需要适配不同屏幕尺寸的文本时,可以结合 `MediaQuery` 或使用 `flutter_screenutil` 这样的库,根据屏幕尺寸动态调整 `fontSize`。
  • 国际化与本地化:在处理多语言支持时,确保字体和样式可以适应不同的字符集和语言特性。例如,某些语言可能需要更大的行高或不同的字体。

通过对 `TextStyle` 的深入理解,你可以在 Flutter 应用中创建美观、统一且响应式的文本展示效果。它是 Flutter UI 构建中不可或缺的一部分,熟练掌握它将帮助你更好地设计和实现高质量的用户界面。

ClipRRect

`ClipRRect` 是 Flutter 中的一个小部件,用于将其子组件裁剪为圆角矩形的形状。它非常适合在需要为组件添加圆角效果时使用,比如为图片、容器等添加圆角。`ClipRRect` 通过使用 `RRect`(圆角矩形)来定义裁剪的形状。

主要属性

1.`borderRadius`:

  • 类型:`BorderRadius`
  • 用于定义圆角的半径,可以指定每个角的圆角大小。
  • 示例:`BorderRadius.circular(8.0)` 会为所有角设置 8.0 的圆角。

2.`clipBehavior`:

  • 类型:`Clip`
  • 定义裁剪行为。常用值包括 `Clip.none`、`Clip.hardEdge`、`Clip.antiAlias` 和 `Clip.antiAliasWithSaveLayer`。
  • `Clip.antiAlias` 和 `Clip.antiAliasWithSaveLayer` 提供更平滑的边缘,但可能会影响性能。

3.`child`:

  • 被裁剪的子组件。可以是任何类型的 Widget。

使用场景

  • 应用圆角效果:为图片、按钮、容器等应用圆角效果。
  • 嵌套裁剪:在需要复杂形状裁剪的场合,可以结合其他裁剪小部件(如 `ClipOval`)使用。

示例代码


下面是一个简单的 `ClipRRect` 使用示例,将一张图片裁剪为圆角矩形:

import 'package:flutter/material.dart';

class ClipRRectExample extends StatelessWidget {
  const ClipRRectExample({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('ClipRRect Example'),
      ),
      body: Center(
        child: ClipRRect(
          borderRadius: BorderRadius.circular(16.0),
          child: Image.asset(
            "static/demo.png",
            width: 200,
            height: 200,
            fit: BoxFit.cover,
          ),
        ),
      ),
    );
  }
}

 代码解析

  • `borderRadius`: 使用 `BorderRadius.circular(16.0)` 为图片的四个角应用了 16.0 的圆角。
  • `child`: 包含了一张通过网络加载的图片。`ClipRRect` 将这张图片裁剪成带有圆角的矩形。

性能考虑

  • 裁剪性能:使用 `ClipRRect` 时,`clipBehavior` 会影响性能,尤其是在需要抗锯齿或使用 `saveLayer` 时。在性能敏感的场景中,尽可能选择 `Clip.hardEdge`,因为它是最快的选项。
  • 避免不必要的裁剪:如果可以通过布局或其他方式实现相同的效果,尽量避免使用 `ClipRRect`,因为裁剪操作会增加渲染开销。

总结


`ClipRRect` 是 Flutter 中用于实现圆角裁剪的强大工具。通过它,可以轻松地为任何组件添加圆角效果,使得应用的视觉效果更加美观和现代。在使用时,需要注意裁剪的性能影响,合理选择裁剪行为以达到最佳的性能和平滑度平衡。

AnimatedContainer

`AnimatedContainer` 是 Flutter 中一个非常有用的小部件,它在属性发生变化时可以自动动画化地过渡到新的属性。这使得创建动画效果和响应式界面变得非常简单,无需手动管理动画控制器或状态。

特性与属性


1.`duration`:

  • 类型:`Duration`
  • 指定动画过渡的持续时间。必须设置这个属性来定义动画的长短。
  • 示例:`Duration(seconds: 1)` 表示动画持续一秒。

2.`curve`:

  • 类型:`Curve`
  • 定义动画的曲线,决定了动画的加速度和减速度。常用曲线有 `Curves.easeIn`、`Curves.easeOut`、`Curves.bounceIn` 等。
  • 示例:`Curves.easeInOut` 表示动画以缓慢的速度开始和结束,但中间速度较快。

3.`alignment`:

  • 控制子组件的对齐方式。

4.`padding`:

  • 控制内部填充。

5.`color`:

  • 背景颜色。

6.`decoration` 和 `foregroundDecoration`:

  • `decoration` 用于背景装饰,例如边框、圆角、渐变等。
  • `foregroundDecoration` 用于在子组件前的装饰。

7.`width` 和 `height`:

  • 控制容器的宽度和高度。

8.`constraints`:

  • 设置容器的大小限制,例如最小和最大宽高。

9.`margin`:

  • 控制外部间距。

`10.transform`:

  • 应用于子组件的变换,例如旋转、缩放、平移等。

11.`child`:

  • 被包裹的子组件。

使用场景

  • 动画化尺寸变化:在用户交互后,动态调整组件的大小。
  • 背景颜色过渡:在状态改变时,平滑地过渡到新的背景颜色。
  • 位置和边距动画:在布局中通过调整位置和边距来创建动画效果。

示例代码

import 'package:flutter/material.dart';

class AnimatedContainerExample extends StatefulWidget {
  const AnimatedContainerExample({super.key});

  @override
  _AnimatedContainerExampleState createState() {
    return _AnimatedContainerExampleState();
  }
}

class _AnimatedContainerExampleState extends State<AnimatedContainerExample> {
  double _width = 100.0;
  double _height = 100.0;
  Color _color = Colors.blue;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('AnimatedContainer Example'),
      ),
      body: Center(
        child: GestureDetector(
          onTap: () {
            setState(() {
              _width = _width == 100.0 ? 200.0 : 100.0;
              _height = _height == 100.0 ? 200.0 : 100.0;
              _color = _color == Colors.blue ? Colors.red : Colors.blue;
            });
          },
          child: AnimatedContainer(
            width: _width,
            height: _height,
            color: _color,
            alignment: Alignment.center,
            duration: const Duration(seconds: 1),
            curve: Curves.easeInOut,
            child: const Text(
              'Tap me!',
              style: TextStyle(color: Colors.white, fontSize: 20.0),
            ),
          ),
        ),
      ),
    );
  }
}

BoxDecoration

`BoxDecoration` 是 Flutter 中用于装饰容器(如 `Container`)的一个类。它提供了一系列属性,允许你为容器添加背景颜色、渐变、图像、边框、阴影等装饰效果。`BoxDecoration` 结合 `Container` 使用,可以打造出丰富的视觉效果。

主要属性

1.`color`:

  • 类型:`Color`
  • 设置容器的背景颜色。

2.`image`:

  • 类型:`DecorationImage`
  • 用于在容器背景中绘制图像。
  • 可以指定图像的对齐方式、填充方式等。

3.`border`:

  • 类型:`Border`
  • 为容器添加边框。可以指定每条边的宽度和颜色。

4.`borderRadius`:

  • 类型:`BorderRadius`
  • 设置容器的圆角半径。

5.`boxShadow`:

  • 类型:`List`
  • 为容器添加阴影效果。可以指定阴影的颜色、偏移、模糊半径等。

6.`gradient`:

  • 类型:`Gradient`
  • 为容器添加渐变背景。支持线性渐变、径向渐变等。

7.`backgroundBlendMode`:

  • 类型:`BlendMode`
  • 设置背景颜色和图像的混合模式。

8.`shape`:

  • 类型:`BoxShape`
  • 指定容器的形状。可以是矩形(默认)或圆形。

使用场景

  • 背景颜色和图像:为容器添加背景颜色或图像。
  • 边框和圆角:为容器添加边框和圆角效果。
  • 阴影效果:为容器添加阴影,提升视觉层次感。
  • 渐变背景:使用渐变色为背景,打造现代化的视觉效果。

示例代码

以下是一个使用 `BoxDecoration` 的示例,展示了如何为容器添加背景颜色、圆角、边框和阴影:

import 'package:flutter/material.dart';

class BoxDecorationExample22 extends StatelessWidget {
  const BoxDecorationExample22({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('BoxDecoration Example'),
      ),
      body: Container(
        width: 200.0,
        height: 200.0,
        decoration: BoxDecoration(
          color: Colors.blue[200],
          borderRadius: BorderRadius.circular(20.0),
          border: Border.all(
            color: Colors.blue,
            width: 3.0,
          ),
          boxShadow: [
            BoxShadow(
              color: Colors.grey.withOpacity(0.5),
              spreadRadius: 5,
              blurRadius: 7,
              offset: const Offset(0, 3), // changes position of shadow
            ),
          ],
        ),
        child: const Center(
          child: Text(
            'Hello, Flutter!',
            style: TextStyle(color: Colors.white, fontSize: 20.0),
          ),
        ),
      ),
    );
  }
}

TextInputFormatter

`TextInputFormatter` 是 Flutter 中用于在用户输入文本时进行格式化和验证的一个抽象类。它允许你在文本被输入到文本字段之前对其进行修改或限制,这对于实现自定义的输入行为(如限制输入类型或长度)非常有用。

主要属性和方法

  • `formatEditUpdate`:
  • 方法:`TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue)`
  • 这是 `TextInputFormatter` 的核心方法,必须被重写。它接收旧的文本值和新的文本值,返回一个格式化后的文本值。
  • `TextEditingValue` 包含文本字段的当前状态,包括文本内容、光标位置和选择范围。

常用子类

1.`LengthLimitingTextInputFormatter`:

  • 用于限制输入文本的最大长度。
  • 构造时传入一个整数表示最大长度。
  • 示例:`LengthLimitingTextInputFormatter(10)` 限制输入长度为 10 个字符。

2.`FilteringTextInputFormatter`:

  • 用于过滤输入的文本,只允许符合特定模式的输入。
  • 提供了 `FilteringTextInputFormatter.digitsOnly` 来限制输入仅为数字。
  • 可以通过自定义正则表达式来实现更复杂的过滤。

示例代码

以下是如何使用 `LengthLimitingTextInputFormatter` 和 `FilteringTextInputFormatter` 的示例:

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

class TextInputFormatterExampleDemo extends StatelessWidget {
  const TextInputFormatterExampleDemo({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('TextInputFormatter Example'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          children: [
            TextField(
              decoration: const InputDecoration(
                labelText: 'Limited Length (Max 10)',
              ),
              inputFormatters: [
                LengthLimitingTextInputFormatter(10),
              ],
            ),
            const SizedBox(
              height: 20,
            ),
            TextField(
              decoration: const InputDecoration(
                labelText: 'Digits Only',
              ),
              keyboardType: TextInputType.number,
              inputFormatters: [
                FilteringTextInputFormatter.digitsOnly,
              ],
            )
          ],
        ),
      ),
    );
  }
}

 代码解析

  • 限制输入长度:第一个文本字段使用 `LengthLimitingTextInputFormatter(10)` 限制输入最大长度为 10 个字符。
  • 限制输入内容:第二个文本字段使用 `FilteringTextInputFormatter.digitsOnly` 限制输入仅为数字。

自定义格式化器


你可以通过继承 `TextInputFormatter` 并重写 `formatEditUpdate` 方法来创建自定义的输入格式化器。例如,创建一个格式化器来限制输入只能是大写字母:

class UpperCaseTextInputFormatter extends TextInputFormatter {
  @override
  TextEditingValue formatEditUpdate(
      TextEditingValue oldValue, TextEditingValue newValue) {
    return TextEditingValue(
      text: newValue.text.toUpperCase(),
      selection: newValue.selection,
    );
  }
}

使用场景

  • 限制输入的类型和格式(例如,只允许字母、数字或特定符号)。
  • 验证用户输入的格式是否符合特定规则(如电子邮件、电话号码)。
  • 动态调整用户输入,使其符合特定格式。

TextField

`TextField` 是 Flutter 中用于获取用户文本输入的一个重要组件。它提供了强大的功能和高度的可定制性,使开发者能够轻松地集成和管理用户输入。下面是对 `TextField` 的详细解析。

基本特性

1.文本输入:`TextField` 是用于用户输入文本的基本组件。

2.键盘类型:可以通过 `keyboardType` 属性设置输入时弹出的键盘类型,例如数字键盘、邮件键盘等。

3.样式和装饰:通过 `decoration` 属性可以自定义 `TextField` 的外观,包括提示文本、边框、标签等。

4.控制器:使用 `TextEditingController` 来管理和监听文本输入的变化。

5.输入格式化:使用 `inputFormatters` 来限制和格式化用户输入,例如限制输入长度或只允许数字输入。

6.焦点控制:通过 `FocusNode` 可以控制和监听 `TextField` 的焦点状态。

主要属性

  • controller: `TextEditingController` 用于读取、设置和监听 `TextField` 的文本。
  • focusNode: `FocusNode` 用于管理和监听焦点状态。
  • decoration: `InputDecoration` 用于定义 `TextField` 的外观和样式。
  • keyboardType: `TextInputType` 确定输入时使用的键盘类型。
  • textInputAction: `TextInputAction` 确定操作按钮的类型,如“下一步”或“完成”。
  • onChanged: 输入内容更改时的回调函数。
  • onSubmitted: 用户提交(按下“完成”键)时的回调函数。
  • inputFormatters: `TextInputFormatter` 用于格式化输入文本。
  • obscureText: 用于密码输入,隐藏输入的字符。
  • maxLength: 限制最大输入长度。

示例代码

以下是一个基本的 `TextField` 示例,展示了如何使用控制器、装饰器和输入格式化器:

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

class TextFieldExample extends StatefulWidget {
  const TextFieldExample({super.key});

  @override
  _TextFieldExampleState createState() {
    return _TextFieldExampleState();
  }
}

class _TextFieldExampleState extends State<TextFieldExample> {
  final TextEditingController _controller = TextEditingController();
  final FocusNode _focusNode = FocusNode();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('TextField Example'),
      ),
      body: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Column(
            children: [
              TextField(
                controller: _controller,
                focusNode: _focusNode,
                decoration: const InputDecoration(
                  labelText: 'Enter your text',
                  border: OutlineInputBorder(),
                ),
                keyboardType: TextInputType.text,
                textInputAction: TextInputAction.done,
                onChanged: (text) {
                  print('Current text: $text');
                },
                onSubmitted: (text) {
                  print('Submitted text: $text');
                },
                inputFormatters: [
                  LengthLimitingTextInputFormatter(20),
                  FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9]')),
                ],
              ),
              const SizedBox(height: 20),
              ElevatedButton(
                onPressed: () {
                  // 打印当前文本框中的文本
                  print('Final text: ${_controller.text}');
                  // 移除焦点,使键盘消失
                  _focusNode.unfocus();
                },
                child: const Text('Print Text and Unfocus'),
              ),
            ],
          )),
    );
  }
}

代码解析

  • `TextEditingController`: 用于管理 `TextField` 的文本。可以通过 `_controller.text` 获取或设置输入文本。
  • `FocusNode`: 管理 `TextField` 的焦点状态。使用 `_focusNode.unfocus()` 可以移除焦点,通常用于隐藏键盘。
  • `InputDecoration`: 自定义 `TextField` 的外观,例如标签文本和边框。
  • `inputFormatters`: 使用 `LengthLimitingTextInputFormatter` 限制输入长度,以及 `FilteringTextInputFormatter.allow` 限制输入内容为字母和数字。
  • `keyboardType`: 设置为 `TextInputType.text`,用于一般文本输入。
  • `textInputAction`: 设置为 `TextInputAction.done`,表示用户完成输入时的操作。
  • 事件回调: `onChanged` 和 `onSubmitted` 允许在用户输入或提交时执行操作。

附加功能和用法

  • 密码输入: 设置 `obscureText: true` 可以隐藏输入的字符,用于密码输入框。
  • 多行输入: 通过设置 `maxLines` 属性,可以允许 `TextField` 输入多行文本。
  • 文本样式: 使用 `style` 属性自定义文本的外观,例如字体大小和颜色。
  • 错误信息: 使用 `errorText` 属性在 `InputDecoration` 中显示错误信息。
  • 自动填充: 在 Android 和 iOS 上,`TextField` 支持自动填充功能,可以通过 `autofillHints` 配置。

Border

在 Flutter 中,`Border` 是一个非常重要的类,用于定义组件(如容器、按钮或输入框)周围的边框。它提供了多种方式来自定义边框的样式、颜色和宽度。理解 `Border` 的各种属性和用法有助于创建更具吸引力和功能性的 UI。

`Border` 类的基本概念



`Border` 类通常用于定义一个组件的四个边的样式。它通常与 `BoxDecoration` 一起使用,以应用于 `Container` 或其他需要边框的组件。

 主要属性

  • `top`、`bottom`、`left`、`right`: 每个边框的样式,通过 `BorderSide` 定义,可以设置颜色、宽度和样式。
  • `all`: 使用同样的边框值应用到所有边。
  • `symmetric`: 为水平和垂直方向的边设置对称的边框。

`BorderSide` 类



`BorderSide` 是用来描述边框的样式的类,包含以下属性:

  • `color`: 边框的颜色。
  • `width`: 边框的宽度,默认为 1.0。
  • `style`: 边框的样式,`BorderStyle.solid`(实线)或 `BorderStyle.none`(无边框)。‘’

 

使用示例

以下是如何使用 `Border` 和 `BorderSide` 来自定义 `Container` 的边框:

import 'package:flutter/material.dart';

class BorderExampleDemo extends StatelessWidget {
  const BorderExampleDemo({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Border Example'),
      ),
      body: Center(
        child: Container(
          width: 200,
          height: 200,
          decoration: BoxDecoration(
              color: Colors.blue[50],
              border: const Border(
                top: BorderSide(
                  color: Colors.blue,
                  width: 3.0,
                  style: BorderStyle.solid,
                ),
                bottom: BorderSide(
                  color: Colors.green,
                  width: 5.0,
                  style: BorderStyle.solid,
                ),
                left: BorderSide(
                  color: Colors.red,
                  width: 2.0,
                  style: BorderStyle.solid,
                ),
                right: BorderSide(
                  color: Colors.orange,
                  width: 4.0,
                  style: BorderStyle.solid,
                ),
              )),
        ),
      ),
    );
  }
}


 

代码解析

  • `BoxDecoration`: 用于定义 `Container` 的视觉外观,包括颜色和边框。
  • `Border`: 使用 `Border` 类为 `Container` 的每一侧定义不同的 `BorderSide`。
  • `BorderSide`: 描述了每个边的颜色、宽度和样式。

常用方法

  • `Border.all()`: 创建一个统一的边框,所有边的样式相同。
decoration: BoxDecoration(
  border: Border.all(
    color: Colors.black,
    width: 2.0,
  ),
),
  •  `Border.symmetric()`: 为水平(`horizontal`)和垂直(`vertical`)方向定义对称的边框。
   decoration: BoxDecoration(
            color: Colors.yellow[50],
            border: Border.symmetric(
              vertical: BorderSide(
                color: Colors.red,
                width: 4.0,
              ),
              horizontal: BorderSide(
                color: Colors.blue,
                width: 2.0,
              ),
            ),
          ),

BorderRadius

`BorderRadius` 是 Flutter 中用于定义圆角矩形的类。它可以用于将边框、容器和其他矩形形状的角变圆。`BorderRadius` 提供了多种方法来定义角的圆度,允许你为每个角指定不同的半径,也可以为所有角指定相同的半径。

主要构造方法

1.`BorderRadius.circular(double radius)`: 为所有角设置相同的圆角半径。这个方法是最常用的,适合需要统一圆角的情况。

2.`BorderRadius.all(Radius radius)`: 使用 `Radius` 对象为所有角设置相同的半径。

3.`BorderRadius.only({Radius topLeft, Radius topRight, Radius bottomLeft, Radius bottomRight})`: 分别为每个角设置不同的半径,提供了最大的灵活性。

4.`BorderRadius.horizontal({Radius left, Radius right})`: 仅为水平的两个角设置半径。

5.`BorderRadius.vertical({Radius top, Radius bottom})`: 仅为垂直的两个角设置半径。

示例代码

以下是如何使用 `BorderRadius` 的一些示例:

1. 使用 `BorderRadius.circular`
import 'package:flutter/material.dart';

class CircularBorderExample extends StatelessWidget {
  const CircularBorderExample({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Circular Border Example')),
      body: Center(
        child: Container(
          width: 200,
          height: 200,
          decoration: BoxDecoration(
            color: Colors.blue[100],
            borderRadius: BorderRadius.circular(20.0), // 所有角为圆角 20.0
          ),
        ),
      ),
    );
  }
}

 

 2. 使用 `BorderRadius.only`
import 'package:flutter/material.dart';
class OnlyBorderExample extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Only Border Example')),
      body: Center(
        child: Container(
          width: 200,
          height: 200,
          decoration: BoxDecoration(
            color: Colors.green[100],
            borderRadius: BorderRadius.only(
              topLeft: Radius.circular(30.0),
              bottomRight: Radius.circular(30.0),
            ),
          ),
        ),
      ),
    );
  }
}
3. 使用 `BorderRadius.horizontal`
import 'package:flutter/material.dart';
class HorizontalBorderExample extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Horizontal Border Example')),
      body: Center(
        child: Container(
          width: 200,
          height: 200,
          decoration: BoxDecoration(
            color: Colors.red[100],
            borderRadius: BorderRadius.horizontal(
              left: Radius.circular(20.0),
              right: Radius.circular(50.0),
            ),
          ),
        ),
      ),
    );
  }
}

 EditableText

在 Flutter 中,`EditableText` 是文本输入框的核心控件,所有类似 `TextField` 和 `TextFormField` 的控件都是基于 `EditableText` 封装的。`EditableText` 提供了更底层的能力,允许开发者对文本输入框的行为进行高度自定义。

1. 什么是 `EditableText`?

`EditableText` 是一个可编辑的文本组件,用于实现完全可控的文本输入功能。它不像 `TextField` 那样提供一套高阶封装,而是提供了对文本输入的较底层控制,包括:

  • 文本内容的管理
  • 焦点的获取与丢失
  • 自定义光标、样式、输入法行为
  • 输入格式化器和验证规则

 2. `EditableText` 的核心属性解析

以下是 `EditableText` 的关键属性及其作用:

必需的属性

属性

类型

描述

`controller`

`TextEditingController`

管理输入框内容的核心控制器,可监听文本变化或更新文本。

`focusNode`

`FocusNode`

管理输入框焦点状态的节点。可判断输入框是否聚焦并控制焦点行为。

`style`

`TextStyle`

定义输入文本的样式(如字体大小、文本颜色等)。

`cursorColor`

`Color`

设置光标的颜色。

`backgroundCursorColor`

`Color`

光标的背景颜色,当光标不可见时使用该颜色。

常用的属性

 属性

类型

描述

`obscureText`

`bool`

是否隐藏输入的文本(常用于密码输入)。

`autofocus`

`bool`

是否在构建时自动获取焦点。

`keyboardType`

`TextInputType`

设置键盘类型(如文本、数字、email等)。

`textAlign`

`TextAlign`

文本的对齐方式(如:左对齐、右对齐、居中)。

`maxLines`

`int`

设置输入框的最大行数,默认为 1。

`minLines`

`int`

设置输入框的最小行数。

`inputFormatters`

`List`

输入格式化器,可用来限制或过滤非法输入(如限制字数、屏蔽特殊字符等)。

onChanged`

`ValueChanged`

当文本内容发生变化时触发的回调函数。

`onEditingComplete`

`VoidCallback`

当用户完成编辑时(如按下键盘的“完成”按钮)触发的回调。

`onSubmitted`

`ValueChanged`

用户提交输入内容时触发的回调。

`readOnly`

`bool`

是否设置为只读模式(用户无法编辑文本)。

光标和样式相关属性

属性

类型

描述

`cursorWidth`

`double`

 

光标的宽度。默认值通常为 2.0 像素。

`cursorHeight`

`double?`

光标的高度。通常情况下,光标的高度与文本的高度一致,但你可以通过此属性自定义。

`cursorRadius`

`Radius?`

光标的圆角半径。如果需要圆角光标,可以在这里设置。

`cursorOpacityAnimates`

`bool`

如果为 true,光标的透明度会在显示和隐藏之间动画过渡。

`selectionHeightStyle`

`BoxHeightStyle`

控制文本选择时的高度样式。影响文本选择的外观。

`selectionWidthStyle`

`BoxWidthStyle`

控制文本选择时的宽度样式。通常与 `selectionHeightStyle` 一起使用。

其他重要属性

属性

类型

描述

`toolbarOptions`

`ToolbarOptions`

定义当用户长按输入框时,弹出工具栏中可用的选项(如剪切、复制、粘贴等)。

`showCursor`

`bool?`

控制光标是否显示。

`enableInteractiveSelection`

`bool`

控制是否允许用户交互式选择文本(如长按选择文本)。

`textCapitalization`

`TextCapitalization`

控制输入文本的自动大写行为(如每个单词首字母大写)。

使用 `EditableText` 的示例

以下是一个使用 `EditableText` 的完整示例,展示如何自定义一个简单的文本输入框:

import 'package:flutter/material.dart';

class EditableTextWidgetDemo extends StatefulWidget {
  const EditableTextWidgetDemo({super.key});

  @override
  _EditableTextWidgetState createState() {
    return _EditableTextWidgetState();
  }
}

class _EditableTextWidgetState extends State<EditableTextWidgetDemo> {
  final TextEditingController _controller = TextEditingController();
  final FocusNode _focusNode = FocusNode();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(title: const Text('TextEditingController Example')),
        body: Center(
            child: Padding(
          padding: const EdgeInsets.all(16.0),
          child: EditableText(
            controller: _controller,
            focusNode: _focusNode,
            style: const TextStyle(color: Colors.black, fontSize: 18.0),
            cursorColor: Colors.blue,
            backgroundCursorColor: Colors.grey,
            keyboardType: TextInputType.text,
            autofocus: true,
            maxLines: null,
            // 允许多行输入
            onChanged: (text) {
              print("Text changed: $text");
            },
          ),
        )));
  }

  @override
  void dispose() {
    _controller.dispose();
    _focusNode.dispose();
    super.dispose();
  }
}

总结

  • 灵活性: `EditableText` 提供了高度的灵活性和定制能力。虽然 `TextField` 和 `TextFormField` 已经满足了大多数日常需求,但 `EditableText` 允许开发者完全控制文本输入的细节。如果你需要实现一个非常定制化的文本输入体验,`EditableText` 是一个很好的起点。
  • 自定义控制: 通过 `EditableText`,你可以完全自定义光标的外观、文本样式、输入格式化、焦点行为、输入法行为等等。这使得它适合于需要特定文本输入行为的应用场景。
  • 底层实现: 作为 `TextField` 和 `TextFormField` 的底层实现,`EditableText` 需要开发者手动管理 `TextEditingController` 和 `FocusNode`,这意味着开发者必须更加关注资源的管理(例如确保在不需要时正确释放这些对象)。
  • 应用场景: 使用 `EditableText` 适用于需要精细控制用户输入的场景,比如自定义的文本编辑器、需要特殊输入验证的表单等。

通过了解和善用 `EditableText`,开发者可以创建更具个性化的用户输入界面,满足特定的应用需求。希望这个解析能够帮助你更好地理解和使用 `EditableText`。

GestureDetector

`GestureDetector` 是 Flutter 中一个非常重要的组件,用于检测用户的手势操作(如点击、双击、拖动、滑动等)。通过使用 `GestureDetector`,你可以捕获用户在屏幕上的各种手势,并对这些手势做出响应。这使得 `GestureDetector` 成为构建交互式用户界面的关键工具之一。

主要功能


`GestureDetector` 提供了一种简单而强大的方式来监听和响应用户的手势。以下是一些常用的手势检测功能:

点击手势:

  • `onTap`: 用户点击时触发。
  • `onDoubleTap`: 用户双击时触发。
  • `onLongPress`: 用户长按时触发。

拖动手势:

  • `onPanStart`: 用户开始拖动时触发。
  • `onPanUpdate`: 用户拖动过程中触发。
  • `onPanEnd`: 用户拖动结束时触发。

滑动手势:

  • `onHorizontalDragStart`, `onHorizontalDragUpdate`, `onHorizontalDragEnd`: 检测水平拖动。
  • `onVerticalDragStart`, `onVerticalDragUpdate`, `onVerticalDragEnd`: 检测垂直拖动。

缩放手势:

  • `onScaleStart`, `onScaleUpdate`, `onScaleEnd`: 用于检测缩放操作,通常用于实现捏合缩放功能。

基本用法


以下是一个简单的示例,展示如何使用 `GestureDetector` 来监听不同的手势:

import 'package:flutter/material.dart';

class GestureDetectorExampleMyTestDemo extends StatelessWidget {
  const GestureDetectorExampleMyTestDemo({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('GestureDetector Example')),
      body: Center(
        child: GestureDetector(
          onTap: () {
            print('Tapped!');
          },
          onDoubleTap: () {
            print('Double Tapped!');
          },
          onLongPress: () {
            print('Long Pressed!');
          },
          onPanUpdate: (details) {
            print('Pan Updated: ${details.delta}');
          },
          child: Container(
            width: 200,
            height: 200,
            color: Colors.blue,
            alignment: Alignment.center,
            child: const Text(
              'Tap Me',
              style: TextStyle(color: Colors.white, fontSize: 24),
            ),
          ),
        ),
      ),
    );
  }
}

 详细属性解析

  • `onTap`: 单次点击时的回调。
  • `onDoubleTap`: 双击时的回调。
  • `onLongPress`: 长按时的回调。
  • `onPanStart`, `onPanUpdate`, `onPanEnd`: 分别用于开始、更新和结束拖动时的回调。
  • `onHorizontalDragStart`, `onHorizontalDragUpdate`, `onHorizontalDragEnd`: 处理水平拖动。
  • `onVerticalDragStart`, `onVerticalDragUpdate`, `onVerticalDragEnd`: 处理垂直拖动。
  • `onScaleStart`, `onScaleUpdate`, `onScaleEnd`: 处理缩放手势。

注意事项

1. Hit Testing(命中测试)
  • `GestureDetector` 需要一个非空的子组件才能检测手势。
  • 如果 `GestureDetector` 的子组件是空的(比如没有子组件,或者子组件是 `Container` 且未设置 `color` 属性),手势检测将无法生效。这是因为 Flutter 默认不会为空组件进行命中测试。
  • 解决方案:可以为 `GestureDetector` 的子组件设置一个明确的背景颜色(即使是透明的),例如 `color: Colors.transparent`。
GestureDetector(
  onTap: () {
    print('Tapped');
  },
  child: Container(
    width: 100,
    height: 100,
    color: Colors.transparent, // 必须设置颜色,否则点击事件可能无法检测
  ),
)

 2. 手势冲突
  • 当多个手势识别器(如拖动和缩放)同时应用于同一个组件时,可能会发生手势冲突。
  • Flutter 提供了 手势竞技场机制(Gesture Arena) 来解决冲突。在默认情况下,多个手势识别器会竞争事件的优先权,只有一个手势识别器会胜出。
  • 如果你需要同时响应多个手势,可以使用 `RawGestureDetector` 或 `GestureRecognizer` 来自定义手势行为。

例如,通过 `onScaleUpdate` 实现拖动和缩放:

GestureDetector(
  onScaleUpdate: (details) {
    print('Scale: ${details.scale}, Translation: ${details.focalPointDelta}');
  },
  child: Container(
    width: 200,
    height: 200,
    color: Colors.blue,
  ),
);

 

3. 嵌套手势
  • 当 `GestureDetector` 嵌套时,内部的手势可能会覆盖外部的手势,或者导致手势冲突。
  • Flutter 提供了 `Behavior` 属性来控制手势的传播方式:
  • `HitTestBehavior.deferToChild`(默认值):只有子组件能够响应手势时,`GestureDetector` 才会检测手势。
  • `HitTestBehavior.opaque`:即使子组件是透明的,父组件也会参与命中测试。
  • `HitTestBehavior.translucent`:父组件会响应手势,但透明区域的子组件仍然可以响应手势。
GestureDetector(
  behavior: HitTestBehavior.translucent,
  onTap: () {
    print('Parent tapped!');
  },
  child: GestureDetector(
    onTap: () {
      print('Child tapped!');
    },
    child: Container(
      width: 100,
      height: 100,
      color: Colors.red,
    ),
  ),
);

Flutter实现输入验证码代码学习

import 'dart:async';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

///验证码输入框
class VerificationCodeInputDemoPage extends StatelessWidget {
  const VerificationCodeInputDemoPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("VerificationCodeInputDemoPage"),
      ),
      body: GestureDetector(
        behavior: HitTestBehavior.translucent,
        onTap: () {
          FocusScope.of(context).requestFocus(FocusNode());
        },
        child: Center(
          child: VerCodeInput(
            ctx: context,
            length: 6,
            keyboardType: TextInputType.number,
            builder: staticRectangle(context),
            onChanged: (value) {
            },

            ///输入完成时
            onFilled: (value) {
              //print('Your input is $value.');
            },
          ),
        ),
      ),
    );
  }

  staticRectangle(BuildContext context) {
    var codeSize = 6;
    double padding = 16;
    double width = MediaQuery.sizeOf(context).width;
    double codeFullSize = ((width - 2 * padding) / codeSize);
    double codeNormalSize = codeFullSize - 20;
    return CodeInputBuilders.rectangle(
        totalSize: Size(codeFullSize, codeFullSize),
        emptySize: Size(codeNormalSize, codeNormalSize),
        filledSize: Size(codeNormalSize, codeNormalSize),
        borderRadius: BorderRadius.zero,
        border: Border.all(color: Theme.of(context).primaryColor, width: 1.0),
        color: Colors.transparent,
        textStyle: TextStyle(
            color: Theme.of(context).primaryColor,
            fontSize: 16.0,
            fontWeight: FontWeight.bold));
  }
}

///from https://github.com/tiny-express/flutter_verification_code_input/blob/master/lib/src/verification_code_input.dart

typedef CodeInputBuilder = Widget Function(bool hasFocus, String char);

class VerCodeInput extends StatefulWidget {
  const VerCodeInput._({
    super.key,
    required this.length,
    required this.keyboardType,
    required this.inputFormatters,
    required this.builder,
    required this.ctx,
    this.onChanged,
    this.onFilled,
  });

  factory VerCodeInput({
    Key? key,
    required int length,
    TextInputType keyboardType = TextInputType.text,
    List<TextInputFormatter>? inputFormatters,
    BuildContext? ctx,
    required CodeInputBuilder builder,
    void Function(String value)? onChanged,
    void Function(String value)? onFilled,
  }) {
    assert(length > 0, 'The length needs to be larger than zero.');
    assert(length.isFinite, 'The length needs to be finite.');

    inputFormatters ??= _createInputFormatters(length, keyboardType);

    return VerCodeInput._(
      key: key,
      length: length,
      keyboardType: keyboardType,
      inputFormatters: inputFormatters,
      builder: builder,
      ctx: ctx,
      onChanged: onChanged,
      onFilled: onFilled,
    );
  }

  /// The length of character entities to always display.
  ///
  /// ## Sample code
  ///
  /// A code input with 4 characters:
  ///
  /// ```dart
  /// CodeInput(length: 4)
  /// ```
  final int length;

  /// The type of thconstard which shows up.
  ///
  /// ## Sample codeconst
  ///
  /// ```dart
  /// CodeInput(keyboardType: TextInputType.number)
  /// ```
  final TextInputType keyboardType;

  /// A list of input formatters which can validate the text as it is being
  /// typed.
  ///
  /// If you specify this parameter, the default input formatters aren't used,
  /// so make sure you really check for everything (like length of the input).
  ///
  /// ## Sample code
  ///
  /// An code input that displays a normal keyboard but only allows for
  /// hexadecimal input:
  ///
  /// ```dart
  /// CodeInput(
  ///   inputFormatters: [
  ///     WhitelistingTextInputFormatter(RegExp('^[0-9a-fA-F]*\$'))
  ///   ]
  /// )
  /// ```
  final List<TextInputFormatter> inputFormatters;

  /// A builder for the character entities.
  ///
  /// See [CodeInputBuilders] for examples.
  final CodeInputBuilder builder;

  /// A callback for changes to the input.
  final void Function(String value)? onChanged;

  /// A callback for when the input is filled.
  final void Function(String value)? onFilled;

  /// context parent because of MediaQuery.of(widget.ctx)
  final BuildContext? ctx;

  /// A helping function that creates input formatters for a given length and
  /// keyboardType.
  static List<TextInputFormatter> _createInputFormatters(
      int length, TextInputType keyboardType) {
    final formatters = <TextInputFormatter>[
      LengthLimitingTextInputFormatter(length)
    ];

    // Add keyboard specific formatters.
    // For example, a code input with a number keyboard type probably doesn't
    // want to allow decimal separators or signs.
    if (keyboardType == TextInputType.number) {
      formatters.add(FilteringTextInputFormatter.digitsOnly);
    }

    return formatters;
  }

  @override
  _VerCodeInputState createState() => _VerCodeInputState();
}

class _VerCodeInputState extends State<VerCodeInput> {
  final node = FocusNode();
  final controller = TextEditingController();

  String get text => controller.text;

  @override
  Widget build(BuildContext context) {
    // We'll display the visual widget and a not shown EditableText for doing
    // the actual work on top of each other.
    return Stack(children: <Widget>[
      // This is the actual EditableText wrapped in a Container with zero
      // dimensions.
      SizedBox(
          width: 0.0,
          height: 0.0,
          child: EditableText(
            controller: controller,
            focusNode: node,
            inputFormatters: widget.inputFormatters,
            keyboardType: widget.keyboardType,
            backgroundCursorColor: Colors.black,
            style: const TextStyle(),
            // Doesn't really matter.
            cursorColor: Colors.black,
            // Doesn't really matter.
            onChanged: (value) => setState(() {
              widget.onChanged?.call(value);
              if (value.length == widget.length) {
                widget.onFilled?.call(value);
              }
            }),
          )),
      // These are the actual character widgets. A transparent container lies
      // right below the gesture detector, so all taps get collected, even
      // the ones between the character entities.
      GestureDetector(
          onTap: () {
            if (MediaQuery.viewInsetsOf(context).bottom == 0) {
              final focusScope = FocusScope.of(context);
              focusScope.requestFocus(FocusNode());
              Future.delayed(
                  Duration.zero, () => focusScope.requestFocus(node));
            }
          },
          child: Container(
            color: Colors.transparent,
            child: Row(
              mainAxisSize: MainAxisSize.min,
              children: List.generate(widget.length, (i) {
                final hasFocus = controller.selection.start == i;
                final char = i < text.length ? text[i] : '';
                final characterEntity = widget.builder(hasFocus, char);


                return characterEntity;
              }),
            ),
          )),
    ]);
  }
}

/// An abstract class that provides some commonly-used builders for the
/// character entities.
///
/// * [containerized]: A builder putting chars in an animated container.
/// * [circle]: A builder putting chars in circles.
/// * [rectangle]: A builder putting chars in rectangles.
/// * [lightCircle]: A builder putting chars in light circles.
/// * [darkCircle]: A builder putting chars in dark circles.
/// * [lightRectangle]: A builder putting chars in light rectangles.
/// * [darkRectangle]: A builder putting chars in dark rectangles.
abstract class CodeInputBuilders {
  /// Builds the input inside an animated container.
  static CodeInputBuilder containerized({
    Duration animationDuration = const Duration(milliseconds: 50),
    required Size totalSize,
    required Size emptySize,
    required Size filledSize,
    required BoxDecoration emptyDecoration,
    required BoxDecoration filledDecoration,
    required TextStyle emptyTextStyle,
    required TextStyle filledTextStyle,
  }) {
    return (bool hasFocus, String char) => Container(
        width: totalSize.width,
        height: totalSize.height,
        alignment: Alignment.center,
        child: AnimatedContainer(
          duration: const Duration(milliseconds: 100),
          decoration: char.isEmpty ? emptyDecoration : filledDecoration,
          width: char.isEmpty ? emptySize.width : filledSize.width,
          height: char.isEmpty ? emptySize.height : filledSize.height,
          alignment: Alignment.center,
          child: Text(char,
              style: char.isEmpty ? emptyTextStyle : filledTextStyle),
        ));
  }

  /// Builds the input inside a circle.
  static CodeInputBuilder circle(
      {double totalRadius = 30.0,
      double emptyRadius = 10.0,
      double filledRadius = 25.0,
      required Border border,
      required Color color,
      required TextStyle textStyle}) {
    final decoration = BoxDecoration(
      shape: BoxShape.circle,
      border: border,
      color: color,
    );

    return containerized(
        totalSize: Size.fromRadius(totalRadius),
        emptySize: Size.fromRadius(emptyRadius),
        filledSize: Size.fromRadius(filledRadius),
        emptyDecoration: decoration,
        filledDecoration: decoration,
        emptyTextStyle: textStyle.copyWith(fontSize: 0.0),
        filledTextStyle: textStyle);
  }

  /// Builds the input inside a rectangle.
  static CodeInputBuilder rectangle({
    Size totalSize = const Size(50.0, 60.0),
    Size emptySize = const Size(20.0, 20.0),
    Size filledSize = const Size(40.0, 60.0),
    BorderRadius borderRadius = BorderRadius.zero,
    required Border border,
    required Color color,
    required TextStyle textStyle,
  }) {
    final decoration = BoxDecoration(
      border: border,
      borderRadius: borderRadius,
      color: color,
    );

    return containerized(
        totalSize: totalSize,
        emptySize: emptySize,
        filledSize: filledSize,
        emptyDecoration: decoration,
        filledDecoration: decoration,
        emptyTextStyle: textStyle.copyWith(fontSize: 0.0),
        filledTextStyle: textStyle);
  }

  /// Builds the input inside a light circle.
  static CodeInputBuilder lightCircle({
    double totalRadius = 30.0,
    double emptyRadius = 10.0,
    double filledRadius = 25.0,
  }) {
    return circle(
        totalRadius: totalRadius,
        emptyRadius: emptyRadius,
        filledRadius: filledRadius,
        border: Border.all(color: Colors.white, width: 2.0),
        color: Colors.white10,
        textStyle: const TextStyle(
            color: Colors.white, fontSize: 20.0, fontWeight: FontWeight.bold));
  }

  /// Builds the input inside a light circle.
  static CodeInputBuilder darkCircle({
    double totalRadius = 30.0,
    double emptyRadius = 10.0,
    double filledRadius = 25.0,
  }) {
    return circle(
        totalRadius: totalRadius,
        emptyRadius: emptyRadius,
        filledRadius: filledRadius,
        border: Border.all(color: Colors.black, width: 2.0),
        color: Colors.black12,
        textStyle: const TextStyle(
            color: Colors.black, fontSize: 20.0, fontWeight: FontWeight.bold));
  }

  /// Builds the input inside a light rectangle.
  static CodeInputBuilder lightRectangle({
    Size totalSize = const Size(50.0, 60.0),
    Size emptySize = const Size(20.0, 20.0),
    Size filledSize = const Size(40.0, 60.0),
    BorderRadius borderRadius = BorderRadius.zero,
  }) {
    return rectangle(
        totalSize: totalSize,
        emptySize: emptySize,
        filledSize: filledSize,
        borderRadius: borderRadius,
        border: Border.all(color: Colors.white, width: 2.0),
        color: Colors.white10,
        textStyle: const TextStyle(
            color: Colors.white, fontSize: 20.0, fontWeight: FontWeight.bold));
  }

  static CodeInputBuilder staticRectangle({
    Size totalSize = const Size(60.0, 60.0),
    Size emptySize = const Size(40.0, 40.0),
    Size filledSize = const Size(40.0, 40.0),
    BorderRadius borderRadius = BorderRadius.zero,
  }) {
    return rectangle(
        totalSize: totalSize,
        emptySize: emptySize,
        filledSize: filledSize,
        borderRadius: borderRadius,
        border: Border.all(color: Colors.white, width: 1.0),
        color: Colors.transparent,
        textStyle: const TextStyle(
            color: Colors.white, fontSize: 20.0, fontWeight: FontWeight.bold));
  }

  /// Builds the input inside a dark rectangle.
  static CodeInputBuilder darkRectangle({
    Size totalSize = const Size(50.0, 60.0),
    Size emptySize = const Size(20.0, 20.0),
    Size filledSize = const Size(40.0, 60.0),
    BorderRadius borderRadius = BorderRadius.zero,
  }) {
    return rectangle(
        totalSize: totalSize,
        emptySize: emptySize,
        filledSize: filledSize,
        borderRadius: borderRadius,
        border: Border.all(color: Colors.black, width: 2.0),
        color: Colors.black12,
        textStyle: const TextStyle(
            color: Colors.black, fontSize: 20.0, fontWeight: FontWeight.bold));
  }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/950897.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Eclipse配置Tomcat服务器(最全图文详解)

前言&#xff1a; 本章使用图文讲解如何在Eclipse开发工具中配置Tomcat服务器、如何创建和启动JavaWeb工程&#xff0c;欢迎童鞋们互相交流。觉得不错可以三连订阅喔。 目标&#xff1a; 一、配置Tomcat服务器 1. 切换Eclipse视图 2. 打开菜单 3. 找到服务选项 4. 选择…

汽车供应链关键节点:物流采购成本管理全解析

在汽车行业&#xff0c;供应链管理是一项至关重要的任务。汽车制造从零部件的生产到整车的交付&#xff0c;涉及多个环节&#xff0c;其中物流、采购与成本管理是核心节点。本文将深入分析这些关键环节&#xff0c;探讨如何通过供应商管理系统及相关工具优化供应链管理。 一、…

软件工程期末整理(二)

快速原型开发模型是&#xff08;适用于客户需求难以清楚定义、规模较小的系统&#xff09;。(编写系统实施计划)不是系统设计阶段的主要活动 解释&#xff1a;系统实施计划”更侧重于后续的实施与部署阶段&#xff0c;属于项目管理层面的内容 协作性不属于构件的特性在类图中…

STM32-笔记35-DMA(直接存储器访问)

一、什么叫DMA&#xff1f; DMA&#xff08;Direct Memory Access&#xff0c;直接存储器访问&#xff09;提供在外设与内存、存储器和存储器之间的高速数据传输使用。它允许不同速度的硬件装置来沟通&#xff0c;而不需要依赖于CPU&#xff0c;在这个时间中&#xff0c;CPU对于…

代码管理助手-Git

前言 Git 是一个版本控制系统&#xff0c;可以帮助你记录文件的每一次修改。这样&#xff0c;如果你在编程时不小心把代码写错了&#xff0c;可以很容易地回退到之前的版本。最重要的是&#xff0c;Git 是完全免费的&#xff0c;用户可以在自己的计算机上安装和使用 Git&#x…

蓝耘:GPU算力云服务的技术探索与AIGC应用支持

&#x1f3ac; 江城开朗的豌豆&#xff1a;个人主页 &#x1f525; 个人专栏 :《 VUE 》 《 javaScript 》 &#x1f4dd; 个人网站 :《 江城开朗的豌豆&#x1fadb; 》 ⛺️ 生活的理想&#xff0c;就是为了理想的生活 ! 目录 一、蓝耘的核心优势 1. 行业领先的基础设施 …

Kubernetes Gateway API-4-TCPRoute和GRPCRoute

1 TCPRoute 目前 TCP routing 还处于实验阶段。 Gateway API 被设计为与多个协议一起工作&#xff0c;TCPRoute 就是这样一个允许管理TCP流量的路由。 在这个例子中&#xff0c;我们有一个 Gateway 资源和两个 TCPRoute 资源&#xff0c;它们按照以下规则分配流量&#xff1…

在不到 5 分钟的时间内将威胁情报 PDF 添加为 AI 助手的自定义知识

作者&#xff1a;来自 Elastic jamesspi 安全运营团队通常会维护威胁情报报告的存储库&#xff0c;这些报告包含由报告提供商生成的大量知识。然而&#xff0c;挑战在于&#xff0c;这些报告的内容通常以 PDF 格式存在&#xff0c;使得在处理安全事件或调查时难以检索和引用相关…

Unity学习之UGUI进阶

一、事件监听接口 1、作用 用于实现类型长按、双击、拖拽等基础控件无法实现的功能 所有控件都能够添加更多的事件监听来处理对应的逻辑 2、事件监听接口类型 &#xff08;1&#xff09;常用事件接口 &#xff08;2&#xff09;不常用事件接口 3、使用事件监听接口 &#…

Redis为 List/Set/Hash 的元素设置单独的过期时间

一.业务简介 我们知道&#xff0c;Redis 里面暂时没有接口给 List、Set 或者 Hash 的 field 单独设置过期时间&#xff0c;只能给整个列表、集合或者 Hash 设置过期时间。 这样&#xff0c;当 List/Set/Hash 过期时&#xff0c;里面的所有 field 元素就全部过期了。但这样并不…

【Notepad++】Notepad++如何删除包含某个字符串所在的行

Notepad如何删除包含某个字符串所在的行 一&#xff0c;简介二&#xff0c;操作方法三&#xff0c;总结 一&#xff0c;简介 在使用beyoundcompare软件进行对比的时候&#xff0c;常常会出现一些无关紧要的地方&#xff0c;且所在行的内容是变化的&#xff0c;不方便进行比较&…

APP上架之Android 证书 MD5 指纹

Android 证书 MD5 指纹 1. 什么是 Android 证书 MD5 指纹&#xff1f; Android 证书 MD5 指纹是对证书数据进行 MD5 哈希运算后得到的 128 位字符串。在 Android 开发中&#xff0c;每个证书在理论上都有一个唯一的 MD5 指纹&#xff0c;用于识别和验证证书的有效性。证书指纹…

软件安全性测试有哪些测试方法?

随着数字化进程的加速&#xff0c;软件在各个领域扮演着越来越重要的角色。软件的安全性测试作为保证软件质量和安全的重要环节&#xff0c;逐渐成为企业在开发和部署过程中不可或缺的一部分。 一、软件安全性测试的测试方法   1、静态分析法&#xff1a;通过分析源代码或二…

LabVIEW轴承性能测试系统

本文介绍了基于LabVIEW的高效轴承性能测试系统的设计与开发。系统通过双端驱动技术实现高精度同步控制&#xff0c;针对轴承性能进行全面的测试与分析&#xff0c;以提高轴承的可靠性和寿命。 项目背景 随着工业自动化程度的提高&#xff0c;对轴承的性能要求越来越高。传统的…

57. Three.js案例-创建一个带有聚光灯和旋转立方体的3D场景

57. Three.js案例-创建一个带有聚光灯和旋转立方体的3D场景 实现效果 该案例实现了使用Three.js创建一个带有聚光灯和旋转立方体的3D场景。 知识点 WebGLRenderer&#xff08;WebGL渲染器&#xff09; THREE.WebGLRenderer 是 Three.js 中用于将场景渲染为 WebGL 内容的核…

如何使用vue引入three.js

在 Vue.js 项目中引入和使用 Three.js 是一个常见的需求&#xff0c;Three.js 是一个用于在浏览器中创建和显示动画 3D 计算机图形的 JavaScript 库。以下是一个基本的示例&#xff0c;展示如何在 Vue 项目中引入和使用 Three.js。 1. 创建 Vue 项目 如果你还没有一个 Vue 项…

9.4 visualStudio 2022 配置 cuda 和 torch (c++)

一、配置torch 1.Libtorch下载 该内容看了【Libtorch 一】libtorchwin10环境配置_vsixtorch-CSDN博客的博客&#xff0c;作为笔记用。我自己搭建后可以正常运行。 下载地址为windows系统下各种LibTorch下载地址_libtorch 百度云-CSDN博客 下载解压后的目录为&#xff1a; 2.vs…

【JavaEE进阶】获取Cookie/Session

&#x1f340;Cookie简介 HTTP协议自身是属于 "⽆状态"协议. "⽆状态"的含义指的是: 默认情况下 HTTP 协议的客⼾端和服务器之间的这次通信,和下次通信之间没有直接的联系.但是实际开发中,我们很多时候是需要知道请求之间的关联关系的. 例如登陆⽹站成…

oscp备考 oscp系列——Kioptix Level 1靶场 古老的 Apache Vuln

目录 前言 1. 主机发现 2. 端口扫描 3. 指纹识别 4. 目录扫描 5. 漏洞搜索和利用 前言 oscp备考&#xff0c;oscp系列——Kioptix Level 1靶场 Kioptix Level 1难度为简单靶场&#xff0c;主要考察 nmap的使用已经是否会看输出&#xff0c;以及是否会通过应用查找对应漏…

CSS——2.书写格式一

<!DOCTYPE html> <html><head><meta charset"UTF-8"><title></title></head><body><!--css书写中&#xff1a;--><!--1.css 由属性名:属性值构成--><!--style"color: red;font-size: 20px;&quo…