【发布时间】:2020-04-15 16:29:15
【问题描述】:
我正在编写一个 Flutter 应用程序,最近(我正在使用支持 Web 的 Flutter 版本)我必须在每个调试会话开始时按下 DartDev 工具中的 Debug 按钮才能使按钮工作。例如,我按下键盘上的 F5 以使用 Mac iPhone 模拟器启动调试会话,如下所示:
当我陈述调试会话并按下小“调试”按钮时,我使用 Command-Tab 进入浏览器中自动启动的 Dart DevTool:
立即在模拟器中启用“登录”按钮:
在 Android 上调试时也会发生这种情况。
知道这是为什么吗?我可以在不按调试按钮的情况下输入文本字段。我不知道为什么 RaisedButton 在开始时被禁用。这似乎是一个小烦恼,但将其乘以您在开发期间每天运行调试器的 100 多次,挫败感就会加起来。
这是一个重现此行为的 main.dart 文件:
import 'package:flutter/material.dart';
// import 'package:flutter/services.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "Bleu Inventory",
//debugShowCheckedModeBanner: false,
home: LoginPage(), //MainPage(),
theme: ThemeData(accentColor: Colors.white70),
);
}
}
class LoginPage extends StatefulWidget {
@override
_LoginPageState createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
bool _isLoading = false;
String message = 'Please login to continue.';
final TextEditingController emailController = new TextEditingController();
final TextEditingController passwordController = new TextEditingController();
FocusNode emailFocusNode;
@override
void initState() {
super.initState();
emailController.text = '';
passwordController.text = '';
emailFocusNode = FocusNode();
}
@override
Widget build(BuildContext context) {
// SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.light
// .copyWith(statusBarColor: Colors.transparent));
return Scaffold(
body: Container(
color: Colors.white,
child: _isLoading
? Center(
child: CircularProgressIndicator(
backgroundColor: Colors.white,
))
: ListView(
children: <Widget>[
headerSection(),
textSection(),
buttonSection(),
messageSection(),
],
),
),
);
}
signIn(String email, pass) async {
Map data = {'USER': email, 'PASSWORD': pass};
setState(() {
_isLoading = false;
message = 'logged in successfully';
});
}
Container buttonSection() {
return Container(
// width: double.infinity, // MediaQuery.of(context).size.width,
height: 40.0,
padding: EdgeInsets.symmetric(horizontal: 15.0),
margin: EdgeInsets.only(top: 15.0),
child: RaisedButton(
onPressed: emailController.text == "" || passwordController.text == ""
? null
: () {
// setState(() {
_isLoading = true;
// });
signIn(emailController.text, passwordController.text);
},
elevation: 6.0,
color: Colors.blue[800],
child: Text("Sign In",
style: TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.bold)),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5.0)),
),
);
}
Container messageSection() {
return Container(
width: double.infinity,
height: 40.0,
padding: EdgeInsets.symmetric(horizontal: 15.0),
margin: EdgeInsets.only(top: 15.0),
child: Text(
message,
style: TextStyle(
color: Colors.black,
fontSize: 18,
fontWeight: FontWeight.bold,
),
textAlign: TextAlign.center,
),
);
}
Container textSection() {
return Container(
padding: EdgeInsets.symmetric(horizontal: 15.0, vertical: 20.0),
child: Column(
children: <Widget>[
TextFormField(
autofocus: true,
focusNode: emailFocusNode,
controller: emailController,
cursorColor: Colors.blue,
style: TextStyle(color: Colors.blue[800]),
decoration: InputDecoration(
icon: Icon(Icons.email, color: Colors.blue[800]),
hintText: "User Name",
border: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.grey)),
hintStyle: TextStyle(color: Colors.grey),
),
),
SizedBox(height: 30.0),
TextFormField(
controller: passwordController,
cursorColor: Colors.black,
obscureText: true,
style: TextStyle(color: Colors.blue[800]),
decoration: InputDecoration(
icon: Icon(Icons.lock, color: Colors.blue[800]),
hintText: "Password",
border: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.blue[800])),
hintStyle: TextStyle(color: Colors.grey),
),
),
],
),
);
}
Container headerSection() {
return Container(
margin: EdgeInsets.fromLTRB(20, 50.0, 20.0, 10.0),
padding: EdgeInsets.symmetric(horizontal: 20.0, vertical: 30.0),
child: Column(
children: <Widget>[
Text('My App Name',
style: TextStyle(
color: Colors.blue[800],
fontSize: 32,
shadows: [
Shadow(
color: Colors.black,
blurRadius: 6,
offset: Offset.fromDirection(0))
],
fontWeight: FontWeight.bold)),
],
),
);
}
}
这是flutter -v Doctor的输出
~/flutter_workspace/debug_example
flutter -v doctor
[✓] Flutter (Channel dev, v1.13.5, on Mac OS X 10.14.6 18G2022, locale en-US)
• Flutter version 1.13.5 at /Users/jdavies/development/flutter
• Framework revision 41a911099b (7 days ago), 2019-12-19 13:48:02 -0800
• Engine revision 0f90e6546b
• Dart version 2.8.0 (build 2.8.0-dev.0.0 aa6709974d)
[✓] Android toolchain - develop for Android devices (Android SDK version 29.0.2)
• Android SDK at /Users/jdavies/Library/Android/sdk
• Android NDK location not configured (optional; useful for native profiling support)
• Platform android-29, build-tools 29.0.2
• Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
• Java version OpenJDK Runtime Environment (build 1.8.0_202-release-1483-b49-5587405)
• All Android licenses accepted.
[✓] Xcode - develop for iOS and macOS (Xcode 11.0)
• Xcode at /Applications/Xcode.app/Contents/Developer
• Xcode 11.0, Build version 11A420a
• CocoaPods version 1.7.5
[✓] Chrome - develop for the web
• Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
[✓] Android Studio (version 3.5)
• Android Studio at /Applications/Android Studio.app/Contents
• Flutter plugin version 42.1.1
• Dart plugin version 191.8593
• Java version OpenJDK Runtime Environment (build 1.8.0_202-release-1483-b49-5587405)
[✓] VS Code (version 1.41.1)
• VS Code at /Applications/Visual Studio Code.app/Contents
• Flutter extension version 3.7.1
[✓] Connected device (3 available)
• iPhone 11 Pro Max • A96AF9B1-AE6E-423E-B4C5-9ECD4E2D8DE3 • ios • com.apple.CoreSimulator.SimRuntime.iOS-13-0
(simulator)
• Chrome • chrome • web-javascript • Google Chrome 79.0.3945.88
• Web Server • web-server • web-javascript • Flutter Tools
• No issues found!
非常感谢 JacksonZ 在这方面的洞察力和帮助。根据他的建议,我将代码重构为以下工作解决方案:
import 'package:flutter/material.dart';
// import 'package:flutter/services.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "Bleu Inventory",
//debugShowCheckedModeBanner: false,
home: LoginPage(), //MainPage(),
theme: ThemeData(accentColor: Colors.white70),
);
}
}
class LoginPage extends StatefulWidget {
@override
_LoginPageState createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
/// Are we waiting on the login process?
bool _isLoading = false;
String message = 'Please login to continue.';
static const _minUserNameLength = 5;
static const _minPasswordLength = 8;
/// This variable tells is if the name and password text fields were of a valid
/// length (or not) before the current keystroke. This keeps us from calling
/// setState() every time a keystroke is added beyond the minimum.
bool wasNameAndPasswordValidBefore = false;
final TextEditingController userNameController = new TextEditingController();
final TextEditingController passwordController = new TextEditingController();
FocusNode userNameFocusNode;
@override
void initState() {
super.initState();
userNameController.text = '';
passwordController.text = '';
userNameFocusNode = FocusNode();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
color: Colors.white,
child: _isLoading
? Center(
child: CircularProgressIndicator(
backgroundColor: Colors.white,
))
: ListView(
children: <Widget>[
headerSection(),
textSection(),
buttonSection(),
messageSection(),
],
),
),
);
}
signIn(String userName, pass) async {
// Map data = {'USER': userName, 'PASSWORD': pass};
setState(() {
_isLoading = false;
message = 'logged in successfully';
});
}
Container buttonSection() {
return Container(
// width: double.infinity, // MediaQuery.of(context).size.width,
height: 40.0,
padding: EdgeInsets.symmetric(horizontal: 15.0),
margin: EdgeInsets.only(top: 15.0),
child: RaisedButton(
onPressed: areNameAndPasswordSupplied() == false
? null
: () {
setState(() {
_isLoading = true;
});
signIn(userNameController.text, passwordController.text);
},
elevation: 6.0,
color: Colors.blue[800],
child: Text("Sign In",
style: TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.bold)),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5.0)),
),
);
}
Container messageSection() {
return Container(
width: double.infinity,
height: 40.0,
padding: EdgeInsets.symmetric(horizontal: 15.0),
margin: EdgeInsets.only(top: 15.0),
child: Text(
message,
style: TextStyle(
color: Colors.black,
fontSize: 18,
fontWeight: FontWeight.bold,
),
textAlign: TextAlign.center,
),
);
}
/// Make changes to the UI IFF the name and password are supplied and of
/// valid lengths and they were NOT both of valid lengths on the last keystroke.
///
bool areNameAndPasswordSupplied() {
// Are both fields valid at this moment?
bool fieldsValid = userNameController.text.length >= _minUserNameLength &&
passwordController.text.length >= _minPasswordLength;
if (fieldsValid ^ wasNameAndPasswordValidBefore) {
// The state has changed
setState(() {});
}
wasNameAndPasswordValidBefore = fieldsValid; // Update our state of validity
return wasNameAndPasswordValidBefore;
}
Container textSection() {
return Container(
padding: EdgeInsets.symmetric(horizontal: 15.0, vertical: 20.0),
child: Column(
children: <Widget>[
TextFormField(
autofocus: true,
focusNode: userNameFocusNode,
controller: userNameController,
cursorColor: Colors.blue,
style: TextStyle(color: Colors.blue[800]),
decoration: InputDecoration(
icon: Icon(Icons.face, color: Colors.blue[800]),
hintText: "User Name",
border: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.grey)),
hintStyle: TextStyle(color: Colors.grey),
),
onChanged: (newText) {
areNameAndPasswordSupplied();
},
),
SizedBox(height: 30.0),
TextFormField(
controller: passwordController,
cursorColor: Colors.black,
obscureText: true,
style: TextStyle(color: Colors.blue[800]),
decoration: InputDecoration(
icon: Icon(Icons.lock, color: Colors.blue[800]),
hintText: "Password",
border: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.blue[800])),
hintStyle: TextStyle(color: Colors.grey),
),
onChanged: (newText) {
areNameAndPasswordSupplied();
},
),
],
),
);
}
Container headerSection() {
return Container(
margin: EdgeInsets.fromLTRB(20, 50.0, 20.0, 10.0),
padding: EdgeInsets.symmetric(horizontal: 20.0, vertical: 30.0),
child: Column(
children: <Widget>[
Text('My App Name',
style: TextStyle(
color: Colors.blue[800],
fontSize: 32,
shadows: [
Shadow(
color: Colors.black,
blurRadius: 6,
offset: Offset.fromDirection(0))
],
fontWeight: FontWeight.bold)),
],
),
);
}
}
【问题讨论】:
-
请添加一些代码