Search code examples
androidflutterdartandroid-emulator

Error with Flutter Form & TextField on the Android Emulator


I have this Login Page that allows user to enter their username, password, and login. Basically, when the user enters information into the two text fields, the text controllers will update. When the user clicks the submit button, it will run some login procedures (not relevent to this problem).

I am developing this on Android Studio, and when I run it on the Chrome web, it works perfectly fine, allowing me to enter text. However when I do it on an Android Emulator, the moment I enter the login page, I am bombarded with a ton of errors. There are a couple errors at the start, but when I open the Android Touch Keyboard, errors appear when I type or remove characters. Is there a problem with my code?

login_screen.dart

import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:wolfpackapp/models_services/teachassist_model.dart';

/*
#########################
#=-=-= LoginScreen =-=-=#
#########################
*/
class LoginScreen extends StatefulWidget {

  const LoginScreen({super.key});

  @override
  State<LoginScreen> createState() => _LoginScreenState();
}

class _LoginScreenState extends State<LoginScreen> {
  final TextEditingController _usernameController = TextEditingController();
  final TextEditingController _passwordController = TextEditingController();

  @override
  Widget build(BuildContext context) {

    return Scaffold(
      backgroundColor: Theme.of(context).colorScheme.primary,
      extendBody: true,
      body: SingleChildScrollView(
        child: Column(
          children: [
            /*
            ##################
            #=-=-= Form =-=-=#
            ##################
            */

            SizedBox (
              height: 350,
              child: Padding(
                  padding: const EdgeInsets.all(50),
                  child: Column(
                    children: [
                      // Username
                      UsernameField(controller: _usernameController),

                      // Password
                      PasswordField(controller: _passwordController),
                    ],
                  ),
              ),
            ),

            /*
            ####################
            #=-=-= Button =-=-=#
            ####################
            */
            Padding(
              padding: const EdgeInsets.symmetric(horizontal: 50),
              child: SizedBox(
                width: double.infinity,
                child: ElevatedButton(
                  style: Theme.of(context).elevatedButtonTheme.style,
                  child: Padding(
                    padding: const EdgeInsets.all(15),
                    child: Text('Sign In',
                      style: GoogleFonts.lato(
                        color: Theme.of(context).colorScheme.inversePrimary,
                        fontSize: 20, fontWeight: FontWeight.w600)),
                  ),
                  onPressed: (){
                    String username = _usernameController.text.trim();
                    String password = _passwordController.text.trim();
                    authorizeUser(username,password);
                  },
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

/*
######################
#=-=-= Username =-=-=#
######################
*/
class UsernameField extends StatefulWidget {
  final TextEditingController controller;

  const UsernameField({
    required this.controller,
    super.key,
  });

  @override
  State<UsernameField> createState() => _UsernameFieldState();
}

class _UsernameFieldState extends State<UsernameField> {
  Color _colorText = Colors.grey;

  @override
  Widget build(BuildContext context) {
    const defaultColor = Colors.grey;
    final focusColor = Theme.of(context).colorScheme.secondary;

    return Focus(
      onFocusChange: (hasFocus) {
      setState(() => _colorText = hasFocus ? focusColor : defaultColor);
      },
      child: TextField(
        controller: widget.controller,
        decoration: InputDecoration(
          prefixIcon: Icon(Icons.person, color: _colorText),
          labelText: "Student Number",
          labelStyle: TextStyle(color: _colorText),
          focusedBorder: UnderlineInputBorder(
            borderSide: BorderSide(color: _colorText)
          ),
        ),
      ),
    );
  }
}


/*
######################
#=-=-= Password =-=-=#
######################
*/
class PasswordField extends StatefulWidget {
  final TextEditingController controller;

  const PasswordField({
    required this.controller,
    super.key,
  });

  @override
  State<PasswordField> createState() => _PasswordFieldState();
}

class _PasswordFieldState extends State<PasswordField> {
  Color _colorText = Colors.grey;

  @override
  Widget build(BuildContext context) {
    const defaultColor = Colors.grey;
    final focusColor = Theme.of(context).colorScheme.secondary;

    return Focus(
      onFocusChange: (hasFocus) {
      setState(() => _colorText = hasFocus ? focusColor : defaultColor);
      },
      child: TextField(
        controller: widget.controller,
        obscureText: true,
        decoration: InputDecoration(
          prefixIcon: Icon(Icons.lock, color: _colorText),
          labelText: "Password",
          labelStyle: TextStyle(color: _colorText),
          focusedBorder: UnderlineInputBorder(
              borderSide: BorderSide(color: _colorText)
          ),
        ),
      ),
    );
  }
}

Error

Performing hot restart...
Syncing files to device sdk gphone64 x86 64...
Restarted application in 1,222ms.
W/WindowOnBackDispatcher( 4191): OnBackInvokedCallback is not enabled for the application.
W/WindowOnBackDispatcher( 4191): Set 'android:enableOnBackInvokedCallback="true"' in the application manifest.
D/InsetsController( 4191): hide(ime(), fromIme=true)
D/InputConnectionAdaptor( 4191): The input method toggled cursor monitoring off
D/EGL_emulation( 4191): app_time_stats: avg=9214.08ms min=1.45ms max=128936.82ms count=14
I/ImeTracker( 4191): com.edisoncai.unionville_student_tools:f5b57e07: onRequestHide at ORIGIN_CLIENT reason HIDE_SOFT_INPUT_ON_ANIMATION_STATE_CHANGED fromUser false
I/ImeTracker( 4191): com.google.android.inputmethod.latin:9f05f268: onHidden
I/ImeTracker( 4191): com.edisoncai.unionville_student_tools:7153a72f: onRequestShow at ORIGIN_CLIENT reason SHOW_SOFT_INPUT fromUser false
D/InputMethodManager( 4191): showSoftInput() view=io.flutter.embedding.android.FlutterView{66c40f9 VFE...... .F...... 0,0-1344,2920 #1 aid=1073741824} flags=0 reason=SHOW_SOFT_INPUT
I/AssistStructure( 4191): Flattened final assist data: 456 bytes, containing 1 windows, 3 views
D/InputConnectionAdaptor( 4191): The input method toggled cursor monitoring on
D/InsetsController( 4191): show(ime(), fromIme=true)
D/EGL_emulation( 4191): app_time_stats: avg=2978.41ms min=13.51ms max=59255.83ms count=20
I/ImeTracker( 4191): com.edisoncai.unionville_student_tools:7153a72f: onShown
I/ImeTracker( 4191): com.edisoncai.unionville_student_tools:df6a6d1c: onRequestShow at ORIGIN_CLIENT reason SHOW_SOFT_INPUT fromUser false
D/InputMethodManager( 4191): showSoftInput() view=io.flutter.embedding.android.FlutterView{66c40f9 VFE...... .F...... 0,0-1344,2920 #1 aid=1073741824} flags=0 reason=SHOW_SOFT_INPUT
D/InputConnectionAdaptor( 4191): The input method toggled cursor monitoring on
I/AssistStructure( 4191): Flattened final assist data: 456 bytes, containing 1 windows, 3 views
D/InputConnectionAdaptor( 4191): The input method toggled cursor monitoring off
D/InputConnectionAdaptor( 4191): The input method toggled cursor monitoring on
D/InsetsController( 4191): show(ime(), fromIme=true)
I/ImeTracker( 4191): com.edisoncai.unionville_student_tools:df6a6d1c: onCancelled at PHASE_CLIENT_APPLY_ANIMATION
I/ImeTracker( 4191): com.edisoncai.unionville_student_tools:7424377f: onRequestShow at ORIGIN_CLIENT reason SHOW_SOFT_INPUT fromUser false
D/InputMethodManager( 4191): showSoftInput() view=io.flutter.embedding.android.FlutterView{66c40f9 VFE...... .F...... 0,0-1344,2920 #1 aid=1073741824} flags=0 reason=SHOW_SOFT_INPUT
I/AssistStructure( 4191): Flattened final assist data: 456 bytes, containing 1 windows, 3 views
D/InputConnectionAdaptor( 4191): The input method toggled cursor monitoring on
D/EGL_emulation( 4191): app_time_stats: avg=289.96ms min=65.88ms max=499.70ms count=4
D/InputConnectionAdaptor( 4191): The input method toggled cursor monitoring off
D/InputConnectionAdaptor( 4191): The input method toggled cursor monitoring on
D/InsetsController( 4191): show(ime(), fromIme=true)
I/ImeTracker( 4191): com.edisoncai.unionville_student_tools:7424377f: onCancelled at PHASE_CLIENT_APPLY_ANIMATION
I/ImeTracker( 4191): com.edisoncai.unionville_student_tools:dbae3d86: onRequestShow at ORIGIN_CLIENT reason SHOW_SOFT_INPUT fromUser false
D/InputMethodManager( 4191): showSoftInput() view=io.flutter.embedding.android.FlutterView{66c40f9 VFE...... .F...... 0,0-1344,2920 #1 aid=1073741824} flags=0 reason=SHOW_SOFT_INPUT
D/InsetsController( 4191): show(ime(), fromIme=true)
I/ImeTracker( 4191): com.edisoncai.unionville_student_tools:dbae3d86: onCancelled at PHASE_CLIENT_APPLY_ANIMATION
Application finished.

Solution

  • First error that gets printed is:

    W/WindowOnBackDispatcher( 4191): OnBackInvokedCallback is not enabled for the application.
    W/WindowOnBackDispatcher( 4191): Set 'android:enableOnBackInvokedCallback="true"' in the application manifest.
    

    You need to add support for Android 14's Predictive Back Gesture feature to fix this (if this steps don't help, look into the linked resources, there might be some things I've missed):

    1. You need to add TargetPlatform.android: PredictiveBackPageTransitionsBuilder(), inside your MaterialApp's ThemeData:
    return MaterialApp(
      theme: ThemeData(
        brightness: Brightness.light,
        pageTransitionsTheme: const PageTransitionsTheme(
          builders: {
            // Use PredictiveBackPageTransitionsBuilder to get the predictive back route transition!
            TargetPlatform.android: PredictiveBackPageTransitionsBuilder(),
          },
        ),
      ),
      home: const MyApp(),
    );
    
    1. Set android:enableOnBackInvokedCallback="true" in android/app/src/main/AndroidManifest.xml file in the <application> tag:
    <application
        ...
        android:enableOnBackInvokedCallback="true"
        ... >
    ...
    </application>
    

    If there are no issues in user experience or UI on this page, other lines from your debug output might just be emulator logs. To hide those, check out this Stack Overflow thread. Hope this helps :)