我正在尝试为我的应用实现反应式ui。我正在登录/注册屏幕的开头,在键盘显示时出现渲染问题:
Performing hot reload...
Syncing files to device Android SDK built for x86...
════════ Exception caught by widgets library ═══════════════════════════════════════════════════════
The following assertion was thrown building Container(constraints: BoxConstraints(0.0<=w<=Infinity, h=-15.0; NOT NORMALIZED), dirty):
BoxConstraints has a negative minimum height.
The offending constraints were: BoxConstraints(0.0<=w<=Infinity, h=-15.0; NOT NORMALIZED)
The relevant error-causing widget was:
Container file:///C:/Dev/mobile/lib/widgets/social_connectors.dart:40:17
When the exception was thrown, this was the stack:
#0 BoxConstraints.debugAssertIsValid.<anonymous closure>.throwError (package:flutter/src/rendering/box.dart:510:9)
#1 BoxConstraints.debugAssertIsValid.<anonymous closure> (package:flutter/src/rendering/box.dart:541:19)
#2 BoxConstraints.debugAssertIsValid (package:flutter/src/rendering/box.dart:558:6)
#3 new ConstrainedBox (package:flutter/src/widgets/basic.dart:2163:27)
#4 Container.build (package:flutter/src/widgets/container.dart:431:17)
...
════════════════════════════════════════════════════════════════════════════════════════════════════
════════ Exception caught by widgets library ═══════════════════════════════════════════════════════
BoxConstraints has a negative minimum height.
The relevant error-causing widget was:
Container file:///C:/Dev/mobile/lib/widgets/social_connectors.dart:40:17
════════════════════════════════════════════════════════════════════════════════════════════════════
Reloaded 2 of 497 libraries in 363ms.
════════ Exception caught by rendering library ═════════════════════════════════════════════════════
The following assertion was thrown during layout:
A RenderFlex overflowed by 169 pixels on the bottom.
The relevant error-causing widget was:
Column file:///C:/Dev/mobile/lib/widgets/login_form.dart:21:22
The overflowing RenderFlex has an orientation of Axis.vertical.
The edge of the RenderFlex that is overflowing has been marked in the rendering with a yellow and black striped pattern. This is usually caused by the contents being too big for the RenderFlex.
Consider applying a flex factor (e.g. using an Expanded widget) to force the children of the RenderFlex to fit within the available space instead of being sized to their natural size.
This is considered an error condition because it indicates that there is content that cannot be seen. If the content is legitimately bigger than the available space, consider clipping it with a ClipRect widget before putting it in the flex, or using a scrollable container rather than a Flex, like a ListView.
The specific RenderFlex in question is: RenderFlex#4cdce OVERFLOWING
... needs compositing
... parentData: offset=Offset(0.0, 0.0) (can use size)
... constraints: BoxConstraints(w=324.0, h=23.0)
... size: Size(324.0, 23.0)
... direction: vertical
... mainAxisAlignment: center
... mainAxisSize: max
... crossAxisAlignment: center
... verticalDirection: down
◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤
════════════════════════════════════════════════════════════════════════════════════════════════════
W/IInputConnectionWrapper(12250): getTextBeforeCursor on inactive InputConnection
W/IInputConnectionWrapper(12250): getSelectedText on inactive InputConnection
W/IInputConnectionWrapper(12250): getTextAfterCursor on inactive InputConnection
W/IInputConnectionWrapper(12250): beginBatchEdit on inactive InputConnection
W/IInputConnectionWrapper(12250): endBatchEdit on inactive InputConnection
════════ Exception caught by widgets library ═══════════════════════════════════════════════════════
The following assertion was thrown building Container(constraints: BoxConstraints(0.0<=w<=Infinity, h=-15.0; NOT NORMALIZED), dirty):
BoxConstraints has a negative minimum height.
The offending constraints were: BoxConstraints(0.0<=w<=Infinity, h=-15.0; NOT NORMALIZED)
The relevant error-causing widget was:
Container file:///C:/Dev/mobile/lib/widgets/social_connectors.dart:40:17
When the exception was thrown, this was the stack:
#0 BoxConstraints.debugAssertIsValid.<anonymous closure>.throwError (package:flutter/src/rendering/box.dart:510:9)
#1 BoxConstraints.debugAssertIsValid.<anonymous closure> (package:flutter/src/rendering/box.dart:541:19)
#2 BoxConstraints.debugAssertIsValid (package:flutter/src/rendering/box.dart:558:6)
#3 new ConstrainedBox (package:flutter/src/widgets/basic.dart:2163:27)
#4 Container.build (package:flutter/src/widgets/container.dart:431:17)
...
════════════════════════════════════════════════════════════════════════════════════════════════════
W/IInputConnectionWrapper(12250): getTextBeforeCursor on inactive InputConnection
W/IInputConnectionWrapper(12250): getSelectedText on inactive InputConnection
W/IInputConnectionWrapper(12250): getTextAfterCursor on inactive InputConnection
W/IInputConnectionWrapper(12250): beginBatchEdit on inactive InputConnection
W/IInputConnectionWrapper(12250): endBatchEdit on inactive InputConnection
════════ Exception caught by widgets library ═══════════════════════════════════════════════════════
The following assertion was thrown building Container(constraints: BoxConstraints(0.0<=w<=Infinity, h=-15.0; NOT NORMALIZED), dirty):
BoxConstraints has a negative minimum height.
The offending constraints were: BoxConstraints(0.0<=w<=Infinity, h=-15.0; NOT NORMALIZED)
The relevant error-causing widget was:
Container file:///C:/Dev/mobile/lib/widgets/social_connectors.dart:40:17
When the exception was thrown, this was the stack:
#0 BoxConstraints.debugAssertIsValid.<anonymous closure>.throwError (package:flutter/src/rendering/box.dart:510:9)
#1 BoxConstraints.debugAssertIsValid.<anonymous closure> (package:flutter/src/rendering/box.dart:541:19)
#2 BoxConstraints.debugAssertIsValid (package:flutter/src/rendering/box.dart:558:6)
#3 new ConstrainedBox (package:flutter/src/widgets/basic.dart:2163:27)
#4 Container.build (package:flutter/src/widgets/container.dart:431:17)
...
════════════════════════════════════════════════════════════════════════════════════════════════════
这是我的布局:
class _AuthenticationPageState extends State<AuthenticationPage> {
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
final authentication_vm = Provider.of<AuthenticationViewModel>(context);
SystemChrome.setEnabledSystemUIOverlays([]);
bool login_visible = true;
return Center(
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/sheets.png"),
fit: BoxFit.fitHeight,
),
),
padding: EdgeInsets.fromLTRB(
MediaQuery.of(context).size.width * 0.05,
MediaQuery.of(context).size.height * 0.05,
MediaQuery.of(context).size.width * 0.05,
MediaQuery.of(context).size.height * 0.05),
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Container(
height: MediaQuery.of(context).size.height * 0.20,
child: LayoutBuilder(builder:
(BuildContext context, BoxConstraints constraints) {
return new Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
AnimatedOpacity(
opacity: login_visible ? 0.0 : 1.0,
duration: Duration(milliseconds: 500),
child: new Container(
height: constraints.maxHeight,
width: 30,
child: Container(
alignment: Alignment.topCenter,
child: new GestureDetector(
onTap: () {
Navigator.pop(context, true);
},
child: Icon(
Icons.arrow_back,
color: Colors.white,
),
),
),
),
),
new Image.asset(
"assets/logo.png",
height: constraints.maxHeight,
fit: BoxFit.fitHeight,
),
new Container(
width: 30,
),
],
);
}),
),
Container(
height: MediaQuery.of(context).size.height * 0.50,
child: ListView(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: false,
children: <Widget>[
Container(
width: MediaQuery.of(context).size.width * 0.90,
height: MediaQuery.of(context).size.height * 0.50,
child: LoginForm(loginViewModel: authentication_vm),
),
Container(
width: MediaQuery.of(context).size.width * 0.90,
height: MediaQuery.of(context).size.height * 0.50,
child: RegisterForm(),
),
],
scrollDirection: Axis.horizontal,
),
),
Container(
alignment: Alignment.bottomCenter,
width: MediaQuery.of(context).size.width * 0.65,
height: MediaQuery.of(context).size.height * 0.20,
child: SocialConnectors()),
])),
),
);
}
}
我的登录表单类如下:
class LoginForm extends StatelessWidget {
final AuthenticationViewModel loginViewModel;
final double spacer = 15.0;
LoginForm({this.loginViewModel});
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
return Scaffold(
backgroundColor: Color(TRANSPARENT),
body: new FractionallySizedBox(
widthFactor: 1,
heightFactor: 1,
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
_showLoginInput(),
_showPasswordInput(),
new Container(
height: constraints.maxHeight * 0.05,
),
_showPrimaryButton(),
new Container(
height: constraints.maxHeight * 0.05,
),
Container(
child: new Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: [
Text(
"Dont have an account? ",
style: TextStyle(color: Color(TEXT_COLOR)),
),
GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => RegisterPage()));
},
child: Text(
" Register!",
style: TextStyle(color: Color(MAIN_COLOR)),
),
),
],
),
),
],
),
),
);
});
}
Widget _showLoginInput() {
return new TextFormField(
style: TextStyle(),
maxLines: 1,
keyboardType: TextInputType.text,
autofocus: false,
decoration: new InputDecoration(
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Color(TEXT_COLOR)),
),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.white),
),
hintText: 'Login',
hintStyle: TextStyle(color: Color(TEXT_COLOR)),
icon: new Icon(
Icons.account_circle,
color: Colors.white,
)),
);
}
Widget _showPasswordInput() {
return new TextFormField(
maxLines: 1,
obscureText: true,
autofocus: false,
decoration: new InputDecoration(
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Color(TEXT_COLOR)),
),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.white),
),
hintText: 'Password',
hintStyle: TextStyle(color: Color(TEXT_COLOR)),
icon: new Icon(
Icons.lock,
color: Colors.white,
)),
);
}
Widget _showPrimaryButton() {
return LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
return new SizedBox(
width: constraints.maxWidth * 0.8,
child: new RaisedButton(
color: Color(MAIN_COLOR),
onPressed: () {},
textColor: Colors.white,
shape: new RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(10.0)),
child: Container(
child: const Text('Login', style: TextStyle(fontSize: 20)),
),
),
);
});
}
}
我的目标是呈现两种状态:显示登录或注册。 显示一个或另一个时,表单将向左或向右滑动,并且“返回”箭头将显示或隐藏。
我尝试将整体包装在SingleChildScrollView中,但不起作用。我该如何工作?