我正在开发一个Flutter应用,下面是我的UI代码
def draw_rotated_image(ctx, image_surface, left, top, width, height, angle=0.0, alpha=1.0):
ctx.save()
w = image_surface.get_width()
h = image_surface.get_height()
# get the new top-left position according to the given angle
newTopLeft = getTopLeftForRectangleAtAngle(left, top, width, height, angle)
# translate
ctx.translate(newTopLeft[0], newTopLeft[1])
# rotate
ctx.rotate(angle * math.pi / 180)
# scale & write
ctx.scale(width/w, height/h)
ctx.set_source_surface(image_surface, 0, 0)
ctx.paint_with_alpha(alpha)
ctx.restore()
return
bELOW图像显示我在大多数手机中获得的用户界面是正确的,在某些手机中获得的用户界面是不正确的。
如您所见,在不准确的版本中,缺少底部的按钮。这特别发生在import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
class LoginPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(maxHeight: MediaQuery.of(context).size.height),
child: Container(child: _LoginUI(),),)
),
);
}
}
class _LoginUI extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return _LoginState();
}
}
class _LoginState extends State<_LoginUI> {
final _formKey = GlobalKey<FormState>();
//FIXME When validate error occures, the fields get super small
TextEditingController _phoneNumber = TextEditingController();
TextEditingController _passwordController = TextEditingController();
@override
Widget build(BuildContext context) {
return Container(
height: double.infinity,
width: double.infinity,
child:
Stack(
fit: StackFit.loose,
children: <Widget>[
SafeArea(
child: Container(
margin: EdgeInsets.only(top: 25),
child: Image.asset("assets/images/login_image.png"),
),
),
Positioned(
top: 275,
child: Container(
height: 600,
width: MediaQuery.of(context).size.width,
decoration: new BoxDecoration(
color: Colors.white,
borderRadius: new BorderRadius.only(
topLeft: const Radius.circular(40.0),
topRight: const Radius.circular(40.0))),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Flexible(
child: Container(
margin:
EdgeInsets.only(top: 20, left: 10, right: 10),
child: Image.asset(
"assets/images/logo.png",
width: 200,
height: 50),
),
)
],
),
Form(
key: _formKey,
child: Column(
children: <Widget>[
Container(
margin: EdgeInsets.only(
top: 40,
),
child: SizedBox(
width: MediaQuery.of(context).size.width * .90,
height: 36,
child: TextFormField(
controller: _phoneNumber,
validator: (value) {
if (value.isEmpty) {
return 'Please enter some text';
}
return null;
},
decoration: InputDecoration(
filled: true,
fillColor: Colors.white,
contentPadding: const EdgeInsets.only(
top: 2, bottom: 2, left: 8),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(30.0),
),
hintText: "Email",
),
),
)),
Container(
margin: EdgeInsets.only(
top: 15,
),
child: SizedBox(
height: 36,
width: MediaQuery.of(context).size.width * .90,
child: TextFormField(
controller: _passwordController,
keyboardType: TextInputType.visiblePassword,
validator: (value) {
if (value.isEmpty) {
return 'Please enter some text';
}
return null;
},
decoration: InputDecoration(
filled: true,
fillColor: Colors.white,
contentPadding: const EdgeInsets.only(
top: 2, bottom: 2, left: 8),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(30.0),
),
hintText: "Password",
),
),
),
),
Align(
alignment: Alignment.bottomRight,
child: Container(
margin: EdgeInsets.only(
top: 1, left: 10, right: 10),
child: FlatButton(
onPressed: () {
Navigator.pushNamed(context, "/password-reset");
},
child: Text("Forgot Password?",
style: TextStyle(
fontFamily: 'Roboto-Medium',
fontSize: 14.0,
letterSpacing: 1.25,
color:
Color.fromRGBO(75, 56, 137, 80))),
)),
),
Container(
margin:
EdgeInsets.only(top: 1, left: 10, right: 10),
child: SizedBox(
width: MediaQuery.of(context).size.width * .90,
child: RaisedButton(
color: Color.fromRGBO(75, 56, 137, 80),
textColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius:
new BorderRadius.circular(18.0),
side: BorderSide(
color:
Color.fromRGBO(75, 56, 137, 80))),
child: Text(
"LOGIN",
style: Theme.of(context).textTheme.button,
),
onPressed: () {
String email = _phoneNumber.text;
String password = _passwordController.text;
if (_formKey.currentState.validate()) {
loginProcess(email, password);
}
},
),
))
],
),
),
Container(
margin: EdgeInsets.only(top: 1, left: 10, right: 10),
child: FlatButton(
onPressed: () {
Navigator.pushNamed(context, "/register");
},
child: RichText(
text: TextSpan(children: <TextSpan>[
TextSpan(
text: "Not a member yet? ",
style: TextStyle(fontFamily: 'Roboto-Regular', fontSize: 14.0, letterSpacing: 0.25, color:Color.fromRGBO(75, 56, 137, 80 )),
),
TextSpan(
text: "Create an Account",
style: TextStyle(decoration: TextDecoration.underline, fontFamily: 'Roboto-Regular', fontSize: 14.0, letterSpacing: 0.25, color:Color.fromRGBO(75, 56, 137, 80 ),
),)
]),
),
)),
],
),
),
),
],
)
//child: Image.asset("assets/images/login_image.png"),
);
}
系列中,其屏幕尺寸为4.6英寸,分辨率为720x1280。
最简单的解决方法是将Sony Xperia
内的值更改为250,这会使图像下方的整个块更加向上。但这在某些手机中很难看,因为它覆盖了顶部图像。我有另一个与此问题相同的屏幕,它具有更多字段。因此,将positioned
值设置为其他值之类的解决方案将行不通。
什么是最好的解决方案,以确保整个屏幕在所有手机中都可见?
答案 0 :(得分:1)
我的方法如下:
然后将Scaffold
和SafeArea
包裹起来(这是可选的)
如果小部件已正确放置在当前设备(例如当前仿真器)中,
分辨率为480x800
。小部件位于250px
(您的用例中的一个示例)
然后将其定位在距离顶部((250/800)* 100)约31.25%的位置。
然后我将使用MediaQuery.of(Context).size.height*0.3125
从顶部放置小部件。
现在,无论手机的高度如何,小部件都将始终位于顶部的31.25%处。
类似地,您也可以为left
职位/
我的建议也是对小部件的宽度和高度执行相同的操作,以使小部件的尺寸也与设备屏幕相同。并且对于某些设备而言看起来也不算太大或太小。不是每个小部件,而是某些。
答案 1 :(得分:1)
我更改了您的代码,但没有资产文件,所以我改了SizedBox。
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
class LoginPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: _LoginUI(),
);
}
}
class _LoginUI extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return _LoginState();
}
}
class _LoginState extends State<_LoginUI> {
final _formKey = GlobalKey<FormState>();
//FIXME When validate error occures, the fields get super small
TextEditingController _phoneNumber = TextEditingController();
TextEditingController _passwordController = TextEditingController();
@override
Widget build(BuildContext context) {
return Container(
child: SafeArea(
child: LayoutBuilder(builder:
(BuildContext context, BoxConstraints viewportConstraints) {
return SingleChildScrollView(
reverse: true,
child: ConstrainedBox(
constraints: BoxConstraints(
minHeight: viewportConstraints.maxHeight,
),
child: Column(
children: <Widget>[
Container(
margin: EdgeInsets.only(top: 25),
// child: Image.asset("assets/images/login_image.png"),
child: SizedBox(
height: 200,
child: Text('Login_image'),
),
),
Container(
width: MediaQuery.of(context).size.width,
decoration: new BoxDecoration(
color: Colors.white,
borderRadius: new BorderRadius.only(
topLeft: const Radius.circular(40.0),
topRight: const Radius.circular(40.0))),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Flexible(
child: Container(
margin: EdgeInsets.only(
top: 20, left: 10, right: 10),
child: Container(
height: 50,
child: Text('LOGO'),
),
//Image.asset("assets/images/logo.png",
// width: 200, height: 50),
),
)
],
),
Form(
key: _formKey,
child: Column(
children: <Widget>[
Container(
margin: EdgeInsets.only(
top: 40,
),
child: SizedBox(
width:
MediaQuery.of(context).size.width * .90,
height: 36,
child: TextFormField(
controller: _phoneNumber,
validator: (value) {
if (value.isEmpty) {
return 'Please enter some text';
}
return null;
},
decoration: InputDecoration(
filled: true,
fillColor: Colors.white,
contentPadding: const EdgeInsets.only(
top: 2, bottom: 2, left: 8),
border: OutlineInputBorder(
borderRadius:
BorderRadius.circular(30.0),
),
hintText: "Email",
),
),
)),
Container(
margin: EdgeInsets.only(
top: 15,
),
child: SizedBox(
height: 36,
width:
MediaQuery.of(context).size.width * .90,
child: TextFormField(
controller: _passwordController,
keyboardType: TextInputType.visiblePassword,
validator: (value) {
if (value.isEmpty) {
return 'Please enter some text';
}
return null;
},
decoration: InputDecoration(
filled: true,
fillColor: Colors.white,
contentPadding: const EdgeInsets.only(
top: 2, bottom: 2, left: 8),
border: OutlineInputBorder(
borderRadius:
BorderRadius.circular(30.0),
),
hintText: "Password",
),
),
),
),
Align(
alignment: Alignment.bottomRight,
child: Container(
margin: EdgeInsets.only(
top: 1, left: 10, right: 10),
child: FlatButton(
onPressed: () {
Navigator.pushNamed(
context, "/password-reset");
},
child: Text("Forgot Password?",
style: TextStyle(
fontFamily: 'Roboto-Medium',
fontSize: 14.0,
letterSpacing: 1.25,
color: Color.fromRGBO(
75, 56, 137, 80))),
)),
),
Container(
margin: EdgeInsets.only(
top: 1, left: 10, right: 10),
child: SizedBox(
width:
MediaQuery.of(context).size.width * .90,
child: RaisedButton(
color: Color.fromRGBO(75, 56, 137, 80),
textColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius:
new BorderRadius.circular(18.0),
side: BorderSide(
color: Color.fromRGBO(
75, 56, 137, 80))),
child: Text(
"LOGIN",
style:
Theme.of(context).textTheme.button,
),
onPressed: () {
String email = _phoneNumber.text;
String password =
_passwordController.text;
if (_formKey.currentState.validate()) {
// loginProcess(email, password);
}
},
),
))
],
),
),
Container(
margin:
EdgeInsets.only(top: 1, left: 10, right: 10),
child: FlatButton(
onPressed: () {
Navigator.pushNamed(context, "/register");
},
child: RichText(
text: TextSpan(children: <TextSpan>[
TextSpan(
text: "Not a member yet? ",
style: TextStyle(
fontFamily: 'Roboto-Regular',
fontSize: 14.0,
letterSpacing: 0.25,
color: Color.fromRGBO(75, 56, 137, 80)),
),
TextSpan(
text: "Create an Account",
style: TextStyle(
decoration: TextDecoration.underline,
fontFamily: 'Roboto-Regular',
fontSize: 14.0,
letterSpacing: 0.25,
color: Color.fromRGBO(75, 56, 137, 80),
),
)
]),
),
)),
SizedBox(height: 400),
],
),
),
],
),
),
);
}),
),
);
//child: Image.asset("assets/images/login_image.png"),
}
}