Flutter UI组件插件pin_ui的使用

Flutter UI组件插件pin_ui的使用

pin_ui 包用于快速构建包含高级PIN码功能的屏幕。它提供了两个核心组件:

  1. Pinpad:高度可定制的数字键盘,用于输入PIN码。
  2. Pin Indicator:可视化进入的PIN码状态(通过遮蔽或非遮蔽字段),并提供了多种预定义的动画供选择。

如果您还对快速实现PIN码功能的后端部分感兴趣,可以查看 pin 包。

![pin_ui pub](https://img.shields.io/pub/v/pin_ui.svg?style=flat&colorB=blue&label=pin_ui pub) pin_ui GitHub

Pinpad

Pinpad 是一个带有两个额外键槽的数字键盘。通常在这些键槽中放置“忘记PIN”和“生物识别”按钮。

Pinpad

使用

  • 0-9 键可以使用 BoxDecoration 类进行装饰以改变其外观:背景颜色、边框半径、边框、阴影等。有三种状态:默认、按下和禁用。每个状态都可以单独自定义,以便使其看起来不同。通过提供 keyDefaultDecorationkeyPressedDecorationkeyDisabledDecoration 来设置您喜欢的方式。
  • 0-9 键具有 TextStyle 属性。同样也有三种状态:默认、按下和禁用。设置 keyDefaultTextStylekeyPressedTextStylekeyDisabledTextStyle 以样式化键内的数字。
  • 使用 keyHeightkeyWidth 调整键的大小。
  • 使用 horizontalSpacingverticalSpacing 属性更改键之间的间距。默认情况下,这些值将根据屏幕大小计算得出。
  • 可以通过设置 enabledisVisible 来禁用或使PIN码不可见。使其不可见不会改变键盘的实际大小。
  • 使用 vibrationEnabled 属性启用振动。当按键被按下时,会提供轻微的振动反馈。
  • 若要在 0 键的左右添加额外的键,请提供 leftExtraKeyrightExtraKey。这些参数具有 PinpadExtraKey 类型。这是一个包装器,其中包含您的子部件,并添加了 onTap 回调。子部件可以是任何部件,但也可以使用此包提供的 PinpadKeyPinpadTextKey,以便使所有按钮看起来相同。
Pinpad(
  onKeyTap: myKeyTapHandler,
  keyDefaultDecoration: myDecoration,
  keyPressedDecoration: myDecoratino.copyWith(color: blue),
  keyDisabledDecoration: myDecoration,
  keyDefaultTextStyle: myTextStyle,
  keyPressedTextStyle: myTextStyle.copyWith(fontWeight: FontWeight.w700),
  keyDisabledTextStyle: myTextStyle.copyWith(color: grey),
  leftExtraKey: PinpadExtraKey(
    onTap: handleForgotPinTap,
    child: myForgotPinButton,
  ),
  rightExtraKey: PinpadExtraKey(
    onTap: handleEraseTap,
    child: myEraseButton,
  ),
  horizontalSpacing: x,
  verticalSpacing: y,
  keyWidth: m,
  keyHeight: n,
  enabled: myEnableCondition,
  isVisible: myVisibleCondition,
  vibrationEnabled: true,
)

Pin Indicator

Pin Indicator 是一个提供可视表示形式的组件,用于显示PIN码的状态:已经输入了多少位数字、是否有错误、是否成功等。

最简单的 Pin Indicator 变体是一行彩色点或遮蔽星号。

使用

PinIndicator 组件有两个构造函数:默认构造函数和 PinIndicator.builder。它们的参数集大多相同,主要的区别在于使用 .builder 版本时,您可以提供任何部件作为项目。因此,它更具可定制性。如果您不需要这种级别的定制,只需使用默认构造函数即可。它提供了简单的项目,可以用 Flutter 的 BoxDecoration 进行装饰。

  • PinIndicator 中的项目有四种状态:Default 表示未输入的PIN码数字,Input 表示已输入的PIN码数字,Error 表示发生了一些错误(输入错误的PIN码),Success 表示用户输入了正确的PIN码。因此,有四个不同的参数来定制您的 Pin Indicator。 对于 .builder 构造函数,有四个必需的参数:defaultItemBuilderinputItemBuildererrorItemBuildersuccessItemBuilder。 对于默认构造函数,有四个可选参数:defaultDecorationinputDecorationerrorDecorationsuccessDecoration。这些参数不是必需的!如果未提供,将使用预定义的装饰。
  • controller – 您的 PinIndicatorAnimationController 实例类的实例,用于管理动画(如果需要)。
  • length 是PIN码的总数字。它可以是任意起始数字,但通常为4、5或6。
  • currentLength 表示用户已输入的数字数量。
  • isError – 错误状态使能器。
  • isSuccess – 成功状态使能器。
  • spacing – 项目之间的距离。
  • size – 项目的大小。它调整 PinIndicator 中的项目大小。对于 .builder 构造函数没有这样的参数,但请注意,所有项目最好保持相同的固定大小。即使它们必须看起来不同,也要通过包装 SizedBox 或添加不可见的边距来使它们占据相同的空间。这将使指示器静态并且不会破坏依赖于子项大小的动画计算。
  • loadingCollapseAnimationChild – 在加载折叠动画中使用的部件。
  • successCollapseAnimationChild – 在成功折叠动画中使用的部件。
PinIndicator(
  errorDecoration = myErrorDecoration,
  successDecoration = mySuccessDecoration,
  inputDecoration = myInputDecoration,
  defaultDecoration = myDefaultDecoration,
  length = 4,
  currentLength = pin.length,
  isError = isPinError,
  isSuccess = isPinSuccess,
  controller = myController,
  spacing = 24,
  size = 14,
  loadingCollapseAnimationChild = myLoadingCollapsedWidget,
  successCollapseAnimationChild = mySuccessCollapsedWidget,
)

PinIndicator.builder(
  errorItemBuilder: (i) => myErrorItemBuilder(i),
  successItemBuilder: (i) => mySuccessItemBuilder(i),
  inputItemBuilder: (i) => myInputItemBuilder(i),
  defaultItemBuilder: (i) => myDefaultItemBuilder(i),
  length = 4,
  currentLength = pin.length,
  isError = isPinError,
  isSuccess = isPinSuccess,
  controller = myController,
  spacing = 24,
  loadingCollapseAnimationChild = myLoadingCollapsedWidget,
  successCollapseAnimationChild = mySuccessCollapsedWidget,
)

注意事项

  • PinIndicator.builder 构造函数的构建器必须返回 PreferredSizeWidget 类型而不是普通的 Widget 类型。为此,只需向 StatefulWidgetStatelessWidget 添加 implements PreferredSizeWidget 并提供 preferredSize 覆盖的 getter。这是因为在某些动画中,它们使用 Pin Indicator 项目的大小进行计算。
typedef PinIndicatorItemBuilder = PreferredSizeWidget Function(int index);

动画

动画是 pin_ui 包的核心功能之一。它包含了许多预定义的动画,适用于用户与应用程序交互的不同场景。

为什么使用动画?

首先,它看起来更美观。其次,它们可以在后台执行异步操作或初始化过程时吸引用户的注意力。通常使用无聊的加载指示器或闪烁效果。但是,一组好的动画序列可以更好地完成这项任务!

Pin Indicator 可以按以下方式动画化:

  • 输入:当用户输入PIN码的一个数字时,为其动画化。
  • 加载:当您需要隐藏长时间的异步操作或将动画流变得更加平滑和明显给用户时,为其动画化。
  • 成功:当用户输入正确的PIN码时为其动画化,以隐藏加载动画后的长时间异步操作。并展示用户输入正确PIN码且无需进一步操作。
  • 错误:当用户输入错误的PIN码时为其动画化,以显示他们输入的PIN码不正确。
  • 清除:当用户一次性清除整个PIN码(如果有此类功能)或因其他逻辑触发清除整个PIN码时为其动画化。
  • 擦除:当用户擦除PIN码中的一个数字时为其动画化。
  • 空闲:当用户一段时间内不活跃时为其动画化,以激励用户采取行动,并展示应用程序仍然活跃并等待用户操作。

每种类型的动画都有许多现成的动画供选择。下表列出了所有动画及其相关信息和建议。

类型 名称 演示 备注和建议 震动
输入 Inflate 演示 默认输入动画 +
输入 Fall 演示 推荐与删除取消动画配对使用 -
输入 Fade 演示 推荐与删除淡出动画配对使用 -
加载 Jump 演示 默认加载动画 +
加载 Wave Inflate 演示 -
加载 Wave Deflate 演示 -
加载 Collapse 演示 可以通过 PinIndicatorloadingCollapseAnimationChild 参数提供自己的动画指示器 -
加载 Travel 演示 -
成功 Collapse 演示 默认成功动画 -
成功 Fill 演示 -
成功 Fill last 演示 成功填充 动画,但此动画非常适合与 加载跳跃 动画结合使用 -
成功 Kick 演示 +
错误 Shake 演示 默认错误动画 +
错误 Jiggle 演示 摇晃效果仅对非圆形的 Pin Indicator 项目可见 +
错误 Brownian 演示 项目随机移动然后返回起点 -
错误 Blink 演示 -
清除 Drop 演示 -
清除 Fade 演示 默认清除动画 -
擦除 Deflate 演示 默认擦除动画 +
擦除 Take off 演示 推荐与输入下落动画配对使用 -
擦除 Fade 演示 推荐与输入淡出动画配对使用 -
空闲 Wave 演示 默认空闲动画 -
空闲 Pulse 演示 -
空闲 Flash 演示 项目随机膨胀和收缩 -

单独来看,一些动画可能看起来有些粗糙,但通过组合它们并在动画前后添加延迟,可以创建出良好的动画序列!

您可以在 示例项目 中尝试使用它,并将其用作测试想法的游乐场。它还可以作为一个很好的起点,您可以从中复制一些代码到您的应用中。

控制器

动画由 PinIndicatorAnimationController 提供的这个包管理。通过传递 controller 参数将控制器与 PinIndicator 关联起来。之后,您可以调用动画方法,指示器将以您指定的方式进行动画。

final controller = PinIndicatorAnimationController();

PinIndicator(
  controller: controller,
  ...
)

控制器 负责管理动画。它是通过队列实现的,所以所有动画调用都是同步操作。在队列中,动画可以依次进行,或者中断不太重要的动画。更多关于这一点的信息在 动画优先级部分

要开始播放所需的动画,只需从控制器调用适当的方法。

controller.animateLoading();

简单的调用不包含任何参数。在这种情况下,默认动画将播放而没有任何其他修改。 但是,您可以通过传递必要的参数来稍微修改动画调用。可用参数列表因方法而异。以下是描述:

  • animation – 您想要播放的动画类型(参见上表)。
  • delayBeforedelayAfter – 在此动画之前和之后设置的延迟。它们对于制作动画序列或在某些情况下使动画持续时间更长非常有用。
  • onCompleteonInterrupt – 有用的回调,用于任何情况:一个动画完成后启动另一个动画,响应用户输入中断动画,导航或触发其他所需逻辑。
  • animationSpeed – 动画速度倍数。在某些情况下很有用,因为所有动画都预先配置了持续时间。
  • vibration – 启用动画的振动(并非所有动画都会振动)。更多信息在 震动部分
  • repeatCount – 一种避免多次调用动画的方法。

您可能希望在动画开始或结束时更新UI。这可以通过监听控制器来实现,它将返回一个带有 PinIndicatorAnimation 类型的服务信息的对象,如果当前没有动画正在播放,则返回 null。您可以避免使用这种方法,如果您需要检查当前正在播放什么动画,可以访问控制器中的getter。

监听控制器在某些情况下可能是有用的。例如,如果您想在重要动画(如加载或成功动画)正在进行时禁用 Pinpad 或使其不可见,以向用户展示后台正在发生一些事情且不再需要操作。或者,如果您想根据当前动画更新 Scaffold 的背景颜色。

在此代码片段中,它监听控制器并根据需要禁用或隐藏 Pinpad:

return ValueListenableBuilder(
  valueListenable: controller,
  builder: (context, value, child) {
    return Column(
      children: [
        PinIndicator(
          contoller: controller,
          ...
        ),
        Pinpad(
          // 当重要动画正在播放时禁用键盘
          enabled: !controller.isAnimatingNonInterruptible,
          // 当成功动画正在播放时隐藏键盘
          isVisible: !controller.isAnimatingSuccess,
          ...
        ),
      ],
    );  
  },
);

所有动画都适用于任何允许数量的项目(> 3)。但如果项目过多,动画看起来会很快,因为它们具有固定的播放时间。因此,可以通过 animationSpeed 参数调整任何动画的速度,使其更快或更慢:

controller.animateSuccess(
  animation: PinSuccessAnimation.fillLast,
  animationSpeed: 2, // 动画将以2倍速度播放
  // animationSpeed: 0.33, // 这将使动画速度降低3倍

  // 两个延迟不会受到 animationSpeed 值的影响
  delayBefore: Duration(milliseconds: 240),
  delayAfter: Duration(seconds: 1),
);

当开始一个新的动画时,您可能希望替换 Pin Indicator 中的不同部件或至少更改它们的颜色,以便动画看起来更自然且易于理解。要做到这一点,您不需要添加任何额外的条件或更新构建器代码。Pin Indicator 将通过读取 isErrorisSuccess 值来处理这两个状态。对于处理默认和输入状态,它将取决于 lengthcurrentLength 来决定应用哪个构建器或装饰。

通过 onCompleteonInterrupt 回调轻松管理错误和成功状态。onComplete 触发动画结束后(如果设置了延迟),onInterrupt 触发动画停止(由用户使用 stop() 或由其他更重要的动画触发)。这些回调可以在调用动画时设置:

// 您的 Pin Indicator 小部件
PinIndicator(
  controller: controller,
  length: 4,
  currentLength: pin.length,
  isError: isPinError,
  isSuccess: isPinSuccess,
)

________________________________________________________________________________


// 如果用户输入了正确的PIN码
controller.animateLoading(
  onComplete: () => setState(() => isPinSuccess = true),
);
controller.animateSuccess(
  onComplete: () { /* 执行导航或其他必要逻辑 */ },
);

________________________________________________________________________________


// 如果用户输入了错误的PIN码     
setState(() => isPinError = true); // 设置错误状态
controller.animateError(
  onInterrupt: clear,
);
controller.animateClear(
  onComplete: clear,
  onInterrupt: clear,
);

void clear() => setState(() {
  pin = ''; // 清除当前输入的PIN变量
  isPinError = false; // 返回默认状态以进行新的尝试
});

注意事项

与其他控制器一样,此控制器也应在可能的情况下被处置!

动画优先级

动画队列设计得当,可以让动画中断其他动画(如果可能的话)。每个动画的中断性预先配置。中断的角色在这里列出所有动画类型及其属性:

类型 可中断 可中断
输入
加载
成功
错误
清除
擦除
空闲

因此,在设计逻辑和动画序列时,请记住这一点。

通常动画顺序如下:

  • 首先是 输入擦除
  • 如果PIN正确,会有一次或几次 加载 和一次 成功
  • 如果PIN错误,会有一次 错误 和一次 清除
  • 空闲 可以随时开始

遵循这些规则,您就不会遇到任何问题。

震动

某些动画具有振动功能!您可以在 表格 中检查它是否可用。

要启用振动功能,您必须在Android清单文件中添加以下内容:

<uses-permission android:name="android.permission.VIBRATE"/>

然后使用 initializeVibration() 异步方法初始化控制器。否则,当带有振动的动画被调用时,它将抛出异常!

准备完毕后,您可以调用动画并启用振动功能:

controller.animateLoading(
  animation: PinLoadingAnimation.jump,
  vibration: true,
);

更多关于Flutter UI组件插件pin_ui的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter UI组件插件pin_ui的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


pin_ui 是一个用于创建 PIN 输入界面的 Flutter 插件。它允许开发者轻松地在应用中添加一个美观且功能齐全的 PIN 输入组件,通常用于身份验证、支付确认等场景。

安装 pin_ui

首先,你需要在 pubspec.yaml 文件中添加 pin_ui 依赖:

dependencies:
  flutter:
    sdk: flutter
  pin_ui: ^1.0.0  # 使用最新版本

然后运行 flutter pub get 来安装依赖。

基本用法

pin_ui 提供了 PinInputTextField 组件,你可以直接在你的 Flutter 应用中使用它来创建一个 PIN 输入框。

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

class PinInputScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('PIN Input Example'),
      ),
      body: Center(
        child: PinInputTextField(
          pinLength: 4, // 设置PIN码的长度
          decoration: BoxLooseDecoration(
            strokeColor: Colors.blue, // 边框颜色
            strokeWidth: 2.0, // 边框宽度
            gapSpace: 8.0, // 每个输入框之间的间距
            bgColor: Colors.grey[200], // 背景颜色
            hintText: '●', // 未输入时的提示字符
          ),
          onChanged: (pin) {
            print('当前输入的PIN码: $pin');
          },
          onSubmit: (pin) {
            print('提交的PIN码: $pin');
          },
        ),
      ),
    );
  }
}

void main() => runApp(MaterialApp(
  home: PinInputScreen(),
));

主要参数说明

  • pinLength: PIN 码的长度,通常为 4 或 6。
  • decoration: 用于自定义 PIN 输入框的外观。BoxLooseDecoration 是一种常见的装饰方式,你可以自定义边框颜色、宽度、背景颜色等。
  • onChanged: 每当 PIN 码发生变化时触发的回调。
  • onSubmit: 当用户完成 PIN 输入并按下确认按钮时触发的回调。

自定义 PIN 输入框

pin_ui 提供了多种装饰选项,你可以根据需要自定义 PIN 输入框的外观。例如:

  • BoxLooseDecoration: 宽松的装饰风格,每个输入框之间有间距。
  • BoxTightDecoration: 紧密的装饰风格,输入框之间没有间距。
  • UnderlineDecoration: 下划线风格的装饰。
PinInputTextField(
  pinLength: 4,
  decoration: UnderlineDecoration(
    color: Colors.blue, // 下划线颜色
    gapSpace: 8.0, // 每个输入框之间的间距
  ),
  onChanged: (pin) {
    print('当前输入的PIN码: $pin');
  },
  onSubmit: (pin) {
    print('提交的PIN码: $pin');
  },
);
回到顶部