Giter VIP home page Giter VIP logo

adar2378 / pin_code_fields Goto Github PK

View Code? Open in Web Editor NEW
664.0 10.0 309.0 57.17 MB

A flutter package which will help you to generate pin code fields with beautiful design and animations. Can be useful for OTP or pin code inputs πŸ€“πŸ€“

Home Page: https://pub.dev/packages/pin_code_fields

License: MIT License

Objective-C 0.04% Dart 65.35% Kotlin 0.14% Swift 0.46% HTML 4.49% CMake 9.41% C++ 19.25% C 0.84%
flutter dart android ios animation shapes otp pin

pin_code_fields's Introduction

A flutter package which will help you to generate pin code fields with beautiful design and animations. Can be useful for OTP or pin code inputs πŸ€“πŸ€“

Features πŸ’š

  • Automatically focuses the next field on typing and focuses previous field on deletation
  • Cursor support ⚑️
  • Can be set to any length. (3-6 fields recommended)
  • 3 different shapes for text fields
  • Highly customizable
  • 3 different types of animation for input texts
  • Animated active, inactive, selected and disabled field color switching
  • Autofocus option
  • Otp-code pasting from clipboard
  • iOS autofill support
  • Error animation. Currently have shake animation only. Watch the example app for how to integrate.
  • Works with Flutter's Form. You can use Form validator right off the bat.
  • Get currently typed text and use your condition to validate it. (for example: if (currentText.length != 6 || currentText != "your desired code"))
  • Haptic Feedback support
  • Animated obscure widget support
  • Single placeholder text

Getting Started ⚑️

Demo

Different Shapes

Notes

  • To enable "Fill color" for each cells, enableActiveFill must be set to true. The default value is false.
  • To change the keyboard type, for example to use only number keyboard, or only for email use keyboardType parameter, default is [TextInputType.visiblePassword]
  • FocosNode and TextEditingController will get disposed automatically. Use autoDisposeControllers = false to disable it.
  • to use v5.0.0 or above, developers must have Flutter SDK 1.20.0 or above.
  • to use v6.0.0 or above, developers must have Flutter SDK 1.22.0 or above.

Properties πŸ”–

  /// The [BuildContext] of the application
  final BuildContext appContext;

  ///Box Shadow for Pincode
  final List<BoxShadow>? boxShadows;

  /// length of how many cells there should be. 3-8 is recommended by me
  final int length;

  /// you already know what it does i guess :P default is false
  final bool obscureText;

  /// Character used for obscuring text if obscureText is true.
  ///
  /// Must not be empty. Single character is recommended.
  ///
  /// Default is ● - 'Black Circle' (U+25CF)
  final String obscuringCharacter;

  /// Widget used to obscure text
  ///
  /// it overrides the obscuringCharacter
  final Widget? obscuringWidget;

  /// Whether to use haptic feedback or not
  ///
  ///
  final bool useHapticFeedback;

  /// Haptic Feedback Types
  ///
  /// heavy, medium, light links to respective impacts
  /// selection - selectionClick, vibrate - vibrate
  /// check [HapticFeedback] for more
  final HapticFeedbackTypes hapticFeedbackTypes;

  /// Decides whether typed character should be
  /// briefly shown before being obscured
  final bool blinkWhenObscuring;

  /// Blink Duration if blinkWhenObscuring is set to true
  final Duration blinkDuration;

  /// returns the current typed text in the fields
  final ValueChanged<String> onChanged;

  /// returns the typed text when all pins are set
  final ValueChanged<String>? onCompleted;

  /// returns the typed text when user presses done/next action on the keyboard
  final ValueChanged<String>? onSubmitted;

  /// the style of the text, default is [ fontSize: 20, fontWeight: FontWeight.bold]
  final TextStyle? textStyle;

  /// the style of the pasted text, default is [fontWeight: FontWeight.bold] while
  /// [TextStyle.color] is [ThemeData.colorScheme.onSecondary]
  final TextStyle? pastedTextStyle;

  /// background color for the whole row of pin code fields.
  final Color? backgroundColor;

  /// This defines how the elements in the pin code field align. Default to [MainAxisAlignment.spaceBetween]
  final MainAxisAlignment mainAxisAlignment;

  /// [AnimationType] for the text to appear in the pin code field. Default is [AnimationType.slide]
  final AnimationType animationType;

  /// Duration for the animation. Default is [Duration(milliseconds: 150)]
  final Duration animationDuration;

  /// [Curve] for the animation. Default is [Curves.easeInOut]
  final Curve animationCurve;

  /// [TextInputType] for the pin code fields. default is [TextInputType.visiblePassword]
  final TextInputType keyboardType;

  /// If the pin code field should be autofocused or not. Default is [false]
  final bool autoFocus;

  /// Should pass a [FocusNode] to manage it from the parent
  final FocusNode? focusNode;

  /// A list of [TextInputFormatter] that goes to the TextField
  final List<TextInputFormatter> inputFormatters;

  /// Enable or disable the Field. Default is [true]
  final bool enabled;

  /// [TextEditingController] to control the text manually. Sets a default [TextEditingController()] object if none given
  final TextEditingController? controller;

  /// Enabled Color fill for individual pin fields, default is [false]
  final bool enableActiveFill;

  /// Auto dismiss the keyboard upon inputting the value for the last field. Default is [true]
  final bool autoDismissKeyboard;

  /// Auto dispose the [controller] and [FocusNode] upon the destruction of widget from the widget tree. Default is [true]
  final bool autoDisposeControllers;

  /// Configures how the platform keyboard will select an uppercase or lowercase keyboard.
  /// Only supports text keyboards, other keyboard types will ignore this configuration. Capitalization is locale-aware.
  /// - Copied from 'https://api.flutter.dev/flutter/services/TextCapitalization-class.html'
  /// Default is [TextCapitalization.none]
  final TextCapitalization textCapitalization;

  final TextInputAction textInputAction;

  /// Triggers the error animation
  final StreamController<ErrorAnimationType>? errorAnimationController;

  /// Callback method to validate if text can be pasted. This is helpful when we need to validate text before pasting.
  /// e.g. validate if text is number. Default will be pasted as received.
  final bool Function(String? text)? beforeTextPaste;

  /// Method for detecting a pin_code form tap
  /// work with all form windows
  final Function? onTap;

  /// Configuration for paste dialog. Read more [DialogConfig]
  final DialogConfig? dialogConfig;

  /// Theme for the pin cells. Read more [PinTheme]
  final PinTheme pinTheme;

  /// Brightness dark or light choices for iOS keyboard.
  final Brightness? keyboardAppearance;

  /// Validator for the [TextFormField]
  final FormFieldValidator<String>? validator;

  /// An optional method to call with the final value when the form is saved via
  /// [FormState.save].
  final FormFieldSetter<String>? onSaved;

  /// enables auto validation for the [TextFormField]
  /// Default is [AutovalidateMode.onUserInteraction]
  final AutovalidateMode autovalidateMode;

  /// The vertical padding from the [PinCodeTextField] to the error text
  /// Default is 16.
  final double errorTextSpace;

  /// Margin for the error text
  /// Default is [EdgeInsets.zero].
  final EdgeInsets errorTextMargin;

  /// [TextDirection] to control a direction in which text flows.
  /// Default is [TextDirection.ltr]
  final TextDirection errorTextDirection;

  /// Enables pin autofill for TextFormField.
  /// Default is true
  final bool enablePinAutofill;

  /// Error animation duration
  final int errorAnimationDuration;

  /// Whether to show cursor or not
  final bool showCursor;

  /// The color of the cursor, default to Theme.of(context).accentColor
  final Color? cursorColor;

  /// width of the cursor, default to 2
  final double cursorWidth;

  /// Height of the cursor, default to FontSize + 8;
  final double? cursorHeight;

  /// Autofill cleanup action
  final AutofillContextAction onAutoFillDisposeAction;

  /// Use external [AutoFillGroup]
  final bool useExternalAutoFillGroup;

  /// Displays a hint or placeholder in the field if it's value is empty.
  /// It only appears if it's not null. Single character is recommended.
  final String? hintCharacter;

  /// the style of the [hintCharacter], default is [fontSize: 20, fontWeight: FontWeight.bold]
  /// and it also uses the [textStyle]'s properties
  /// [TextStyle.color] is [Colors.grey]
  final TextStyle? hintStyle;

  /// ScrollPadding follows the same property as TextField's ScrollPadding, default to
  /// const EdgeInsets.all(20),
  final EdgeInsets scrollPadding;

  /// Text gradient for Pincode
  final Gradient? textGradient;

  /// Makes the pin cells readOnly
  final bool readOnly;

  /// Enable auto unfocus
  final bool autoUnfocus;

  /// Builds separator children
  final IndexedWidgetBuilder? separatorBuilder;

PinTheme

/// Colors of the input fields which have inputs. Default is [Colors.green]
  final Color activeColor;

  /// Color of the input field which is currently selected. Default is [Colors.blue]
  final Color selectedColor;

  /// Colors of the input fields which don't have inputs. Default is [Colors.red]
  final Color inactiveColor;

  /// Colors of the input fields if the [PinCodeTextField] is disabled. Default is [Colors.grey]
  final Color disabledColor;

  /// Colors of the input fields which have inputs. Default is [Colors.green]
  final Color activeFillColor;

  /// Color of the input field which is currently selected. Default is [Colors.blue]
  final Color selectedFillColor;

  /// Colors of the input fields which don't have inputs. Default is [Colors.red]
  final Color inactiveFillColor;

  /// Color of the input field when in error mode. Default is [Colors.redAccent]
  final Color errorBorderColor;

  /// Border radius of each pin code field
  final BorderRadius borderRadius;

  /// [height] for the pin code field. default is [50.0]
  final double fieldHeight;

  /// [width] for the pin code field. default is [40.0]
  final double fieldWidth;

  /// Border width for the each input fields. Default is [2.0]
  final double borderWidth;

  /// this defines the shape of the input fields. Default is underlined
  final PinCodeFieldShape shape;

DialogConfig

/// title of the [AlertDialog] while pasting the code. Default to [Paste Code]
  final String dialogTitle;

  /// content of the [AlertDialog] while pasting the code. Default to ["Do you want to paste this code "]
  final String dialogContent;

  /// Affirmative action text for the [AlertDialog]. Default to "Paste"
  final String affirmativeText;

  /// Negative action text for the [AlertDialog]. Default to "Cancel"
  final String negativeText;

  /// The default dialog theme, should it be iOS or other(including web and Android)
  final Platform platform; //enum Platform { iOS, other } other indicates for web and android

Contributors ✨

Thanks to everyone whoever suggested their thoughts to improve this package. And special thanks goes to these people:

Emmanuel Vlad
Emmanuel Vlad

πŸ“–πŸ’»
Atiq
Atiqur Rahaman

🎨
Milind Mevada
Milind Mevada

πŸ“–πŸ’»
Reme Le Hane
Reme Le Hane

πŸ“–πŸ’»
TabooSun
TabooSun

πŸ’»
Thalles Santos
Thalles Santos

πŸ’»
ItamarMu
ItamarMu

πŸ’»
Jonathan White
ThinkDigitalSoftware

πŸ’»
Jeffry Hermanto
Jeffry Hermanto

πŸ’»
ItamarMu
ItamarMu

πŸ’»
Sebastian Roth
Sebastian Roth

πŸ’»
Dango Mango
Dango Mango

πŸ’»
Stanislav Ilin
Stanislav Ilin

πŸ’»
Varun Barad
Varun Barad

πŸ’»
Mohak Shrivastava
Mohak Shrivastava

πŸ’»
ItamarMu
ItamarMu

πŸ’»
Kim Minju
Kim Minju

πŸ’»
Dmitry Vakhnin
Dmitry Vakhnin

πŸ’»
serendipity1004
Jiho Choi

πŸ’»
jobfeikens
Job

πŸ’»
BrunoEleodoro
Bruno Eleodoro Roza

πŸ’»
tgbarker
tgbarker

πŸ’»
karabanovbs
karabanovbs

πŸ’»
adarsh-technocrat
Adarsh kumar singh

πŸ’»
adrianFarkas
Farkas AdriΓ‘n

πŸ’»
grafovdenis
Denis Grafov

πŸ’»
ItzNotABug
DarShan

πŸ’»
dhruvanbhalara
Dhruvan Bhalara

πŸ’»
rodion-m
Rodion Mostovoy

πŸ’»
nerotyc
Robin Holzinger

πŸ’»
Graaggas
Deyew Vladimir

πŸ’»
Add00w
Abdullahi A. Addow

πŸ’»
vlkonoshenko
Konoshenko Vlad

πŸ’»

The pin code text field widget example

PinCodeTextField(
  length: 6,
  obscureText: false,
  animationType: AnimationType.fade,
  pinTheme: PinTheme(
    shape: PinCodeFieldShape.box,
    borderRadius: BorderRadius.circular(5),
    fieldHeight: 50,
    fieldWidth: 40,
    activeFillColor: Colors.white,
  ),
  animationDuration: Duration(milliseconds: 300),
  backgroundColor: Colors.blue.shade50,
  enableActiveFill: true,
  errorAnimationController: errorController,
  controller: textEditingController,
  onCompleted: (v) {
    print("Completed");
  },
  onChanged: (value) {
    print(value);
    setState(() {
      currentText = value;
    });
  },
  beforeTextPaste: (text) {
    print("Allowing to paste $text");
    //if you return true then it will show the paste confirmation dialog. Otherwise if false, then nothing will happen.
    //but you can show anything you want here, like your pop up saying wrong paste format or etc
    return true;
  },
)

Shape can be among these 3 types

enum PinCodeFieldShape { box, underline, circle }

Animations can be among these 3 types

enum AnimationType { scale, slide, fade, none }

Haptic Feedbacks can be among these 5 types

enum HapticFeedbackTypes {
  heavy,
  light,
  medium,
  selection,
  vibrate,
}

Trigger Error animation

  1. Create a StreamController
StreamController<ErrorAnimationType> errorController = StreamController<ErrorAnimationType>();
  1. And pass the controller like this.
PinCodeTextField(
  length: 6,
  obscureText: false,
  animationType: AnimationType.fade,
  animationDuration: Duration(milliseconds: 300),
  errorAnimationController: errorController, // Pass it here
  onChanged: (value) {
    setState(() {
      currentText = value;
    });
  },
)
  1. Then you can trigger the animation just by writing this:
errorController.add(ErrorAnimationType.shake); // This will shake the pin code field

This full code is from the example folder. You can run the example to see.

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: PinCodeVerificationScreen(
          "+8801376221100"), // a random number, please don't call xD
    );
  }
}

class PinCodeVerificationScreen extends StatefulWidget {
  final String phoneNumber;

  PinCodeVerificationScreen(this.phoneNumber);

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

class _PinCodeVerificationScreenState extends State<PinCodeVerificationScreen> {
  var onTapRecognizer;

  TextEditingController textEditingController = TextEditingController();
  // ..text = "123456";

  StreamController<ErrorAnimationType> errorController;

  bool hasError = false;
  String currentText = "";
  final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();
  final formKey = GlobalKey<FormState>();

  @override
  void initState() {
    onTapRecognizer = TapGestureRecognizer()
      ..onTap = () {
        Navigator.pop(context);
      };
    errorController = StreamController<ErrorAnimationType>();
    super.initState();
  }

  @override
  void dispose() {
    errorController.close();

    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.blue.shade50,
      key: scaffoldKey,
      body: GestureDetector(
        onTap: () {},
        child: Container(
          height: MediaQuery.of(context).size.height,
          width: MediaQuery.of(context).size.width,
          child: ListView(
            children: <Widget>[
              SizedBox(height: 30),
              Container(
                height: MediaQuery.of(context).size.height / 3,
                child: FlareActor(
                  "assets/otp.flr",
                  animation: "otp",
                  fit: BoxFit.fitHeight,
                  alignment: Alignment.center,
                ),
              ),
              SizedBox(height: 8),
              Padding(
                padding: const EdgeInsets.symmetric(vertical: 8.0),
                child: Text(
                  'Phone Number Verification',
                  style: TextStyle(fontWeight: FontWeight.bold, fontSize: 22),
                  textAlign: TextAlign.center,
                ),
              ),
              Padding(
                padding:
                    const EdgeInsets.symmetric(horizontal: 30.0, vertical: 8),
                child: RichText(
                  text: TextSpan(
                      text: "Enter the code sent to ",
                      children: [
                        TextSpan(
                            text: widget.phoneNumber,
                            style: TextStyle(
                                color: Colors.black,
                                fontWeight: FontWeight.bold,
                                fontSize: 15)),
                      ],
                      style: TextStyle(color: Colors.black54, fontSize: 15)),
                  textAlign: TextAlign.center,
                ),
              ),
              SizedBox(
                height: 20,
              ),
              Form(
                key: formKey,
                child: Padding(
                    padding: const EdgeInsets.symmetric(
                        vertical: 8.0, horizontal: 30),
                    child: PinCodeTextField(
                      appContext: context,
                      pastedTextStyle: TextStyle(
                        color: Colors.green.shade600,
                        fontWeight: FontWeight.bold,
                      ),
                      length: 6,
                      obscureText: false,
                      obscuringCharacter: '*',
                      animationType: AnimationType.fade,
                      validator: (v) {
                        if (v.length < 3) {
                          return "I'm from validator";
                        } else {
                          return null;
                        }
                      },
                      pinTheme: PinTheme(
                        shape: PinCodeFieldShape.box,
                        borderRadius: BorderRadius.circular(5),
                        fieldHeight: 60,
                        fieldWidth: 50,
                        activeFillColor:
                            hasError ? Colors.orange : Colors.white,
                      ),
                      cursorColor: Colors.black,
                      animationDuration: Duration(milliseconds: 300),
                      textStyle: TextStyle(fontSize: 20, height: 1.6),
                      backgroundColor: Colors.blue.shade50,
                      enableActiveFill: true,
                      errorAnimationController: errorController,
                      controller: textEditingController,
                      keyboardType: TextInputType.number,
                      boxShadows: [
                        BoxShadow(
                          offset: Offset(0, 1),
                          color: Colors.black12,
                          blurRadius: 10,
                        )
                      ],
                      onCompleted: (v) {
                        print("Completed");
                      },
                      // onTap: () {
                      //   print("Pressed");
                      // },
                      onChanged: (value) {
                        print(value);
                        setState(() {
                          currentText = value;
                        });
                      },
                      beforeTextPaste: (text) {
                        print("Allowing to paste $text");
                        //if you return true then it will show the paste confirmation dialog. Otherwise if false, then nothing will happen.
                        //but you can show anything you want here, like your pop up saying wrong paste format or etc
                        return true;
                      },
                    )),
              ),
              Padding(
                padding: const EdgeInsets.symmetric(horizontal: 30.0),
                child: Text(
                  hasError ? "*Please fill up all the cells properly" : "",
                  style: TextStyle(
                      color: Colors.red,
                      fontSize: 12,
                      fontWeight: FontWeight.w400),
                ),
              ),
              SizedBox(
                height: 20,
              ),
              RichText(
                textAlign: TextAlign.center,
                text: TextSpan(
                    text: "Didn't receive the code? ",
                    style: TextStyle(color: Colors.black54, fontSize: 15),
                    children: [
                      TextSpan(
                          text: " RESEND",
                          recognizer: onTapRecognizer,
                          style: TextStyle(
                              color: Color(0xFF91D3B3),
                              fontWeight: FontWeight.bold,
                              fontSize: 16))
                    ]),
              ),
              SizedBox(
                height: 14,
              ),
              Container(
                margin:
                    const EdgeInsets.symmetric(vertical: 16.0, horizontal: 30),
                child: ButtonTheme(
                  height: 50,
                  child: FlatButton(
                    onPressed: () {
                      formKey.currentState.validate();
                      // conditions for validating
                      if (currentText.length != 6 || currentText != "towtow") {
                        errorController.add(ErrorAnimationType
                            .shake); // Triggering error shake animation
                        setState(() {
                          hasError = true;
                        });
                      } else {
                        setState(() {
                          hasError = false;
                          scaffoldKey.currentState.showSnackBar(SnackBar(
                            content: Text("Aye!!"),
                            duration: Duration(seconds: 2),
                          ));
                        });
                      }
                    },
                    child: Center(
                        child: Text(
                      "VERIFY".toUpperCase(),
                      style: TextStyle(
                          color: Colors.white,
                          fontSize: 18,
                          fontWeight: FontWeight.bold),
                    )),
                  ),
                ),
                decoration: BoxDecoration(
                    color: Colors.green.shade300,
                    borderRadius: BorderRadius.circular(5),
                    boxShadow: [
                      BoxShadow(
                          color: Colors.green.shade200,
                          offset: Offset(1, -2),
                          blurRadius: 5),
                      BoxShadow(
                          color: Colors.green.shade200,
                          offset: Offset(-1, 2),
                          blurRadius: 5)
                    ]),
              ),
              SizedBox(
                height: 16,
              ),
              Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  FlatButton(
                    child: Text("Clear"),
                    onPressed: () {
                      textEditingController.clear();
                    },
                  ),
                  FlatButton(
                    child: Text("Set Text"),
                    onPressed: () {
                      textEditingController.text = "123456";
                    },
                  ),
                ],
              )
            ],
          ),
        ),
      ),
    );
  }
}

pin_code_fields's People

Contributors

adar2378 avatar add00w avatar adrianfarkas avatar brunoeleodoro avatar darkang3lz92 avatar dhruvanbhalara avatar emmanuelvlad avatar ened avatar frezyx avatar githelge avatar grafovdenis avatar itamarmu avatar itznotabug avatar jeffryhermanto avatar jobfeikens avatar jsbmand avatar karabanovbs avatar mohak852 avatar outdatedguy avatar robinholzi avatar rodion-m avatar serendipity1004 avatar shaurya-src avatar shliama avatar superakabo avatar techno-disaster avatar tgbarker avatar thallessantos avatar will-ramon-remo avatar ymdkit avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pin_code_fields's Issues

append text programatically

if I want to set a value in pin code fields how do I do that, I don't see any parameter that allows me set the text. you don't expose the textediting controller

change pin theme after some validation

Hi thank you for this project. this is great. but I do want to change pinTheme (underline color) after some validation. for example I have if it's not error, activeColor should be green and if some validation its not valid, then activeColor should be red like this :

PinTheme pinTheme = _isOtpValid
          ? PinTheme(
              activeColor: Color.green,
           )
          : PinTheme(
              activeColor: Color.red,
          );

PinCodeTextField(
    pinTheme: pinTheme,
)

I set it with setState but pinTheme is not updated. do you have any suggestion for this kind of scenario ?

Allow modifying the shown theme color for the last input field

When completing all input fields the last field gets displayed in the selectedColor of the specified pin theme, as you can see here (selectedColor is blue and activeColor is green in this case):

Screenshot 2020-05-11 at 15 57 05
I need the last input field to be displayed in the activeColor though, so that it's color matches the color of all other fields and therefore indicates that the pin input is completed. This is what I expect when all pin fields are entered:
Screenshot 2020-05-11 at 16 02 52
The required change concerns the following private method from lib/pin_code_fields.dart. For this one could add an attribute to the PinCodeTextField widget that determines what color gets returned for the last input field in _getColorFromIndex() instead of generically displaying the last input as selected.

// selects the right color for the field
  Color _getColorFromIndex(int index) {
    if (!widget.enabled) {
      return _pinTheme.disabledColor;
    }
    if (((_selectedIndex == index) ||
            (_selectedIndex == index + 1 && index + 1 == widget.length)) &&
        _focusNode.hasFocus) {
      return _pinTheme.selectedColor;
    } else if (_selectedIndex > index) {
      return _pinTheme.activeColor;
    }
    return _pinTheme.inactiveColor;
  }

Web version request

Is it planned to adapt to web use? Not working right now: keyboard input not accepted

Bad state: Stream has already been listened to

Hi,
Thank you for creating the library, it is pretty good.

Just faced this issue -
I have set a stream to errorAnimationController, the field itself is inside a stateful widget. I call setState and replace the field with a loader which causes the field's dispose() to be called but since the subscription to error stream is not cancelled, when the field is visible again it cannot listen to the same error stream.

afaiu, one possible solution could be to store the subscription returned by listen at https://github.com/adar2378/pin_code_fields/blob/master/lib/pin_code_fields.dart#L200
and cancel it in the dispose.

Bad cursor position for box shape

The cursor position is very ugly when using the box shape.

A simple solution or rather workaround would be to disable the cursor but that's not currently possible.

Sample code:

Widget build(BuildContext context) {
    return Scaffold(
      body: Padding(
        padding: EdgeInsets.all(60),
        child: PinCodeTextField(
          shape: PinCodeFieldShape.box,
          length: 4,
          currentText: (value) => print,
        ),
      ),
    );
  }
Misplaced cursor on iPhone 11 Max simulator
Captura de Pantalla 2019-11-03 a la(s) 04 07 07
^ the blue arrow is artificially added for illustration

Feature Request: Keyboard Type

I was using this plugin for OTP verification and typically it's in Number format

It will be great if we can choose the keyboard type like normal TextEdit

show keyboard after on back press

It is not possible to show keyboard again , after pressing keyboard's on back button.
Please help to solve this issue. I already used autoDisposeControllers: false ,but it doesn't work.And problem is only for android devices.

IOS - misplaced cursor

Hi, my QA team found that there's a misplaced cursor on the iOS iPhone 7 device running ios 13.

6b53c2c4-beee-4517-a37f-f0a84c4876ba

Here's my implementation

return new Scaffold(
      key: _otpKey,
      backgroundColor: Colors.white,
      appBar: CustomAppBar(title: AppLocalization.of(context).verificationNumber, showBackButton: false),
      body: _isResendLoading
          ? LoadingIndicator()
          : Container(
              padding: EdgeInsets.fromLTRB(40.0, 20.0, 40.0, 20.0),
              child: new Column(
                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                children: <Widget>[
                  Container(
                    margin: EdgeInsets.only(top: 15.0),
                  ),
                  RichText(
                    text: TextSpan(
                      style: TextStyle(color: CustomColors.mainColor()),
                      children: <TextSpan>[
                        TextSpan(text: AppLocalization.of(context).enterTheCode + ' '),
                        TextSpan(
                            text: phoneNumber + '.',
                            style: TextStyle(fontWeight: FontWeight.bold)),
                        TextSpan(text: ' ' + AppLocalization.of(context).itsOnlyValid),
                      ],
                    ),
                  ),
                  _buildForm(context),
                  Expanded(
                    child: Align(
                      alignment: Alignment.bottomCenter,
                      child: _buildBottom(context),
                    ),
                  ),
                ],
              ),
            ),
    );
  }

  Widget _buildForm(context) {
    return new Form(
      key: otpFormKey,
      child: new Container(
        width: 250.0,
        child: new Column(
          children: <Widget>[
            PinCodeTextField(
              length: 4,
              obsecureText: false,
              shape: PinCodeFieldShape.circle,
              borderRadius: BorderRadius.circular(20.0),
              backgroundColor: Colors.white,
              textInputType: TextInputType.number,
              currentText: (value) {
                setState(() {
                  _otpCode = value;
                });

                if (value.length == 4) {
                  verifyOtp();
                  return;
                }
              },
              borderWidth: 2.0,
              activeColor: Color.fromRGBO(90, 96, 117, 1),
              inactiveColor: Color.fromRGBO(205, 205, 205, 1),
              fieldHeight: 100.0,
              fieldWidth: 50.0,
            )
          ],
        ),
      ),
    );
  }

setState() called after dispose() Exception

Having an exception i don't know why. This caurses the excception

      ```

onChanged: (value) {
setState(() {
currentText = value;
});
},



otp_screen.dart

class OtpScreen extends StatefulWidget {
@OverRide
_OtpScreenState createState() => _OtpScreenState();
}

class _OtpScreenState extends State {
var onTapRecognizer;
TextEditingController textEditingController = TextEditingController();
StreamController errorController;
bool hasError = false;
String currentText = "";
final GlobalKey scaffoldKey = GlobalKey();

@OverRide
void initState() {
onTapRecognizer = TapGestureRecognizer()
..onTap = () {
Navigator.pop(context);
};
errorController = StreamController();
super.initState();
}

@OverRide
void dispose() {
errorController.close();
super.dispose();
}

@OverRide
Widget build(BuildContext context) {
return Scaffold(
key: scaffoldKey,
body: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.only(
left: SizeConfig.widthMultiplier * 7,
right: SizeConfig.widthMultiplier * 7,
top: SizeConfig.heightMultiplier * 10,
bottom: SizeConfig.heightMultiplier * 7,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Enter OTP',
style: Styles.bigPageTitleStyles,
),
SizedBox(height: SizeConfig.heightMultiplier * 5),
Text(
'Enter the Six Digit Code Sent',
style: Styles.bigPageTitleStyles.copyWith(
fontSize: SizeConfig.textSizeMultiplier * 2.5,
letterSpacing: 1,
color: AppColor.secondaryColor,
),
),
SizedBox(height: SizeConfig.heightMultiplier * 2),
Container(
height: SizeConfig.heightMultiplier * 10,
width: double.infinity,
child: Text(
'Check 0813677229 for the six digit code sent, if not found, click on resend below after 3 minutes',
style: Styles.bigPageTitleStyles.copyWith(
fontSize: SizeConfig.textSizeMultiplier * 2,
letterSpacing: 1,
color: AppColor.secondaryColor.withOpacity(0.5),
),
),
),
SizedBox(height: SizeConfig.heightMultiplier * 3),
Padding(
padding:
const EdgeInsets.symmetric(vertical: 8.0, horizontal: 30),
child: PinCodeTextField(
inactiveColor: AppColor.accentColor,
textStyle: TextStyle(
fontSize: 30,
fontFamily: 'Roboto Bold',
color: AppColor.secondaryColor,
),
selectedColor: AppColor.primaryColor,
textInputType: TextInputType.number,
length: 6,
obsecureText: false,
animationType: AnimationType.fade,
shape: PinCodeFieldShape.underline,
animationDuration: Duration(milliseconds: 300),
borderRadius: BorderRadius.circular(5),
fieldHeight: 50,
backgroundColor: Colors.blue.shade50,
fieldWidth: 40,
activeFillColor: Colors.white,
enableActiveFill: false,
errorAnimationController: errorController,
controller: textEditingController,
onCompleted: (v) {
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (BuildContext context) => BaseScreen()));
},
onChanged: (value) {
print(value);
setState(() {
currentText = value;
});
},
),
),
SizedBox(
height: 20,
),
RichText(
textAlign: TextAlign.center,
text: TextSpan(
text: "Didn't receive the code? ",
style: TextStyle(color: Colors.black54, fontSize: 15),
children: [
TextSpan(
text: " RESEND",
recognizer: onTapRecognizer,
style: TextStyle(
color: Color(0xFF91D3B3),
fontWeight: FontWeight.bold,
fontSize: 16))
]),
),
SizedBox(
height: 14,
),
],
),
),
),
);
}
}


Please how can i fix it??

Unable to open keyboard

When pressing the back button to close the keyboard, you can't open the keyboard back up again.

Can you show the focus box cursor?

Now the focus is on the change between the outer box and the bottom color, but in fact, it should conform to the characteristics of the input box and show the position of the cursor, which will make it easier to see the current input position.

I found that there is no way to set it through parameters. I hope to add this feature.

It's a great project, so I want her to be perfect. Thank you

TextSelection not correctly resumed after keyboard done action and refocusing

22 typed: ` TextEditingValue(text: ─22β”œ, selection: TextSelection(baseOffset: 2, extentOffset: 2, affinity: TextAffinity.downstream, isDirectional: false), composing: TextRange(start: -1, end: -1))

done typed: flutter: TextEditingValue(text: ─22β”œ, selection: TextSelection(baseOffset: -1, extentOffset: -1, affinity: TextAffinity.downstream, isDirectional: false), composing: TextRange(start: -1, end: -1))

refocus PinCodeTextField: flutter: TextEditingValue(text: ─22β”œ, selection: TextSelection(baseOffset: 0, extentOffset: 0, affinity: TextAffinity.downstream, isDirectional: false), composing: TextRange(start: 0, end: 0))`

the baseOffset becomes 0 rather than recover to 2.

pinCodeField dispose dispose the TextEditingController

in my code i made a setState and change the field with a loading, this cause this field dispose method was called, it dispose my TextEditingController and when the loading finish and the pinCodeField is called again, the controller was disposed.

A TextEditingController was used after being disposed.

bug: iOS autofill can not trigger ValueChanged function

In my use case, if the pin codes positions have been filled fully. Then the codes will be commited automatically.

Now,IOS autofill can not trigger ValueChanged function, so I don't not know when the pin code has been filled.

final ValueChanged<String> currentText

HOWTO: show keyboard on resume

May I kindly have some assistance how to show a keyboard on resume?

Here's my code:


class _PinCodeVerificationScreenState extends State<PinCodeVerificationScreen> with WidgetsBindingObserver {

  TextEditingController controller = TextEditingController();
  FocusNode _focusNode;
  bool hasError = false;
  String currentText = "";
  bool _isButtonTapped = false;

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
    _focusNode = FocusNode();
  }

  void didChangeAppLifecycleState(AppLifecycleState state) {
    if(state == AppLifecycleState.resumed){
      print('RESUME');
      _focusNode.requestFocus();
    }
  }

  @override
  void dispose() {
    super.dispose();
    WidgetsBinding.instance.addObserver(this);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: GestureDetector(
        onTap: () => FocusScope.of(context).requestFocus(new FocusNode()),
        child: Container(
          height: MediaQuery.of(context).size.height,
          width: MediaQuery.of(context).size.width,
          child: ListView(
            children: <Widget>[
              SizedBox(height: 8),
              Padding(
                padding: const EdgeInsets.symmetric(vertical: 8.0),
                child: Text('Codice di verifica', style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18), textAlign: TextAlign.center),
              ),
              Padding(
                padding:const EdgeInsets.symmetric(vertical: 0.0, horizontal: 5),
                child: PinCodeTextField(
                  controller: controller,
                  backgroundColor: Colors.transparent, // remove this line to have white background
                  textInputType: TextInputType.number,
                  autoFocus: true,
                  focusNode: _focusNode,
                  


support - dot like input

not a circle put "Β·" dot like pincode input.
is there current way to implement this shape? since the shape cannot be fully customized.

Unhandled Exception: setState() called after dispose():

pin_code_fields: ^3.1.2

This PinCodeTextField is used to enter an OTP (OneTimePhone) SMS code.
The first time the field is used, and _linkWithOTP() validates the code, there is no error.
When the code is not valid, and the PinCodeTextField is focused (or tapped if autoFocus: false), the error is displayed before any characters are entered.

 Unhandled Exception: setState() called after dispose():
Widget _smsCode() {
    return !_codeSent 
      ? SizedBox() 
      : Column(
        children: <Widget>[
          PinCodeTextField (
            autoFocus: true,
            backgroundColor: Colors.grey[50],
            length: 6,
            autoDisposeControllers: false,
            mainAxisAlignment: MainAxisAlignment.spaceAround,
            textInputType: TextInputType.number,
            controller: _smsEditingCodeController,
            pinTheme: PinTheme(
              //shape: PinCodeFieldShape.box,
              borderRadius: BorderRadius.circular(5),
              fieldHeight: 50,
              fieldWidth: 30,
              //activeFillColor: hasError ? Colors.orange : Colors.white,
            ),
            onCompleted: (String v) {
              setState(() => _smsEditingCodeController.text = '');
              _linkWithOTP(
                context: context, 
                verificationId: _verificationId, 
                smsCode: v);
            },
            onChanged: (value) {},
          ),
          Text('Enter SMS code'),
        ],
    );
  }
E/flutter (17294): [ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: setState() called after dispose(): _PinCodeTextFieldState#71afa(lifecycle state: defunct, not mounted, ticker inactive)
E/flutter (17294): This error happens if you call setState() on a State object for a widget that no longer appears in the widget tree (e.g., whose parent widget no longer includes the widget in its build). This error can occur when code calls setState() from a timer or an animation callback.
E/flutter (17294): The preferred solution is to cancel the timer or stop listening to the animation in the dispose() callback. Another solution is to check the "mounted" property of this object before calling setState() to ensure the object is still in the tree.
E/flutter (17294): This error might indicate a memory leak if setState() is being called because another object is retaining a reference to this State object after it has been removed from the tree. To avoid memory leaks, consider breaking the reference to this object during dispose().

E/flutter (17294): #0      State.setState.<anonymous closure> 
package:flutter/…/widgets/framework.dart:1197
E/flutter (17294): #1      State.setState 
package:flutter/…/widgets/framework.dart:1232
E/flutter (17294): #2      _PinCodeTextFieldState._setTextToInput 
package:pin_code_fields/pin_code_fields.dart:561
E/flutter (17294): #3      _PinCodeTextFieldState._assignController.<anonymous closure> 
package:pin_code_fields/pin_code_fields.dart:270
E/flutter (17294): #4      ChangeNotifier.notifyListeners 
package:flutter/…/foundation/change_notifier.dart:207
E/flutter (17294): #5      ValueNotifier.value= 
package:flutter/…/foundation/change_notifier.dart:274
E/flutter (17294): #6      TextEditingController.selection= 
package:flutter/…/widgets/editable_text.dart:194
E/flutter (17294): #7      EditableTextState._handleSelectionChanged 
package:flutter/…/widgets/editable_text.dart:1547
E/flutter (17294): #8      EditableTextState._handleFocusChanged 
package:flutter/…/widgets/editable_text.dart:1802
E/flutter (17294): #9      ChangeNotifier.notifyListeners 
package:flutter/…/foundation/change_notifier.dart:207
E/flutter (17294): #10     FocusNode._notify 
package:flutter/…/widgets/focus_manager.dart:970
E/flutter (17294): #11     FocusManager._applyFocusChange 
package:flutter/…/widgets/focus_manager.dart:1633
E/flutter (17294): #12     _rootRun  (dart:async/zone.dart:1180:38)
E/flutter (17294): #13     _CustomZone.run  (dart:async/zone.dart:1077:19)
E/flutter (17294): #14     _CustomZone.runGuarded  (dart:async/zone.dart:979:7)
E/flutter (17294): #15     _CustomZone.bindCallbackGuarded.<anonymous closure>  (dart:async/zone.dart:1019:23)
E/flutter (17294): #16     _rootRun  (dart:async/zone.dart:1184:13)
E/flutter (17294): #17     _CustomZone.run  (dart:async/zone.dart:1077:19)
E/flutter (17294): #18     _CustomZone.runGuarded  (dart:async/zone.dart:979:7)
E/flutter (17294): #19     _CustomZone.bindCallbackGuarded.<anonymous closure>  (dart:async/zone.dart:1019:23)
E/flutter (17294): #20     _microtaskLoop  (dart:async/schedule_microtask.dart:43:21)
E/flutter (17294): #21     _startMicrotaskLoop  (dart:async/schedule_microtask.dart:52:5)
E/flutter (17294):

Request: Ability to reset the input

When used for login, if the user types the incorrect pin by mistake, it would be much nicer to be able to clear the field as to not have to go and delete the pin.

Keyboard does not show

The keyboard does not show up after clicking on the widget, does not focus.
The widget seems to be disabled for some reason?
Screenshot_1572288591

(This happens on the sample code too)

Force typing direction to LTR

Hi,

Currently direction of typing in this widget is based on current active local configuration of app.
But I would like to force this widget to set direction of typing always to LTR.
Because in Persian language that is RTL , but typing pin doesn't make sense to type form right to left.

How to do that?
Or where is related lines of code for that.
I think it's related to this code, but i don't know which parameters can do it.

Thanks.

Obscure delay [question/suggestion]

Hi there.

Is there an option to turn on the delay of obscuring?

Just like the obscureText property of a TextField widget, it shows what user has entered for roughly 1 second before hiding it.

Thanks!

dispose focusNode and controller

Hi,

Thanks for your awesome plugin!

I am confused about dispose process. I think this plug-in has auto dispose of focusNode and controller, so we cannot call focusNode.dispose() and controller.dispose() in our stateful widget (even If we assign a focus node or controller for the plug-in). Am I right about this?

Support FormValidators?

I realize there is a mechanism to support some level of validation with the onChanged event, but any chance of supporting FormValidators so we can wrap this into the entire form validation lifecycle like a standard TextFormField?

Great Project btw, thank you for this.
Bob

Feature request: autofocus and manually keyboard closing.

Can you give the capability to autofocus the pin code on opening?
Another minor feature is to give the capability to close the keyboard manually when the user writes the last character.
In general thx, I really like this library.

Themes?

Instead of passing in a bunch of colors, can\does the control support Themes?

Pasting text issue with inputFormatters

With the addition of inputFormatters when you paste an incorrect formatted text and then try to edit it, it'll reset the input.

Example:
Here I got inputFormatters: [WhitelistingTextInputFormatter.digitsOnly]
I can paste non digit text, but when I try to edit it, it resets

Solution:
Format the text when pasting it by using the inputFormatters

Feature Request: keyboardAppearance property

Thanks a lot for writing such a beautiful and useful package. It would be nice if the appearance of the keyboard could be changed on iOS devices like Brightness.light. I have created a Pull Request for this feature, please take a look, thanks again!

Make dialog more flexible.

I like the paste function of components very much.
But I think she can change.

The existing methods of parameter control will bring many problems, such as user interface and localization.
In fact, it can make it more flexible.
I've removed the getactionbuttons and showpastedialog functions.
Then I give the ownership to the developers themselves.

I added the following code:

final String Function(String pasteValue, String fieldValue) pasteAction;

            onLongPress: widget.enabled
                ? () async {
                    var data = await Clipboard.getData("text/plain");
                    if (data.text.isNotEmpty) {
                      var str = widget.pasteAction(data.text, _textEditingController.text);
                      if (str != null && str.isNotEmpty == true){
                        _textEditingController.text = str.substring(0, widget.length - 1);
                      }
                      else if (widget.pasteAction == null){ // Default paste
                        _textEditingController.text = data.text.substring(0, widget.length - 1);
                      }
                    }
                  }
                : null,

In this way, developers can customize the response mode of pasteaction. You can adjust it according to your UI, and you can consider the need to paste without asking.

Because multiple parameters will be deleted. So I didn't try to pull the request.

support inputFormatters and onComplete(String val)

I have two ideas.

  1. TextFormField support keyboard inputFormatters such as :
    inputFormatters: [WhitelistingTextInputFormatter.digitsOnly]

    Hope this config can be expose to developers.

  2. If all pin code position has been filled , trigger a callback function like onComplete(String val) will be
    better.

Not support iOS autofill

As the title say.

In my using scene,when iPhone get sms code,the code will be dissplayed on keyboard.

After clicking the sms code on keyboard, the code will autofill the pin code.

However , pin_code_fields only fill the last pin code position with the other positions empty.

The following two images cut from your example.


image

image

Bug: Impossible to open the keyboard again

Hello, there is a problem with the opening of the keyboard.
After you have focused the pin code if you press the Android back button to close the keyboard, you can't focus pin code again and open the keyboard.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.