D/InputConnectionAdaptor(3218):输入方法切换光标监视

发布于 2025-01-23 17:56:23 字数 6366 浏览 3 评论 0原文

这是我在我的auth_screen.dart文件中使用的表单的一部分:该 file:

child: Obx(() => Form(
      key: _formKey,
      child: SingleChildScrollView(
        child: Column(
          children: <Widget>[
            TextFormField(
              decoration: const InputDecoration(labelText: 'E-Mail'),
              keyboardType: TextInputType.emailAddress,
              validator: (value) {
                if (value!.isEmpty || !value.contains('@')) {
                  return 'Invalid email!';
                }
              },
              onSaved: (value) {
                _authData['email'] = value as String;
              },
            ),
            TextFormField(
              decoration: const InputDecoration(labelText: 'Password'),
              obscureText: true,
              controller: _passwordController,
              validator: (value) {
                if (value!.isEmpty || value.length < 5) {
                  return 'Password is too short!';
                }
              },
              onSaved: (value) {
                _authData['password'] = value as String;
              },
            ),

它有两个textformfield用于电子邮件的密码。

另外,相关auth_controller.dart文件如下:

enum AuthMode { Signup, Login }

class AuthController extends GetxController
    with GetSingleTickerProviderStateMixin {
  static AuthController instance = Get.find();
  Rx<dynamic>? authMode = AuthMode.Login.obs;
  RxBool? isLoading = false.obs;
  String? _token;
  DateTime? _expiryDate;
  String? _userId;
  Timer? _authTimer;
  final _isAuth = false.obs;

  AnimationController? controller;
  Animation<Offset>? slideAnimation;
  Animation<double>? opacityAnimation;
  late TextEditingController passwordController;
  final key = GlobalKey<FormState>();

  @override
  void onInit() {
    super.onInit();
    tryAutoLogin();
    controller = AnimationController(
      vsync: this,
      duration: const Duration(
        milliseconds: 300,
      ),
    );
    slideAnimation = Tween<Offset>(
      begin: const Offset(0, -1.5),
      end: const Offset(0, 0),
    ).animate(
      CurvedAnimation(
        parent: controller as Animation<double>,
        curve: Curves.fastOutSlowIn,
      ),
    );
    opacityAnimation = Tween(begin: 0.0, end: 1.0).animate(
      CurvedAnimation(
        parent: controller as Animation<double>,
        curve: Curves.easeIn,
      ),
    );
    // _heightAnimation.addListener(() => setState(() {}));

    passwordController = TextEditingController();
  }

  @override
  void onClose() {
    super.onClose();
    passwordController.dispose();
  }

  bool get isAuth {
    _isAuth.value = token != null;
    return _isAuth.value;
  }

  String? get token {
    if (_expiryDate != null &&
        _expiryDate!.isAfter(DateTime.now()) &&
        _token != null) {
      return _token;
    }
    return null;
  }

  String? get userId {
    return _userId;
  }

  Future<void> _authenticate(
      String email, String password, String urlSegment) async {
    // print('app is here!!!5555');
    // const host = "localhost";
    final host = UniversalPlatform.isAndroid ? '10.0.2.2' : '127.0.0.1';
    final url = Uri.parse('http://$host:8000/api/$urlSegment');

    try {
      final http.Response response = await http.post(
        url,
        headers: {"Content-Type": "application/json"},
        body: json.encode(
          {
            'email': email,
            'password': password,

            //'returnSecureToken': true,
          },
        ),
      );
      // print('this is responsde ' );
      // print(response);

      final responseData = json.decode(response.body);
        print(responseData);

      if (responseData['error'] != null) {
        throw HttpException(responseData['error']['message']);
      } else {
        _token = responseData['idToken'];
        _userId = responseData['id'];
        _expiryDate = DateTime.now().add(
          Duration(
            milliseconds: responseData['expiresIn'],
          ),
        );
      }
      _autoLogout();
      // update();
      final prefs = await SharedPreferences.getInstance();
      final userData = json.encode(
        {
          'token': _token,
          'userId': _userId,
          'expiryDate': _expiryDate!.toIso8601String(),
        },
      );
      prefs.setString('userData', userData);
      isLoading?.value = false;

      // print(prefs.getString('userData'));
      Get.toNamed(rootRoute);
    } catch (error) {
      throw error;
    }
  }

  Future<void> signup(String email, String password) async {
    return _authenticate(email, password, 'signup');
  }

  Future<void> login(String email, String password) async {
    return _authenticate(email, password, 'sessions');
  }

  Future<bool> tryAutoLogin() async {
final prefs = await SharedPreferences.getInstance();
    if (!prefs.containsKey('userData')) {
      return false;
    }
    final Map<String, Object> extractedUserData = Map<String, Object>.from(
        json.decode(prefs.getString('userData') as String));
    final expiryDate =
        DateTime.parse(extractedUserData['expiryDate'] as String);

    if (expiryDate.isBefore(DateTime.now())) {
      return false;
    }
    _token = extractedUserData['token'] as String;
    _userId = extractedUserData['userId'] as String;
    _expiryDate = expiryDate;
     _isAuth.value = true;
    _autoLogout();
    return true;
  }

  Future<void> logout() async {
    _token = null;
    _userId = null;
    _expiryDate = null;
    if (_authTimer != null) {
      _authTimer!.cancel();
      _authTimer = null;
    }
    // update();
    final prefs = await SharedPreferences.getInstance();
    // prefs.remove('userData');
    prefs.clear();
    _isAuth.value = false;
  }

  void _autoLogout() {
    if (_authTimer != null) {
      _authTimer!.cancel();
    }
    final timeToExpiry = _expiryDate!.difference(DateTime.now()).inSeconds;
    _authTimer = Timer(Duration(seconds: timeToExpiry), logout);
  }
}

当我启动应用程序时,它似乎没有错误运行,但是当我单击textformfield s以输入电子邮件或密码,Android模拟器上的虚拟键盘将立即打开并关闭,并且不允许我输入任何内容。它还在调试控制台中显示以下消息:

d/inputConnectionAdaptor(3218):输入方法切换光标 监视

This is a part of form I use inside a card widget on my auth_screen.dart file:

child: Obx(() => Form(
      key: _formKey,
      child: SingleChildScrollView(
        child: Column(
          children: <Widget>[
            TextFormField(
              decoration: const InputDecoration(labelText: 'E-Mail'),
              keyboardType: TextInputType.emailAddress,
              validator: (value) {
                if (value!.isEmpty || !value.contains('@')) {
                  return 'Invalid email!';
                }
              },
              onSaved: (value) {
                _authData['email'] = value as String;
              },
            ),
            TextFormField(
              decoration: const InputDecoration(labelText: 'Password'),
              obscureText: true,
              controller: _passwordController,
              validator: (value) {
                if (value!.isEmpty || value.length < 5) {
                  return 'Password is too short!';
                }
              },
              onSaved: (value) {
                _authData['password'] = value as String;
              },
            ),

That has two TextFormField for E-Mail an Password.

Also the related auth_controller.dart file as following:

enum AuthMode { Signup, Login }

class AuthController extends GetxController
    with GetSingleTickerProviderStateMixin {
  static AuthController instance = Get.find();
  Rx<dynamic>? authMode = AuthMode.Login.obs;
  RxBool? isLoading = false.obs;
  String? _token;
  DateTime? _expiryDate;
  String? _userId;
  Timer? _authTimer;
  final _isAuth = false.obs;

  AnimationController? controller;
  Animation<Offset>? slideAnimation;
  Animation<double>? opacityAnimation;
  late TextEditingController passwordController;
  final key = GlobalKey<FormState>();

  @override
  void onInit() {
    super.onInit();
    tryAutoLogin();
    controller = AnimationController(
      vsync: this,
      duration: const Duration(
        milliseconds: 300,
      ),
    );
    slideAnimation = Tween<Offset>(
      begin: const Offset(0, -1.5),
      end: const Offset(0, 0),
    ).animate(
      CurvedAnimation(
        parent: controller as Animation<double>,
        curve: Curves.fastOutSlowIn,
      ),
    );
    opacityAnimation = Tween(begin: 0.0, end: 1.0).animate(
      CurvedAnimation(
        parent: controller as Animation<double>,
        curve: Curves.easeIn,
      ),
    );
    // _heightAnimation.addListener(() => setState(() {}));

    passwordController = TextEditingController();
  }

  @override
  void onClose() {
    super.onClose();
    passwordController.dispose();
  }

  bool get isAuth {
    _isAuth.value = token != null;
    return _isAuth.value;
  }

  String? get token {
    if (_expiryDate != null &&
        _expiryDate!.isAfter(DateTime.now()) &&
        _token != null) {
      return _token;
    }
    return null;
  }

  String? get userId {
    return _userId;
  }

  Future<void> _authenticate(
      String email, String password, String urlSegment) async {
    // print('app is here!!!5555');
    // const host = "localhost";
    final host = UniversalPlatform.isAndroid ? '10.0.2.2' : '127.0.0.1';
    final url = Uri.parse('http://$host:8000/api/$urlSegment');

    try {
      final http.Response response = await http.post(
        url,
        headers: {"Content-Type": "application/json"},
        body: json.encode(
          {
            'email': email,
            'password': password,

            //'returnSecureToken': true,
          },
        ),
      );
      // print('this is responsde ' );
      // print(response);

      final responseData = json.decode(response.body);
        print(responseData);

      if (responseData['error'] != null) {
        throw HttpException(responseData['error']['message']);
      } else {
        _token = responseData['idToken'];
        _userId = responseData['id'];
        _expiryDate = DateTime.now().add(
          Duration(
            milliseconds: responseData['expiresIn'],
          ),
        );
      }
      _autoLogout();
      // update();
      final prefs = await SharedPreferences.getInstance();
      final userData = json.encode(
        {
          'token': _token,
          'userId': _userId,
          'expiryDate': _expiryDate!.toIso8601String(),
        },
      );
      prefs.setString('userData', userData);
      isLoading?.value = false;

      // print(prefs.getString('userData'));
      Get.toNamed(rootRoute);
    } catch (error) {
      throw error;
    }
  }

  Future<void> signup(String email, String password) async {
    return _authenticate(email, password, 'signup');
  }

  Future<void> login(String email, String password) async {
    return _authenticate(email, password, 'sessions');
  }

  Future<bool> tryAutoLogin() async {
final prefs = await SharedPreferences.getInstance();
    if (!prefs.containsKey('userData')) {
      return false;
    }
    final Map<String, Object> extractedUserData = Map<String, Object>.from(
        json.decode(prefs.getString('userData') as String));
    final expiryDate =
        DateTime.parse(extractedUserData['expiryDate'] as String);

    if (expiryDate.isBefore(DateTime.now())) {
      return false;
    }
    _token = extractedUserData['token'] as String;
    _userId = extractedUserData['userId'] as String;
    _expiryDate = expiryDate;
     _isAuth.value = true;
    _autoLogout();
    return true;
  }

  Future<void> logout() async {
    _token = null;
    _userId = null;
    _expiryDate = null;
    if (_authTimer != null) {
      _authTimer!.cancel();
      _authTimer = null;
    }
    // update();
    final prefs = await SharedPreferences.getInstance();
    // prefs.remove('userData');
    prefs.clear();
    _isAuth.value = false;
  }

  void _autoLogout() {
    if (_authTimer != null) {
      _authTimer!.cancel();
    }
    final timeToExpiry = _expiryDate!.difference(DateTime.now()).inSeconds;
    _authTimer = Timer(Duration(seconds: timeToExpiry), logout);
  }
}

When I start the application it seems it runs with no errors but when as soon as I click on TextFormFields to enter email or password, the virtual keyboard on the Android Emulator opens and closes immediately and doesn't let me enter anything. Also it shows the following message within the DEBUG CONSOLE:

D/InputConnectionAdaptor( 3218): The input method toggled cursor
monitoring on

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

蓝眼睛不忧郁 2025-01-30 17:56:23

经过如此多的努力,我发现而不是neceslesswidget请使用statefullwidget对此。
我希望它能帮助您!

After So many efforts I found that instead of StateLessWidget Please use StatefullWidget for the same.
I hope it helps you!

微凉 2025-01-30 17:56:23

就我而言,解决方案是将globalkey()从build()方法

关闭键盘中取出:

Form(key: GlobalKey<FormState>());

解决方案:

final _formKey = GlobalKey<FormState>();
Form(key: _formKey)

In my case, solution was taking GlobalKey() out of build () method

Closing keyboard:

Form(key: GlobalKey<FormState>());

Solution:

final _formKey = GlobalKey<FormState>();
Form(key: _formKey)
德意的啸 2025-01-30 17:56:23

textformfield上设置“ ”属性为我解决了此问题。我在initstate方法中创建了密钥(尽管可以使用globalkey&formfieldState&gt;()构造函数,但可以在其他位置创建它。

Setting the "key" property on the TextFormField solved this problem for me. I created the key in the initState method (although it could probably be created in other places), using the GlobalKey<FormFieldState>() constructor.

埖埖迣鎅 2025-01-30 17:56:23

我面临着同样的问题。解决方案是使用状态小部件,并将_FormKey直接放在类范围下,而不是窗口小部件的构建。

    class _SignupFormState extends State<SignupForm> {
  final _formkey = GlobalKey<FormState>();
  @override
  Widget build(BuildContext context) {
//rest of the code
}

I was facing the same problem. Solution is to use Stateful Widget and put the _formkey direct under the class scope and not under Widget build.

    class _SignupFormState extends State<SignupForm> {
  final _formkey = GlobalKey<FormState>();
  @override
  Widget build(BuildContext context) {
//rest of the code
}
笑叹一世浮沉 2025-01-30 17:56:23

我使用 hooks_riverpod 。以下代码在构建方法中为我解决了问题。

final formKey = useMemoized(() => GlobalKey<FormState>());

我希望如果您使用 flutter_hooks

I use hooks_riverpod. The following code fixed the issue for me inside the build method.

final formKey = useMemoized(() => GlobalKey<FormState>());

I hope this applies if you are using flutter_hooks as well.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文