【问题标题】:Making Phone Verification Textfield UI in flutter在颤动中制作电话验证文本字段 UI
【发布时间】:2019-08-22 13:01:35
【问题描述】:

我正在制作一个 UI,其中包含对电话号码的验证。它有四个要输入的代码,您将通过我们后端的通知获得这些代码。因为我负责为此制作 UI,所以它真的不适合我。

这是我想要实现的 UI:

我已尽我最大的努力来实现这一目标,但我每次都未能达到这一目标。

代码

Container(
   height: 64.0,
   width: 56.0,
   child: Card(
       color: Color.fromRGBO(173, 179, 191, 0.7),
       child: Padding(
            padding: EdgeInsets.only(left: 10.0, right: 10.0),
            child: TextEditorForPhoneVerify(this.codeOne)
       )
   )
)

我有自己的输入小部件:

class TextEditorForPhoneVerify extends StatelessWidget {
   final TextEditingController code;

   TextEditorForPhoneVerify(this.code);

   @override
   Widget build(BuildContext context) {
     return TextField(
       textAlign: TextAlign.center,
       keyboardType: TextInputType.number,
       controller: this.code,
       maxLength: 1,
       cursorColor: Theme.of(context).primaryColor,
       decoration: InputDecoration(
         hintText: "*",
         counterText: '',
         hintStyle: TextStyle(color: Colors.black, fontSize: 20.0)
       )
    );
  }
}

现在,每次我使用 textAlign: TextAlgn.center 时,它都会崩溃并且我的其他文本字段也会崩溃。我已经记下不要对所有人使用相同的小部件,它们都有不同的小部件。当我热启动它时,它可以工作。但是这个 textAlign 有问题。

我真的很想实现这一点,用上面的代码我得到了这个:

结果

当我尝试将光标置于中心时出现的错误是:

flutter: ══╡ EXCEPTION CAUGHT BY RENDERING LIBRARY ╞═════════════════════════════════════════════════════════
flutter: The following assertion was thrown during performLayout():
flutter: Please see the documentation for computeDistanceToActualBaseline for the required calling
flutter: conventions of this method.
flutter: 'package:flutter/src/rendering/box.dart': Failed assertion: line 1642 pos 12: '!_debugDoingBaseline'
flutter:
flutter: Either the assertion indicates an error in the framework itself, or we should provide substantially
flutter: more information in this error message to help you determine and fix the underlying cause.
flutter: In either case, please report this assertion by filing a bug on GitHub:
flutter:   https://github.com/flutter/flutter/issues/new?template=BUG.md
flutter:
flutter: When the exception was thrown, this was the stack:
flutter: #2      RenderBox.getDistanceToBaseline (package:flutter/src/rendering/box.dart:1642:12)
flutter: #3      _RenderDecoration._layout.layoutLineBox (package:flutter/src/material/input_decorator.dart:820:35)
flutter: #4      _RenderDecoration._layout (package:flutter/src/material/input_decorator.dart:857:18)
flutter: #5      _RenderDecoration.performLayout (package:flutter/src/material/input_decorator.dart:987:44)
flutter: #6      RenderObject.layout (package:flutter/src/rendering/object.dart:1632:7)
flutter: #7      _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
flutter: #8      RenderObject.layout (package:flutter/src/rendering/object.dart:1632:7)
flutter: #9      _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
flutter: #10     RenderObject.layout (package:flutter/src/rendering/object.dart:1632:7)
flutter: #11     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
flutter: #12     RenderObject.layout (package:flutter/src/rendering/object.dart:1632:7)
flutter: #13     RenderPadding.performLayout (package:flutter/src/rendering/shifted_box.dart:199:11)
flutter: #14     RenderObject.layout (package:flutter/src/rendering/object.dart:1632:7)
flutter: #15     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
flutter: #16     RenderObject.layout (package:flutter/src/rendering/object.dart:1632:7)
flutter: #17     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
flutter: #18     RenderObject.layout (package:flutter/src/rendering/object.dart:1632:7)
flutter: #19     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
flutter: #20     RenderObject.layout (package:flutter/src/rendering/object.dart:1632:7)
flutter: #21     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
flutter: #22     _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1206:11)
flutter: #23     RenderObject.layout (package:flutter/src/rendering/object.dart:1632:7)
flutter: #24     RenderPadding.performLayout (package:flutter/src/rendering/shifted_box.dart:199:11)
flutter: #25     RenderObject.layout (package:flutter/src/rendering/object.dart:1632:7)
flutter: #26     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
flutter: #27     RenderObject.layout (package:flutter/src/rendering/object.dart:1632:7)
flutter: #28     RenderConstrainedBox.performLayout (package:flutter/src/rendering/proxy_box.dart:259:13)
flutter: #29     RenderObject.layout (package:flutter/src/rendering/object.dart:1632:7)
flutter: #30     RenderFlex.performLayout (package:flutter/src/rendering/flex.dart:738:15)
flutter: #31     RenderObject.layout (package:flutter/src/rendering/object.dart:1632:7)
flutter: #32     RenderFlex.performLayout (package:flutter/src/rendering/flex.dart:738:15)
flutter: #33     RenderObject.layout (package:flutter/src/rendering/object.dart:1632:7)
flutter: #34     MultiChildLayoutDelegate.layoutChild (package:flutter/src/rendering/custom_layout.dart:142:11)
flutter: #35     _ScaffoldLayout.performLayout (package:flutter/src/material/scaffold.dart:350:7)
flutter: #36     MultiChildLayoutDelegate._callPerformLayout (package:flutter/src/rendering/custom_layout.dart:212:7)
flutter: #37     RenderCustomMultiChildLayoutBox.performLayout (package:flutter/src/rendering/custom_layout.dart:356:14)
flutter: #38     RenderObject.layout (package:flutter/src/rendering/object.dart:1632:7)
flutter: #39     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
flutter: #40     RenderObject.layout (package:flutter/src/rendering/object.dart:1632:7)
flutter: #41     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
flutter: #42     _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1206:11)
flutter: #43     RenderObject.layout (package:flutter/src/rendering/object.dart:1632:7)
flutter: #44     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
flutter: #45     RenderObject.layout (package:flutter/src/rendering/object.dart:1632:7)
flutter: #46     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
flutter: #47     RenderObject.layout (package:flutter/src/rendering/object.dart:1632:7)
flutter: #48     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
flutter: #49     RenderObject.layout (package:flutter/src/rendering/object.dart:1632:7)
flutter: #50     RenderStack.performLayout (package:flutter/src/rendering/stack.dart:510:15)
flutter: #51     RenderObject.layout (package:flutter/src/rendering/object.dart:1632:7)
flutter: #52     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
flutter: #53     RenderObject.layout (package:flutter/src/rendering/object.dart:1632:7)
flutter: #54     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
flutter: #55     RenderObject.layout (package:flutter/src/rendering/object.dart:1632:7)
flutter: #56     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
flutter: #57     RenderObject.layout (package:flutter/src/rendering/object.dart:1632:7)
flutter: #58     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
flutter: #59     RenderObject.layout (package:flutter/src/rendering/object.dart:1632:7)
flutter: #60     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
flutter: #61     RenderObject.layout (package:flutter/src/rendering/object.dart:1632:7)
flutter: #62     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
flutter: #63     RenderOffstage.performLayout (package:flutter/src/rendering/proxy_box.dart:3032:13)
flutter: #64     RenderObject.layout (package:flutter/src/rendering/object.dart:1632:7)
flutter: #65     RenderStack.performLayout (package:flutter/src/rendering/stack.dart:510:15)
flutter: #66     RenderObject.layout (package:flutter/src/rendering/object.dart:1632:7)
flutter: #67     __RenderTheatre&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
flutter: #68     RenderObject.layout (package:flutter/src/rendering/object.dart:1632:7)
flutter: #69     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
flutter: #70     RenderObject.layout (package:flutter/src/rendering/object.dart:1632:7)
flutter: #71     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
flutter: #72     RenderObject.layout (package:flutter/src/rendering/object.dart:1632:7)
flutter: #73     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
flutter: #74     RenderObject.layout (package:flutter/src/rendering/object.dart:1632:7)
flutter: #75     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
flutter: #76     RenderObject.layout (package:flutter/src/rendering/object.dart:1632:7)
flutter: #77     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
flutter: #78     RenderObject.layout (package:flutter/src/rendering/object.dart:1632:7)
flutter: #79     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
flutter: #80     RenderObject.layout (package:flutter/src/rendering/object.dart:1632:7)
flutter: #81     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
flutter: #82     RenderObject.layout (package:flutter/src/rendering/object.dart:1632:7)
flutter: #83     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
flutter: #84     RenderObject.layout (package:flutter/src/rendering/object.dart:1632:7)
flutter: #85     RenderStack.performLayout (package:flutter/src/rendering/stack.dart:510:15)
flutter: #86     RenderObject.layout (package:flutter/src/rendering/object.dart:1632:7)
flutter: #87     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
flutter: #88     RenderObject.layout (package:flutter/src/rendering/object.dart:1632:7)
flutter: #89     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
flutter: #90     RenderObject.layout (package:flutter/src/rendering/object.dart:1632:7)
flutter: #91     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
flutter: #92     RenderObject.layout (package:flutter/src/rendering/object.dart:1632:7)
flutter: #93     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
flutter: #94     RenderObject.layout (package:flutter/src/rendering/object.dart:1632:7)
flutter: #95     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
flutter: #96     RenderObject.layout (package:flutter/src/rendering/object.dart:1632:7)

Reloaded 0 of 567 libraries in 2,311ms.
flutter: #97     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
flutter: #98     RenderOffstage.performLayout (package:flutter/src/rendering/proxy_box.dart:3032:13)
flutter: #99     RenderObject.layout (package:flutter/src/rendering/object.dart:1632:7)
flutter: #100    RenderStack.performLayout (package:flutter/src/rendering/stack.dart:510:15)
flutter: #101    RenderObject.layout (package:flutter/src/rendering/object.dart:1632:7)
flutter: #102    __RenderTheatre&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
flutter: #103    RenderObject.layout (package:flutter/src/rendering/object.dart:1632:7)
flutter: #104    _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
flutter: #105    RenderObject.layout (package:flutter/src/rendering/object.dart:1632:7)
flutter: #106    _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
flutter: #107    RenderObject.layout (package:flutter/src/rendering/object.dart:1632:7)
flutter: #108    _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
flutter: #109    RenderObject.layout (package:flutter/src/rendering/object.dart:1632:7)
flutter: #110    _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
flutter: #111    RenderObject.layout (package:flutter/src/rendering/object.dart:1632:7)
flutter: #112    _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
flutter: #113    RenderObject.layout (package:flutter/src/rendering/object.dart:1632:7)
flutter: #114    RenderView.performLayout (package:flutter/src/rendering/view.dart:151:13)
flutter: #115    RenderObject._layoutWithoutResize (package:flutter/src/rendering/object.dart:1507:7)
flutter: #116    PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:766:18)
flutter: #117    _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding&PaintingBinding&SemanticsBinding&RendererBinding.drawFrame (package:flutter/src/rendering/binding.dart:329:19)
flutter: #118    _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding&PaintingBinding&SemanticsBinding&RendererBinding&WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:701:13)
flutter: #119    _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding&PaintingBinding&SemanticsBinding&RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:268:5)
flutter: #120    _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:988:15)
flutter: #121    _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:928:9)
flutter: #122    _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding.scheduleWarmUpFrame.<anonymous closure> (package:flutter/src/scheduler/binding.dart:749:7)
flutter: #124    _Timer._runTimers (dart:isolate/runtime/libtimer_impl.dart:382:19)
flutter: #125    _Timer._handleMessage (dart:isolate/runtime/libtimer_impl.dart:416:5)
flutter: #126    _RawReceivePortImpl._handleMessage (dart:isolate/runtime/libisolate_patch.dart:171:12)
flutter: (elided 3 frames from class _AssertionError and package dart:async)
flutter:
flutter: The following RenderObject was being processed when the exception was fired:
flutter:   _RenderDecoration#10671 NEEDS-LAYOUT NEEDS-PAINT
flutter:   creator: _Decorator ← InputDecorator ← AnimatedBuilder ← Listener ← RawGestureDetector ←
flutter:   GestureDetector ← TextSelectionGestureDetector ← IgnorePointer ← Semantics ← TextField ←
flutter:   TextEditorForPhoneVerify ← Padding ← ⋯
flutter:   parentData: <none> (can use size)
flutter:   constraints: BoxConstraints(w=28.0, h=56.0)
flutter:   size: Size(28.0, 56.0)
flutter: This RenderObject had the following descendants (showing up to depth 5):
flutter:   RenderRepaintBoundary#9838d relayoutBoundary=up1 NEEDS-LAYOUT NEEDS-PAINT
flutter:     RenderPointerListener#95bb3 relayoutBoundary=up2 NEEDS-LAYOUT NEEDS-PAINT
flutter:       RenderSemanticsAnnotations#1d581 relayoutBoundary=up3 NEEDS-LAYOUT NEEDS-PAINT
flutter:         RenderIgnorePointer#7b37c relayoutBoundary=up4 NEEDS-LAYOUT NEEDS-PAINT
flutter:           RenderLeaderLayer#d035d relayoutBoundary=up5 NEEDS-LAYOUT NEEDS-PAINT
flutter:   RenderAnimatedOpacity#5b708 relayoutBoundary=up1 NEEDS-PAINT
flutter:     RenderParagraph#62bf0 relayoutBoundary=up2 NEEDS-PAINT
flutter:   RenderConstrainedBox#fb712 relayoutBoundary=up1 NEEDS-LAYOUT NEEDS-PAINT
flutter:   RenderCustomPaint#7c081 NEEDS-LAYOUT NEEDS-PAINT
flutter: ════════════════════════════════════════════════════════════════════════════════════════════════════
flutter: Another exception was thrown: Please see the documentation for computeDistanceToActualBaseline for the required calling conventions of this method.
flutter: Another exception was thrown: Please see the documentation for computeDistanceToActualBaseline for the required calling conventions of this method.
flutter: Another exception was thrown: Please see the documentation for computeDistanceToActualBaseline for the required calling conventions of this method.
flutter: Another exception was thrown: Please see the documentation for computeDistanceToActualBaseline for the required calling conventions of this method.
flutter: Another exception was thrown: Please see the documentation for computeDistanceToActualBaseline for the required calling conventions of this method.
flutter: Another exception was thrown: Please see the documentation for computeDistanceToActualBaseline for the required calling conventions of this method.
flutter: Another exception was thrown: Please see the documentation for computeDistanceToActualBaseline for the required calling conventions of this method.

另外,我也更感兴趣:只要输入数字,光标就会自动转到下一个数字,甚至无需按键盘上的任何键。正如您在大多数验证码布局中看到的那样。

请帮忙,因为我已经尝试过我的水平达到一个,但无法得到想要的结果。谢谢

【问题讨论】:

    标签: flutter uitextfield


    【解决方案1】:
    Scaffold(
      body: Padding(
        padding: const EdgeInsets.all(30.0),
        child:  Wrap(
          alignment: WrapAlignment.start,
          spacing: 4,
          direction: Axis.horizontal,
          runSpacing: 10,
          children: [
            _otpTextField(context, true),
            _otpTextField(context, false),
            _otpTextField(context, false),
            _otpTextField(context, false),
            _otpTextField(context, false),
            _otpTextField(context, false),
          ],
        ),
      ),
    );
    
    Widget _otpTextField(BuildContext context, bool autoFocus) {
     return  Container(
      height: MediaQuery.of(context).size.shortestSide * 0.13,
      decoration: BoxDecoration(
        border: Border.all(color: Colors.grey),
        borderRadius: BorderRadius.circular(5),
        color: Colors.white,
        shape: BoxShape.rectangle,
      ),
      child: AspectRatio(
        aspectRatio: 1,
        child: TextField(
          autofocus: autoFocus,
          decoration: InputDecoration(
            border: InputBorder.none,
          ),
          textAlign: TextAlign.center,
          keyboardType: TextInputType.number,
          style: TextStyle(),
          maxLines: 1,
          onChanged: (value) {
            if(value.length == 1) {
              FocusScope.of(context).nextFocus();
            }
          },
        ),
      ),
    );
    }
    

    【讨论】:

      【解决方案2】:

      我知道现在回答为时已晚,但我测试了不同的包和不同的答案,比如这个 package 没有 readOnly 属性,而且当我们插入或删除文本时,有些答案没有自动对焦来自TextField,但对我来说,下面的代码工作正常。

      import 'package:flutter/material.dart';
      
      import 'const/mSize.dart';
      
      class TestFile extends StatefulWidget {
        @override
        _TestFileState createState() => _TestFileState();
      }
      
      class _TestFileState extends State<TestFile> {
        FocusNode _focusDigit1 = FocusNode();
        FocusNode _focusDigit2 = FocusNode();
        FocusNode _focusDigit3 = FocusNode();
        FocusNode _focusDigit4 = FocusNode();
        FocusNode _focusDigit5 = FocusNode();
        FocusNode _focusDigit6 = FocusNode();
      
        @override
        void dispose() {
          // TODO: implement dispose
          super.dispose();
          _focusDigit1.dispose();
          _focusDigit2.dispose();
          _focusDigit3.dispose();
          _focusDigit4.dispose();
          _focusDigit5.dispose();
          _focusDigit6.dispose();
        }
      
        @override
        Widget build(BuildContext context) {
          return Scaffold(
            body: Padding(
              padding: EdgeInsets.symmetric(
                horizontal: mediaQueryData(context).size.width * 0.15,
              ),
              child: Container(
                margin: EdgeInsets.only(top: 100),
                child: Row(
                  children: [
                    CodeInput(
                      focusNode0: _focusDigit5,
                      focusNode1: _focusDigit6,
                      focusNode2: null,
                    ),
                    SizedBox(
                      width: mediaQueryData(context).size.width * 0.063,
                    ),
                    CodeInput(
                      focusNode0: _focusDigit4,
                      focusNode1: _focusDigit5,
                      focusNode2: _focusDigit6,
                    ),
                    SizedBox(
                      width: mediaQueryData(context).size.width * 0.063,
                    ),
                    CodeInput(
                      focusNode0: _focusDigit3,
                      focusNode1: _focusDigit4,
                      focusNode2: _focusDigit5,
                    ),
                    SizedBox(
                      width: mediaQueryData(context).size.width * 0.063,
                    ),
                    CodeInput(
                      focusNode0: _focusDigit2,
                      focusNode1: _focusDigit3,
                      focusNode2: _focusDigit4,
                    ),
                    SizedBox(
                      width: mediaQueryData(context).size.width * 0.063,
                    ),
                    CodeInput(
                      focusNode0: _focusDigit1,
                      focusNode1: _focusDigit2,
                      focusNode2: _focusDigit3,
                    ),
                    SizedBox(
                      width: mediaQueryData(context).size.width * 0.063,
                    ),
                    CodeInput(
                      focusNode0: null,
                      focusNode1: _focusDigit1,
                      focusNode2: _focusDigit2,
                    ),
                  ],
                ),
              ),
            ),
          );
        }
      }
      
      class CodeInput extends StatelessWidget {
        final FocusNode focusNode0;
        final FocusNode focusNode1;
        final FocusNode focusNode2;
      
        const CodeInput({
          Key key,
          this.focusNode0,
          this.focusNode1,
          this.focusNode2,
        }) : super(key: key);
      
        @override
        Widget build(BuildContext context) {
          return Row(
            children: [
              SizedBox(
                width: mediaQueryData(context).size.width * 0.063,
                child: TextField(
                  focusNode: focusNode1,
                  textAlign: TextAlign.center,
                  maxLength: 1,
                  onChanged: (str) {
                    if (str.length == 1) {
                      FocusScope.of(context).requestFocus(focusNode2);
                    } else if (str.length == 0) {
                      FocusScope.of(context).requestFocus(focusNode0);
                    }
                  },
                  decoration: InputDecoration(
                    hintText: "*",
                    hintStyle: TextStyle(color: Colors.grey),
                    counterText: "",
                  ),
                ),
              ),
            ],
          );
        }
      }
      

      【讨论】:

        【解决方案3】:
        class EnterOTP extends StatelessWidget {
          @override
          Widget build(BuildContext context) {
            return Material(
              color: Colors.transparent,
              child: Container(
                padding: EdgeInsets.symmetric(horizontal: 20),
                child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [
                  Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: [
                      OTPDigitTextFieldBox(first: true, last: false),
                      OTPDigitTextFieldBox(first: false, last: false),
                      OTPDigitTextFieldBox(first: false, last: false),
                      OTPDigitTextFieldBox(first: false, last: true),
                    ],
                  )
                ]),
              ),
            );
          }
        }
            
            class OTPDigitTextFieldBox extends StatelessWidget {
              final bool first;
              final bool last;
              const OTPDigitTextFieldBox(
                  {Key key, @required this.first, @required this.last})
                  : super(key: key);
            
              @override
              Widget build(BuildContext context) {
                return Container(
                  height: 85,
                  child: AspectRatio(
                    aspectRatio: 1.0,
                    child: TextField(
                      autofocus: true,
                      onChanged: (value) {
                        if (value.length == 1 && last == false) {
                          FocusScope.of(context).nextFocus();
                        }
                        if (value.length == 0 && first == false) {
                          FocusScope.of(context).previousFocus();
                        }
                      },
                      showCursor: false,
                      readOnly: false,
                      textAlign: TextAlign.center,
                      style: MyStyles.inputTextStyle,
                      keyboardType: TextInputType.number,
                      maxLength: 1,
                      decoration: InputDecoration(
                        // contentPadding: EdgeInsets.all(0),
                        counter: Offstage(),
                        enabledBorder: OutlineInputBorder(
                            borderSide: BorderSide(width: 2, color: primaryColor),
                            borderRadius: BorderRadius.circular(10)),
                        focusedBorder: OutlineInputBorder(
                            borderSide: BorderSide(width: 2, color: primaryColor),
                            borderRadius: BorderRadius.circular(10)),
                        hintText: "*",
                        hintStyle: MyStyles.hintTextStyle,
                      ),
                    ),
                  ),
                );
              }
            }
        

        【讨论】:

        • 请添加此代码作用的描述。只有代码没有写出来的代码描述那么有意义。
        • 这不是一个有效的代码片段。它仍然为定制的文本框提供了一个总体思路。谢谢
        • @SwissCodeMen 我添加了描述/摘要。
        • 因为你有这个 MyStyles 类..但是你没有把这个类放在这里
        【解决方案4】:

        要自动将焦点转移到下一个字段,TextFormField 上的简单 onChanged 就可以了

        onChanged: (str) {
          if (str.length == 1) {
             FocusScope.of(context).requestFocus(_nextFocusField);
          }  
        }
        

        【讨论】:

        • 这对我不起作用,直到我添加了textInputAction: TextInputAction.go,
        【解决方案5】:

        您可以使用 PinCodeTextField https://pub.dev/packages/pin_code_fields

        您可以使用不同的形状和动画,也可以处理删除中间文本时出现的问题。

        【讨论】:

        • 从长远来看,使用大量软件包可能会给维护带来困难。我建议在某些事情真正需要您时使用软件包,例如 Firebase 功能、intl funcs。
        【解决方案6】:

        使用pin_input_text_field

        这个库是专门为这样的文本字段设计的。它有一个 decoration 属性用于自定义框。

        【讨论】:

          【解决方案7】:

          我已经制作了自己的 UI,如果您喜欢,请使用它,或者您可以根据自己的需要进行自定义

          import 'dart:async';
          
          import 'package:flutter/cupertino.dart';
          import 'package:flutter/foundation.dart';
          import 'package:flutter/material.dart';
          
          class Otp extends StatefulWidget {
            final String email;
            final String newEmail;
            final bool isGuestCheckOut;
          
            const Otp({
              Key key,
              @required this.email,
              this.newEmail = "",
              this.isGuestCheckOut,
            }) : super(key: key);
          
            @override
            _OtpState createState() => new _OtpState();
          }
          
          class _OtpState extends State<Otp> with SingleTickerProviderStateMixin {
            // Constants
            final int time = 30;
            AnimationController _controller;
          
            // Variables
            Size _screenSize;
            int _currentDigit;
            int _firstDigit;
            int _secondDigit;
            int _thirdDigit;
            int _fourthDigit;
          
            Timer timer;
            int totalTimeInSeconds;
            bool _hideResendButton;
          
            String userName = "";
            bool didReadNotifications = false;
            int unReadNotificationsCount = 0;
          
            // Returns "Appbar"
            get _getAppbar {
              return new AppBar(
                backgroundColor: Colors.transparent,
                elevation: 0.0,
                leading: new InkWell(
                  borderRadius: BorderRadius.circular(30.0),
                  child: new Icon(
                    Icons.arrow_back,
                    color: Colors.black54,
                  ),
                  onTap: () {
                    Navigator.pop(context);
                  },
                ),
                centerTitle: true,
              );
            }
          
            // Return "Verification Code" label
            get _getVerificationCodeLabel {
              return new Text(
                "Verification Code",
                textAlign: TextAlign.center,
                style: new TextStyle(
                    fontSize: 28.0, color: Colors.black, fontWeight: FontWeight.bold),
              );
            }
          
            // Return "Email" label
            get _getEmailLabel {
              return new Text(
                "Please enter the OTP sent\non your registered Email ID.",
                textAlign: TextAlign.center,
                style: new TextStyle(
                    fontSize: 18.0, color: Colors.black, fontWeight: FontWeight.w600),
              );
            }
          
            // Return "OTP" input field
            get _getInputField {
              return new Row(
                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                children: <Widget>[
                  _otpTextField(_firstDigit),
                  _otpTextField(_secondDigit),
                  _otpTextField(_thirdDigit),
                  _otpTextField(_fourthDigit),
                ],
              );
            }
          
            // Returns "OTP" input part
            get _getInputPart {
              return new Column(
                mainAxisSize: MainAxisSize.max,
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: <Widget>[
                  _getVerificationCodeLabel,
                  _getEmailLabel,
                  _getInputField,
                  _hideResendButton ? _getTimerText : _getResendButton,
                  _getOtpKeyboard
                ],
              );
            }
          
            // Returns "Timer" label
            get _getTimerText {
              return Container(
                height: 32,
                child: new Offstage(
                  offstage: !_hideResendButton,
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: <Widget>[
                      new Icon(Icons.access_time),
                      new SizedBox(
                        width: 5.0,
                      ),
                      OtpTimer(_controller, 15.0, Colors.black)
                    ],
                  ),
                ),
              );
            }
          
            // Returns "Resend" button
            get _getResendButton {
              return new InkWell(
                child: new Container(
                  height: 32,
                  width: 120,
                  decoration: BoxDecoration(
                      color: Colors.black,
                      shape: BoxShape.rectangle,
                      borderRadius: BorderRadius.circular(32)),
                  alignment: Alignment.center,
                  child: new Text(
                    "Resend OTP",
                    style:
                        new TextStyle(fontWeight: FontWeight.bold, color: Colors.white),
                  ),
                ),
                onTap: () {
                  // Resend you OTP via API or anything
                },
              );
            }
          
            // Returns "Otp" keyboard
            get _getOtpKeyboard {
              return new Container(
                  height: _screenSize.width - 80,
                  child: new Column(
                    children: <Widget>[
                      new Expanded(
                        child: new Row(
                          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                          children: <Widget>[
                            _otpKeyboardInputButton(
                                label: "1",
                                onPressed: () {
                                  _setCurrentDigit(1);
                                }),
                            _otpKeyboardInputButton(
                                label: "2",
                                onPressed: () {
                                  _setCurrentDigit(2);
                                }),
                            _otpKeyboardInputButton(
                                label: "3",
                                onPressed: () {
                                  _setCurrentDigit(3);
                                }),
                          ],
                        ),
                      ),
                      new Expanded(
                        child: new Row(
                          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                          children: <Widget>[
                            _otpKeyboardInputButton(
                                label: "4",
                                onPressed: () {
                                  _setCurrentDigit(4);
                                }),
                            _otpKeyboardInputButton(
                                label: "5",
                                onPressed: () {
                                  _setCurrentDigit(5);
                                }),
                            _otpKeyboardInputButton(
                                label: "6",
                                onPressed: () {
                                  _setCurrentDigit(6);
                                }),
                          ],
                        ),
                      ),
                      new Expanded(
                        child: new Row(
                          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                          children: <Widget>[
                            _otpKeyboardInputButton(
                                label: "7",
                                onPressed: () {
                                  _setCurrentDigit(7);
                                }),
                            _otpKeyboardInputButton(
                                label: "8",
                                onPressed: () {
                                  _setCurrentDigit(8);
                                }),
                            _otpKeyboardInputButton(
                                label: "9",
                                onPressed: () {
                                  _setCurrentDigit(9);
                                }),
                          ],
                        ),
                      ),
                      new Expanded(
                        child: new Row(
                          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                          children: <Widget>[
                            new SizedBox(
                              width: 80.0,
                            ),
                            _otpKeyboardInputButton(
                                label: "0",
                                onPressed: () {
                                  _setCurrentDigit(0);
                                }),
                            _otpKeyboardActionButton(
                                label: new Icon(
                                  Icons.backspace,
                                  color: Colors.black,
                                ),
                                onPressed: () {
                                  setState(() {
                                    if (_fourthDigit != null) {
                                      _fourthDigit = null;
                                    } else if (_thirdDigit != null) {
                                      _thirdDigit = null;
                                    } else if (_secondDigit != null) {
                                      _secondDigit = null;
                                    } else if (_firstDigit != null) {
                                      _firstDigit = null;
                                    }
                                  });
                                }),
                          ],
                        ),
                      ),
                    ],
                  ));
            }
          
            // Overridden methods
            @override
            void initState() {
              totalTimeInSeconds = time;
              super.initState();
              _controller =
                  AnimationController(vsync: this, duration: Duration(seconds: time))
                    ..addStatusListener((status) {
                      if (status == AnimationStatus.dismissed) {
                        setState(() {
                          _hideResendButton = !_hideResendButton;
                        });
                      }
                    });
              _controller.reverse(
                  from: _controller.value == 0.0 ? 1.0 : _controller.value);
              _startCountdown();
            }
          
            @override
            void dispose() {
              _controller.dispose();
              super.dispose();
            }
          
            @override
            Widget build(BuildContext context) {
              _screenSize = MediaQuery.of(context).size;
              return new Scaffold(
                appBar: _getAppbar,
                backgroundColor: Colors.white,
                body: new Container(
                  width: _screenSize.width,
          //        padding: new EdgeInsets.only(bottom: 16.0),
                  child: _getInputPart,
                ),
              );
            }
          
            // Returns "Otp custom text field"
            Widget _otpTextField(int digit) {
              return new Container(
                width: 35.0,
                height: 45.0,
                alignment: Alignment.center,
                child: new Text(
                  digit != null ? digit.toString() : "",
                  style: new TextStyle(
                    fontSize: 30.0,
                    color: Colors.black,
                  ),
                ),
                decoration: BoxDecoration(
          //            color: Colors.grey.withOpacity(0.4),
                    border: Border(
                        bottom: BorderSide(
                  width: 2.0,
                  color: Colors.black,
                ))),
              );
            }
          
            // Returns "Otp keyboard input Button"
            Widget _otpKeyboardInputButton({String label, VoidCallback onPressed}) {
              return new Material(
                color: Colors.transparent,
                child: new InkWell(
                  onTap: onPressed,
                  borderRadius: new BorderRadius.circular(40.0),
                  child: new Container(
                    height: 80.0,
                    width: 80.0,
                    decoration: new BoxDecoration(
                      shape: BoxShape.circle,
                    ),
                    child: new Center(
                      child: new Text(
                        label,
                        style: new TextStyle(
                          fontSize: 30.0,
                          color: Colors.black,
                        ),
                      ),
                    ),
                  ),
                ),
              );
            }
          
            // Returns "Otp keyboard action Button"
            _otpKeyboardActionButton({Widget label, VoidCallback onPressed}) {
              return new InkWell(
                onTap: onPressed,
                borderRadius: new BorderRadius.circular(40.0),
                child: new Container(
                  height: 80.0,
                  width: 80.0,
                  decoration: new BoxDecoration(
                    shape: BoxShape.circle,
                  ),
                  child: new Center(
                    child: label,
                  ),
                ),
              );
            }
          
            // Current digit
            void _setCurrentDigit(int i) {
              setState(() {
                _currentDigit = i;
                if (_firstDigit == null) {
                  _firstDigit = _currentDigit;
                } else if (_secondDigit == null) {
                  _secondDigit = _currentDigit;
                } else if (_thirdDigit == null) {
                  _thirdDigit = _currentDigit;
                } else if (_fourthDigit == null) {
                  _fourthDigit = _currentDigit;
          
                  var otp = _firstDigit.toString() +
                      _secondDigit.toString() +
                      _thirdDigit.toString() +
                      _fourthDigit.toString();
          
                  // Verify your otp by here. API call
                }
              });
            }
          
            Future<Null> _startCountdown() async {
              setState(() {
                _hideResendButton = true;
                totalTimeInSeconds = time;
              });
              _controller.reverse(
                  from: _controller.value == 0.0 ? 1.0 : _controller.value);
            }
          
            void clearOtp() {
              _fourthDigit = null;
              _thirdDigit = null;
              _secondDigit = null;
              _firstDigit = null;
              setState(() {});
            }
          }
          
          class OtpTimer extends StatelessWidget {
            final AnimationController controller;
            double fontSize;
            Color timeColor = Colors.black;
          
            OtpTimer(this.controller, this.fontSize, this.timeColor);
          
            String get timerString {
              Duration duration = controller.duration * controller.value;
              if (duration.inHours > 0) {
                return '${duration.inHours}:${duration.inMinutes % 60}:${(duration.inSeconds % 60).toString().padLeft(2, '0')}';
              }
              return '${duration.inMinutes % 60}:${(duration.inSeconds % 60).toString().padLeft(2, '0')}';
            }
          
            Duration get duration {
              Duration duration = controller.duration;
              return duration;
            }
          
            @override
            Widget build(BuildContext context) {
              return AnimatedBuilder(
                  animation: controller,
                  builder: (BuildContext context, Widget child) {
                    return new Text(
                      timerString,
                      style: new TextStyle(
                          fontSize: fontSize,
                          color: timeColor,
                          fontWeight: FontWeight.w600),
                    );
                  });
            }
          }
          

          【讨论】:

          • 感谢您的输入,但我可以轻松完成上述设计。我主要关心的是实现我在我的问题中提出的内容。谢谢,但这不是我要找的。​​span>
          • 不,整个 UI 与 Lakhwinder 不同。我不是在寻找那个。谢谢
          • 这不是关于 UI,而是关于你需要的功能,UI,你可以根据你的要求进行更改
          • 我可以,但我已经尝试并收到此错误。我不能盲目地遵循代码。为什么我提出了一个问题,因为我无法让我的 UI 变得像我必须得到的那样
          • 这是你的电话,使用与否,至少你可以得到一个想法,如何实现你想要的。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-10-19
          • 2021-02-27
          • 1970-01-01
          • 2015-12-22
          相关资源
          最近更新 更多