adar2378 / pin_code_fields

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 🤓🤓
https://pub.dev/packages/pin_code_fields
MIT License
699 stars 340 forks source link

When pin_code becomes the focus, the build method is called multiple times #386

Open yanashenyang opened 2 months ago

yanashenyang commented 2 months ago

When pin_code becomes the focus, the build method is called multiple times

demo here:

import 'dart:async';

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

class TestPage extends StatelessWidget {
  TestPage({super.key});

  @override
  Widget build(BuildContext context) {
    print('test page build');
    return Scaffold(
      appBar: AppBar(
        title: Text('test page'),
      ),
      body: _codeWidget(context),
    );
  }

  final errorController = StreamController<ErrorAnimationType>();

  _codeWidget(BuildContext context) {
    return SizedBox(
      height: 52,
      width: MediaQuery.of(context).size.width,
      child: PinCodeTextField(
        length: 4,
        cursorColor: const Color(0xFF009B3C),
        keyboardType: TextInputType.number,
        obscureText: false,
        animationType: AnimationType.scale,
        pinTheme: PinTheme(
          shape: PinCodeFieldShape.box,
          borderRadius: BorderRadius.circular(5),
          fieldHeight: 52,
          fieldWidth: 52,
        ),
        animationDuration: const Duration(milliseconds: 300),
        enableActiveFill: true,
        errorAnimationController: errorController,
        onCompleted: (v) {
          print("Completed");
          Future.delayed(const Duration(seconds: 1)).then((_) {
            errorController.add(ErrorAnimationType.shake); // This will shake the pin code field
          });
        },
        appContext: context,
      ),
    );
  }
}

console:

flutter: test page build
flutter: test page build
flutter: test page build
flutter: test page build
flutter: test page build
flutter: test page build
flutter: test page build
flutter: test page build
flutter: test page build
flutter: test page build
flutter: test page build
flutter: test page build
flutter: test page build
flutter: test page build
flutter: test page build
flutter: test page build
flutter: test page build
flutter: test page build
flutter: test page build
flutter: test page build
flutter: test page build
flutter: test page build
flutter: test page build
flutter: test page build
flutter: test page build
flutter: test page build
flutter: test page build
flutter: test page build
flutter: test page build
flutter: test page build
flutter: test page build

why????

SebastijanKokai commented 1 month ago

Hi,

I don’t think this issue is a pin_code_fields package one. By using a function that returns a Widget, you are essentially not allowing Flutter to use its caching mechanism.
It's always better to use classes instead of functions.

Try the code sample below, it should solve your problem:

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

  @override
  Widget build(BuildContext context) {
    print('test page build');
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('test page'),
        ),
        body: TestWidget(),
      ),
    );
  }
}

class TestWidget extends StatelessWidget {
  TestWidget({super.key});

  final errorController = StreamController<ErrorAnimationType>();

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      height: 52,
      width: MediaQuery.of(context).size.width,
      child: PinCodeTextField(
        length: 4,
        cursorColor: const Color(0xFF009B3C),
        keyboardType: TextInputType.number,
        obscureText: false,
        animationType: AnimationType.scale,
        pinTheme: PinTheme(
          shape: PinCodeFieldShape.box,
          borderRadius: BorderRadius.circular(5),
          fieldHeight: 52,
          fieldWidth: 52,
        ),
        animationDuration: const Duration(milliseconds: 300),
        enableActiveFill: true,
        errorAnimationController: errorController,
        onCompleted: (v) {
          print("Completed");
          Future.delayed(const Duration(seconds: 1)).then((_) {
            errorController.add(
                ErrorAnimationType.shake); // This will shake the pin code field
          });
        },
        appContext: context,
      ),
    );
  }
}