我与Flutter的故事已于6个月前开始,今天我终于决定开始在Flutter社区分享我的小指纹。
我将解释Login UI flutter代码的不同部分,但首先,让我告诉你它的样子!我们走吧!
初步设计
首先,我开始在Sketch上进行UI设计,遵循我唯一且永远的设计理念“保持简单!”。
注意:为了能够跟进本文,我希望您对Flutter拥有最低限度的专业知识。
代码
我们现在深入研究代码!
当然,我们从main.dart开始,声明主要方法和一些主题规则。
请注意,我们将DeviceOrientation设置为Portrait Up,因为我们不想处理设备方向改变时发生的混乱。
void main() {
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp])
.then((_) {
runApp(new MyApp());
});
}
很简单。
现在让我们来看看MyApp类,我在这里声明了一些主题规则。
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
hintColor: Color(0xFFC0F0E8),
primaryColor: Color(0xFF80E1D1),
canvasColor: Colors.transparent),
fontFamily: "Montserrat",
home: Home(),
);
}
}
下一步和主要步骤,home.dart包含我们的大部分代码。首先,我们编写Home StatefulWidget类并声明所有必要的变量以便稍后存储用户输入。
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
TextEditingController _emailController = new TextEditingController();
TextEditingController _passwordController = new TextEditingController();
TextEditingController _nameController = new TextEditingController();
String _email;
String _password;
String _displayName;
bool _obsecure = false;
真正的工作从构建方法开始,但首先让我分解我们的UI以了解我们将如何编码它。
我们有3页:
- 包含Logo的主页面,2个用于登录的按钮和用于注册的按钮,以及一些绘制在底部的曲线。
- 登录页面,从主页面点击登录按钮后出现,它有4个组件:关闭图标,2个输入字段和一个提交按钮。
- 注册页面,是具有1个附加字段的登录页面的副本。
现在我们可以开始编写每个组件!
首先,我们有一个带有key
和backgroundColor
的Scaffold
,我们将resizeToAvoidBottomPadding
设置为false,因为当键盘越过它们时,它会在输入字段后面变得混乱。
return Scaffold(
resizeToAvoidBottomPadding: false,
key: _scaffoldKey,
backgroundColor: Theme.of(context).primaryColor,
body: Column());
}
在Column小部件中,我们将添加logo()小部件,以使用Stack和Positioned小部件绘制这个漂亮的简单徽标。Logo()将在构建方法之外,以使我们的代码更清晰。
//GO logo widget
Widget logo() {
return Center(
child: Padding(
padding: EdgeInsets.only(top: 120),
child: Container(
width: MediaQuery.of(context).size.width,
height: 240,
child: Stack(
children: <Widget>[
Positioned(
child: Container(
child: Align(
child: Container(
decoration: BoxDecoration(
shape: BoxShape.circle, color: Colors.white),
width: 150,
height: 150,
),
alignment: Alignment.center,
),
height: 154,
)),
Positioned(
child: Container(
height: 154,
width: MediaQuery.of(context).size.width,
child: Align(
alignment: Alignment.center,
child: Text(
"GO",
style: TextStyle(
fontSize: 120,
fontWeight: FontWeight.bold,
color: Theme.of(context).primaryColor,
),
),
)),
),
Positioned(
width: 60,
height: 60,
top: 140,
left: 260,
child: Container(
decoration: BoxDecoration(
shape: BoxShape.circle, color: Colors.white),
),
),
Positioned(
width: 30,
height: 30,
top: 200,
left: 230,
child: Container(
decoration: BoxDecoration(
shape: BoxShape.circle, color: Colors.white),
),
),
],
),
),
));
}
轮到按钮。我们有2个按钮,一个是RaisedButton,另一个是OutlineButton。为什么我们为每个按钮使用2种不同的小部件?
仅仅为了造型 😁
RaisedButton可以很容易地给它填充颜色,这是我们想要的登录按钮(带有白色填充)。OutlineButton使得有一个带边框但没有填充的按钮变得更容易,这就是我们想要的注册按钮。
我真的很擅长安排我的代码...所以这是我想到的最好的主意。我在代码中多次使用凸起按钮,但是大纲按钮只有一个,所以我认为最好将一个凸起按钮作为一个函数并给它以下参数以使其可重用:
Widget _button (String text, Color splashColor, Color highlightColor, Color fillColor, Color textColor, void function()){}
这么长的参数列表!但比多次编写相同的按钮代码要好得多!
这是我们的RaisedButton小部件的完整代码:
Widget filledButton(String text, Color splashColor, Color highlightColor,
Color fillColor, Color textColor, void function()) {
return RaisedButton(
highlightElevation: 0.0,
splashColor: splashColor,
highlightColor: highlightColor,
elevation: 0.0,
color: fillColor,
shape: RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(30.0)),
child: Text(
text,
style: TextStyle(
fontWeight: FontWeight.bold, color: textColor, fontSize: 20),
),
onPressed: () {
function();
},
);
}
这是OutlineButton:
OutlineButton(
highlightedBorderColor: Colors.white,
borderSide: BorderSide(color: Colors.white, width: 2.0),
highlightElevation: 0.0,
splashColor: Colors.white,
highlightColor: Theme.of(context).primaryColor,
color: Theme.of(context).primaryColor,
shape: RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(30.0),
),
child: Text("REGISTER",style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.white,
fontSize: 20),),
onPressed: () { _registerSheet();
},
),
主页的最后一部分是底部弯曲的白色形状,想知道如何做到这一点?我们将使用ClipPath小部件。
在我们的Scaffold体内的Column内部,我们将添加此代码以绘制弯曲的形状:
Expanded(
child: Align(
child: ClipPath(
child: Container(
color: Colors.white,
height: 300,
),
clipper: BottomWaveClipper(),
),
alignment: Alignment.bottomCenter,
),
)
让我们转到一个名为clipper.dart的新文件,它将包含将绘制弯曲路径的类BottomWaveClipper。
import 'package:flutter/material.dart';
class BottomWaveClipper extends CustomClipper<Path> {
@override
Path getClip(Size size) {
var path = Path();
path.moveTo(size.width, 0.0);
path.lineTo(size.width, size.height);
path.lineTo(0.0, size.height);
path.lineTo(0.0, size.height + 5);
var secondControlPoint = Offset(size.width - (size.width / 6), size.height);
var secondEndPoint = Offset(size.width, 0.0);
path.quadraticBezierTo(secondControlPoint.dx, secondControlPoint.dy,
secondEndPoint.dx, secondEndPoint.dy);
return path;
}
@override
bool shouldReclip(CustomClipper<Path> oldClipper) => false;
}
太神奇了!我们完成了主页面,让我们继续前进。
看起来登录页面和注册页面是应用程序中的新路由,但它们不是,每个都只是一个PersistentBottomSheet!
PersistentBottomSheet是在主要上下文中从底部绘制到屏幕的底部工作表,我们可以在其中填充我们想要的任何内容。
让我们将以下函数添加到每个按钮的onPressed属性上(实际上我们将第一个函数传递给没有括号的_button函数):
_loginSheet
_registerSheet()
你猜他们是什么?嗯,确切地说!它们的功能将返回登录和注册表。每个代码都很长,我不会在这里全部包含它,但我们将看一下它的一些重要特性。
- 它的包裹里面DecoratedBox小部件,然后ClipRRect,给它顶部边角半径。
- 为了滚动,当键盘位于密码字段和提交按钮之上时,元素用ListView而不是Column包裹,使用户能够滚动来解决问题。
DecoratedBox(
decoration: BoxDecoration(color: Theme.of(context).canvasColor),
child:
ClipRRect(borderRadius: BorderRadius.only(
topLeft: Radius.circular(40.0),
topRight: Radius.circular(40.0)),
child: Container( child:
ListView())
)
)
同样适用于工作表,登录和注册。
现在是InputField,它将是一个名为_input的函数,它将返回所需的InputField小部件:
//input widget
Widget _input(Icon icon, String hint, TextEditingController controller, bool obsecure) {
return Container(
padding: EdgeInsets.only(left: 20, right: 20),
child: TextField(
controller: controller,
obscureText: obsecure,
style: TextStyle(fontSize: 20, ),
decoration: InputDecoration(
hintStyle: TextStyle(fontWeight: FontWeight.bold, fontSize: 20),
hintText: hint,
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(30),
borderSide: BorderSide(
color: Theme.of(context).primaryColor,
width: 2,
),
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(30),
borderSide: BorderSide(
color: Theme.of(context).primaryColor,
width: 3,
),
),
prefixIcon: Padding(
child: IconTheme(
data: IconThemeData(color: Theme.of(context).primaryColor),
child: icon,
),
padding: EdgeInsets.only(left: 30, right: 10),
)),
),
);
}
因此,每次我们想要使用输入字段时,我们只需调用此函数并为其提供适合我们使用的参数。我们有5个输入字段,将从这个功能中提取,非常整洁和优雅。
完成!
你可以在这里找到GitHub上的源代码。💙
转:https://medium.com/swlh/simple-clean-login-ui-using-flutter-43314d0dbdee