抖动中的步进器输入和数据问题

时间:2019-12-16 17:02:03

标签: flutter dart

我们在抖动中使用步进器,并且在我们尝试实现的示例中看到了奇怪的数据问题。当您输入“名字”文本框时,它不会立即输入,您必须执行多次,并且“名字”文本区域中也会显示该名字。非常奇怪的行为,我不确定我们何时发现此示例,也许不是一个好例子:)

import 'package:flutter/material.dart';
import 'package:validators/validators.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'dart:async';
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:lightbridge_mobile/models/user_step1_model .dart';
import 'package:lightbridge_mobile/screens/member/profile/step2.dart';
import 'package:lightbridge_mobile/models/user.dart';



class ProfileStep1 extends StatefulWidget {
  final User user;

  const ProfileStep1({Key key, this.user}) : super(key: key);
  @override
  State<StatefulWidget> createState() {
return new MyAppScreenMode(user: user);
 }
}

class MyData {
  String firstname = '';
  String lastname = '';
  String phone = '';
  String email = '';

  }

class MyAppScreenMode extends State<ProfileStep1> {
  final User user;

  MyAppScreenMode({@required this.user});
  @override
  Widget build(BuildContext context) {
   return new MaterialApp(
    theme: new ThemeData(
      primarySwatch: Colors.blueGrey
    ),
    home: new Scaffold(
      appBar: new AppBar(
        backgroundColor: const Color.fromRGBO(1,89,99, 1.0),
        title:  Container(child: Row(children: <Widget>[
          Icon(
                     FontAwesomeIcons.userPlus,
                     size: 25.0,
                     color: Colors.white,

             ),
           new Text('   Create Account : Step 1 of 5'),
        ],
        ),
        ),

        ),

         body: Container(
        child: StepperBody(user: user),
        decoration: BoxDecoration(
        gradient: new LinearGradient(
            colors: [Color.fromRGBO(1,89,99, 1.0),Color.fromRGBO(1,89,99, 1.0),],
            begin: Alignment.bottomLeft,
            end: Alignment.topRight
        )
    ),
    )
    )
    );
 }
}

    class StepperBody extends StatefulWidget {
     final User user;
     const StepperBody({Key key,@required this.user}) : super(key: key);
     @override
    _StepperBodyState createState() => new _StepperBodyState();
 }

 class _StepperBodyState extends State<StepperBody> {
 int currStep = 0;
 static var _focusNode = new FocusNode();
  GlobalKey<FormState> _formKey = new GlobalKey<FormState>();
  static MyData data = new MyData();



  @override
  void initState() {
    super.initState();
    _focusNode.addListener(() {
      setState(() {});
      print('Has focus: $_focusNode.hasFocus');
    });
  }

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

   List<Step> steps = [
    new Step(
       title: const Text('First Name', style: TextStyle( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 19.0 )),

       isActive: true,

         state: StepState.indexed,
       content: new TextFormField(
         focusNode: _focusNode,
       keyboardType: TextInputType.text,
      autocorrect: false,
      onSaved: (String fnvalue) {
        data.firstname = fnvalue;
      },
      maxLines: 1,
      validator: (fnvalue) {
        if (fnvalue.isEmpty || fnvalue.length < 1) {
          return 'Please enter first name';
        }
      },
      decoration: new InputDecoration(
          labelText: 'Enter your first name',
          icon: const Icon(Icons.person, color: Colors.white),
          labelStyle:
              new TextStyle(decorationStyle: TextDecorationStyle.solid,color: Colors.white, fontSize: 16.0))
              ),
       ),

    new Step(
    title: const Text('Last Name', style: TextStyle( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 19.0 )),   
    isActive: false,
    state: StepState.indexed,
    content: new TextFormField(
      focusNode: _focusNode,
      keyboardType: TextInputType.text,
      autocorrect: false,
      onSaved: (String lnvalue) {
        data.lastname = lnvalue;
      },
      maxLines: 1,
      validator: (lnvalue) {
        if (lnvalue.isEmpty || lnvalue.length < 1) {
          return 'Please enter last name';
        }
      },
      decoration: new InputDecoration(
          labelText: 'Enter your last name',
          icon: const Icon(Icons.person, color: Colors.white),
          labelStyle:
              new TextStyle(decorationStyle: TextDecorationStyle.solid)),
    )),
new Step(
    title: const Text('Phone',style: TextStyle( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 19.0 )),
    //subtitle: const Text('Subtitle'),
    isActive: false,
    //state: StepState.editing,
    state: StepState.indexed,
    content: new TextFormField(
      keyboardType: TextInputType.phone,
      autocorrect: false,
      validator: (value) {
        if (value.isEmpty || value.length < 10) {
          return 'Please enter valid number';
        }
      },
      onSaved: (String value) {
        data.phone = value;
      },
      maxLines: 1,
      decoration: new InputDecoration(
          labelText: 'Enter your number',
          icon: const Icon(Icons.phone, color: Colors.white),
          labelStyle:
              new TextStyle(decorationStyle: TextDecorationStyle.solid, color: Colors.white, fontSize: 16.0)),
    )),
new Step(
    title: const Text('Email', style: TextStyle( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 19.0 )),
    // subtitle: const Text('Subtitle'),
    isActive: false,
    state: StepState.indexed,
    // state: StepState.disabled,
    content: new TextFormField(
      keyboardType: TextInputType.emailAddress,
      style: new TextStyle(color: Colors.white),
      autocorrect: false,
      validator: (value) {
        if (value.isEmpty || !value.contains('@')) {
          return 'Please enter valid email';
        }
      },
      onSaved: (String value) {
        data.email = value;
      },
      maxLines: 1,
      decoration: new InputDecoration(
          labelText: 'Enter your email',
          hintText: 'Enter a email address',
          icon: const Icon(Icons.email, color: Colors.white),
          labelStyle:
              new TextStyle(decorationStyle: TextDecorationStyle.solid, color: Colors.white, fontSize: 16.0))),
    ),

  ];

  @override
  Widget build(BuildContext context) {
    void showSnackBarMessage(String message,
       [MaterialColor color = Colors.red]) {
      Scaffold
        .of(context)
        .showSnackBar(new SnackBar(content: new Text(message)));
   }

    void _submitDetails() {
     final FormState formState = _formKey.currentState;

     if (!formState.validate()) {
       showSnackBarMessage('Please enter correct data');
     } else {
    formState.save();
    // HERE
    insertUserStep1(data.firstname, data.lastname, data.email, data.phone);

  }
}

return new Container(
    child: new Form(
  key: _formKey,
  child: new ListView(children: <Widget>[
    new Stepper(
      steps: steps,
      type: StepperType.vertical,
      currentStep: this.currStep,
      onStepContinue: () {
        setState(() {
          if (currStep < steps.length - 1) {
            currStep = currStep + 1;
          } else {
            currStep = 0;
          }
          // else {
          // Scaffold
          //     .of(context)
          //     .showSnackBar(new SnackBar(content: new Text('$currStep')));

          // if (currStep == 1) {
          //   print('First Step');
          //   print('object' + FocusScope.of(context).toStringDeep());
          // }

          // }
        });
      },
      onStepCancel: () {
        setState(() {
          if (currStep > 0) {
            currStep = currStep - 1;
          } else {
            currStep = 0;
          }
        });
      },
      onStepTapped: (step) {
        setState(() {
          currStep = step;
        });
      },
    ),

      Container(
            margin: EdgeInsets.all(10.0),
       child: OutlineButton(
             child: Text('Tap to Continue'), textColor: Colors.white,
          shape: new RoundedRectangleBorder(borderRadius: new BorderRadius.circular(30.0)),
            onPressed: _submitDetails,

            )
            //  Navigator.of(context).push(new MaterialPageRoute(builder: (BuildContext context) => new ProfileStep1()));
        ),
   ] ),







));

}

  Future<void> insertUserStep1(String firstname, String lastname, String email, String cell ) async 
   {
      final response =
     await http.post('http://url/api/UserStep1',
      headers: {"Content-Type": "application/json", 
             'Accept': 'application/json',},
  body: json.encode({'firstname' : firstname,'lastname' : lastname ,  'email' : email, 'cell': cell}));

  if (response.statusCode == 200) {
  // If the call to the server was successful, parse the JSON
UserStep1Model _user;
    _user = UserStep1Model.fromJson(json.decode(response.body));
  Navigator.of(context).push(new MaterialPageRoute(builder: (BuildContext context) => new ProfileStep2(userID: _user.userId)));

 } else {
// If that call was not successful, throw an error.
throw Exception('Failed to load user');
   }
}
}

1 个答案:

答案 0 :(得分:0)

您可以让名字TextFormField和姓氏TextFormField使用不同的focusNode
代码段

content: new TextFormField(
          focusNode: _focusNode,
          keyboardType: TextInputType.text,

content: new TextFormField(
          focusNode: _focusNodeLastName,
          keyboardType: TextInputType.text,

工作演示

enter image description here 完整的测试代码

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

void main() => runApp(MyApp());

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: ProfileStep1(user: User()),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

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

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.display1,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

class ProfileStep1 extends StatefulWidget {
  final User user;

  const ProfileStep1({Key key, this.user}) : super(key: key);
  @override
  State<StatefulWidget> createState() {
    return new MyAppScreenMode(user: user);
  }
}

class User {}

class MyData {
  String firstname = '';
  String lastname = '';
  String phone = '';
  String email = '';
}

class MyAppScreenMode extends State<ProfileStep1> {
  final User user;

  MyAppScreenMode({@required this.user});
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
        theme: new ThemeData(primarySwatch: Colors.blueGrey),
        home: new Scaffold(
            appBar: new AppBar(
              backgroundColor: const Color.fromRGBO(1, 89, 99, 1.0),
              title: Container(
                child: Row(
                  children: <Widget>[
                    Icon(
                      FontAwesomeIcons.userPlus,
                      size: 25.0,
                      color: Colors.white,
                    ),
                    new Text('   Create Account : Step 1 of 5'),
                  ],
                ),
              ),
            ),
            body: Container(
              child: StepperBody(user: user),
              decoration: BoxDecoration(
                  gradient: new LinearGradient(colors: [
                Color.fromRGBO(1, 89, 99, 1.0),
                Color.fromRGBO(1, 89, 99, 1.0),
              ], begin: Alignment.bottomLeft, end: Alignment.topRight)),
            )));
  }
}

class StepperBody extends StatefulWidget {
  final User user;
  const StepperBody({Key key, @required this.user}) : super(key: key);
  @override
  _StepperBodyState createState() => new _StepperBodyState();
}

class _StepperBodyState extends State<StepperBody> {
  int currStep = 0;
  static var _focusNode = new FocusNode();
  static var _focusNodeLastName = new FocusNode();
  GlobalKey<FormState> _formKey = new GlobalKey<FormState>();
  static MyData data = new MyData();

  @override
  void initState() {
    super.initState();
    _focusNode.addListener(() {
      setState(() {});
      print('Has focus: $_focusNode.hasFocus');
    });

    _focusNodeLastName.addListener(() {
      setState(() {});
      print('Has focus: $_focusNode.hasFocus');
    });
  }

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

  List<Step> steps = [
    new Step(
      title: const Text('First Name',
          style: TextStyle(
              color: Colors.white,
              fontWeight: FontWeight.bold,
              fontSize: 19.0)),
      isActive: true,
      state: StepState.indexed,
      content: new TextFormField(
          focusNode: _focusNode,
          keyboardType: TextInputType.text,
          autocorrect: false,
          onSaved: (String fnvalue) {
            data.firstname = fnvalue;
          },
          maxLines: 1,
          validator: (fnvalue) {
            if (fnvalue.isEmpty || fnvalue.length < 1) {
              return 'Please enter first name';
            }
          },
          decoration: new InputDecoration(
              labelText: 'Enter your first name',
              icon: const Icon(Icons.person, color: Colors.white),
              labelStyle: new TextStyle(
                  decorationStyle: TextDecorationStyle.solid,
                  color: Colors.white,
                  fontSize: 16.0))),
    ),
    new Step(
        title: const Text('Last Name',
            style: TextStyle(
                color: Colors.white,
                fontWeight: FontWeight.bold,
                fontSize: 19.0)),
        isActive: false,
        state: StepState.indexed,
        content: new TextFormField(
          focusNode: _focusNodeLastName,
          keyboardType: TextInputType.text,
          autocorrect: false,
          onSaved: (String lnvalue) {
            data.lastname = lnvalue;
          },
          maxLines: 1,
          validator: (lnvalue) {
            if (lnvalue.isEmpty || lnvalue.length < 1) {
              return 'Please enter last name';
            }
          },
          decoration: new InputDecoration(
              labelText: 'Enter your last name',
              icon: const Icon(Icons.person, color: Colors.white),
              labelStyle:
                  new TextStyle(decorationStyle: TextDecorationStyle.solid)),
        )),
    new Step(
        title: const Text('Phone',
            style: TextStyle(
                color: Colors.white,
                fontWeight: FontWeight.bold,
                fontSize: 19.0)),
        //subtitle: const Text('Subtitle'),
        isActive: false,
        //state: StepState.editing,
        state: StepState.indexed,
        content: new TextFormField(
          keyboardType: TextInputType.phone,
          autocorrect: false,
          validator: (value) {
            if (value.isEmpty || value.length < 10) {
              return 'Please enter valid number';
            }
          },
          onSaved: (String value) {
            data.phone = value;
          },
          maxLines: 1,
          decoration: new InputDecoration(
              labelText: 'Enter your number',
              icon: const Icon(Icons.phone, color: Colors.white),
              labelStyle: new TextStyle(
                  decorationStyle: TextDecorationStyle.solid,
                  color: Colors.white,
                  fontSize: 16.0)),
        )),
    new Step(
      title: const Text('Email',
          style: TextStyle(
              color: Colors.white,
              fontWeight: FontWeight.bold,
              fontSize: 19.0)),
      // subtitle: const Text('Subtitle'),
      isActive: false,
      state: StepState.indexed,
      // state: StepState.disabled,
      content: new TextFormField(
          keyboardType: TextInputType.emailAddress,
          style: new TextStyle(color: Colors.white),
          autocorrect: false,
          validator: (value) {
            if (value.isEmpty || !value.contains('@')) {
              return 'Please enter valid email';
            }
          },
          onSaved: (String value) {
            data.email = value;
          },
          maxLines: 1,
          decoration: new InputDecoration(
              labelText: 'Enter your email',
              hintText: 'Enter a email address',
              icon: const Icon(Icons.email, color: Colors.white),
              labelStyle: new TextStyle(
                  decorationStyle: TextDecorationStyle.solid,
                  color: Colors.white,
                  fontSize: 16.0))),
    ),
  ];

  @override
  Widget build(BuildContext context) {
    void showSnackBarMessage(String message,
        [MaterialColor color = Colors.red]) {
      Scaffold.of(context)
          .showSnackBar(new SnackBar(content: new Text(message)));
    }

    void _submitDetails() {
      final FormState formState = _formKey.currentState;

      if (!formState.validate()) {
        showSnackBarMessage('Please enter correct data');
      } else {
        formState.save();
        // HERE
        //insertUserStep1(data.firstname, data.lastname, data.email, data.phone);

      }
    }

    return new Container(
        child: new Form(
      key: _formKey,
      child: new ListView(children: <Widget>[
        new Stepper(
          steps: steps,
          type: StepperType.vertical,
          currentStep: this.currStep,
          onStepContinue: () {
            setState(() {
              if (currStep < steps.length - 1) {
                currStep = currStep + 1;
              } else {
                currStep = 0;
              }
              // else {
              // Scaffold
              //     .of(context)
              //     .showSnackBar(new SnackBar(content: new Text('$currStep')));

              // if (currStep == 1) {
              //   print('First Step');
              //   print('object' + FocusScope.of(context).toStringDeep());
              // }

              // }
            });
          },
          onStepCancel: () {
            setState(() {
              if (currStep > 0) {
                currStep = currStep - 1;
              } else {
                currStep = 0;
              }
            });
          },
          onStepTapped: (step) {
            setState(() {
              currStep = step;
            });
          },
        ),
        Container(
            margin: EdgeInsets.all(10.0),
            child: OutlineButton(
              child: Text('Tap to Continue'),
              textColor: Colors.white,
              shape: new RoundedRectangleBorder(
                  borderRadius: new BorderRadius.circular(30.0)),
              onPressed: _submitDetails,
            )
            //  Navigator.of(context).push(new MaterialPageRoute(builder: (BuildContext context) => new ProfileStep1()));
            ),
      ]),
    ));
  }
}