实验一 环境搭建与界面设计
一、实验目的
1、掌握移动 APP 客户端开发环境搭建。
2、掌握 HelloWorld 工程项目的创建。
3、了解工程项目文件组织基本组织结构。
4、掌握移动应用开发过程中基本界面布局和基本控件使用。
5、利用基本布局和控件完成移动应用中常见功能。
二、知识要点
1、布局
Flutter 布局机制的核心就是 widget。在 Flutter 中,几乎所有东西都是一个widget - 甚至布局模型都是 widget。您在 Flutter 应用中看到的图像、图标和文本都是 widget。 甚至不可见的东西也是 widget,例如行(row)、列(column)以及用来排列、约束和对齐这些可见 widget 的网格(grid)。
2、基本控件
a) Scaffold:脚手架,布局的基本容器,内部可以使用 material 的控件。
b) Container、SizeBox:容器、盒子,一般用于对内部控件的约束。
c) Column、Row:列、行,用于实现竖直、水平布局。
d) Text:文本展示。
e) Image:图片展示。
f) TextField:文本输入。
g) FlatButton、RaisedButton:按钮。
h) Padding、Align、Center:单一功能简单控件,分别是填充、对齐方式、居中。
i) GridView:网格控件的一种,用于实现网格布局。
j) LinearProgressIndicator:条形进度条。
三、实验内容
1、课堂实验
参考效果图实现百度云盘的个人账户登录界面,具体要求和实现如下:
a) 百度 logo。
b) “欢迎登录百度账号”文本。
c) “登录”按钮,背景色为RGB(200,200,200),”登录”为 Colors.black38。
d) 账号密码未输入情况下,“登录”按钮不可点击。
e) 用户名和密码输入框,“密码是否可见按钮”(小眼睛)支持点击。
f) 输入账号密码后,登陆按钮背景变为 RGB(75,207,250),同时“登录”变为白色且可点击。
g) 点击登录按钮,校验与已设定密码是否相符,并弹出密码正确与否提示。
2、课后练习
参考效果图实现百度云盘个人中心页面的基本界面,具体要求和实现如下:
a) 在课堂实验的基础上,新建界面 personal_center,实现布局。
b) 要求登录成功后跳转至个人中心界面(要求使Navigator.push)。
c) 参考效果添加圆头头像。
d) 添加个人昵称。
e) 展示已用容量/可用容量文本。
f) 展示容量进度条(要求使用LinearProgressIndicator)。
g) 使用网格视图实现功能区,包括 8 个图标及文字(要求使用GridView)。
四、实验结果
1)、课堂实验
1、代码
import 'package:flutter/material.dart';
import 'package:flutter_app02/Tabs.dart';
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("LoginPage"),
),
body: HomeContent(),
);
}
}
class HomeContent extends StatefulWidget {
@override
_HomeContentState createState() => _HomeContentState();
}
class _HomeContentState extends State<HomeContent> {
String _username;
String _password;
//模拟数据库已经存在的账户和密码
String db_username = "zhangsan";
String db_password = "123456";
bool _enable = false;
bool _obscureText = true;
void _click_event(){
if(this._username == this.db_username && this._password == this.db_password)
{
print("登录成功");
showDialog(
context: this.context,
builder: (context){
return AlertDialog(
title: Text('登录提醒'),
content: Text('登录账户:$_username \n'+'登录密码:$_password'),
actions: <Widget>[
FlatButton(
color: Colors.blue,
child: Text('确 认'),
onPressed: (){
Navigator.pop(context);
Navigator.push(context, MaterialPageRoute(
builder: (context)=>Tabs(),
));
},
),
FlatButton(
color: Colors.blue,
child: Text('取 消'),
onPressed: (){
Navigator.pop(context);
},
)
],
);
}
);
}
else
print("用户名或密码错误");
}
// 图片
Widget _imageWidget(){
return Container(
height: 100.0,
child: Image.network("https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png"),
);
}
// 文字
Widget _textWidget(){
return Text(
"欢迎登录百度账户",
style: TextStyle(
fontSize: 20,
),
);
}
// username textField
Widget _usernameTextField(){
return TextField(
decoration: InputDecoration(
hintText: "请输入手机号/用户名/邮箱",
border: OutlineInputBorder(),
icon: Icon(Icons.supervised_user_circle)
),
onChanged: (value){
this._username = value;
setState(() {
if((this._username != "" && this._username != null) && (this._password != "" && this._password != null))
this._enable = true;
else
this._enable = false;
});
},
);
}
Widget _passwordTextField(){
return TextField(
decoration: InputDecoration(
hintText: "请输入登录密码",
fillColor: Color.fromARGB(255, 240, 240, 240),
border: OutlineInputBorder(),
icon: Icon(Icons.security),
suffixIcon: IconButton(
onPressed: (){
setState(() {
this._obscureText = !this._obscureText;
});
},
icon: Image.asset(
this._obscureText ? "assets/hide.png" : "assets/open.png",
width: 20.0,
height: 20.0,
),
splashColor: Colors.transparent,
highlightColor: Colors.transparent,
)
),
obscureText: this._obscureText,
onChanged: (value){
this._password = value;
setState(() {
if((this._username != "" && this._username != null) && (this._password != "" && this._password != null))
this._enable = true;
else
this._enable = false;
});
},
);
}
//登录按钮
Widget _loginButton(){
return Row(
children: [
Expanded(
child: RaisedButton(
child: Text("登录"),
color: Colors.blue,
textColor: Colors.white,
onPressed: this._enable ? _click_event : null,
),
)
],
);
}
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(20),
child: SingleChildScrollView(
child: Column(
children: <Widget>[
_imageWidget(),
_textWidget(),
SizedBox(height: 10.0,),
_usernameTextField(),
SizedBox(height: 10.0,),
_passwordTextField(),
SizedBox(),
_loginButton()
],
),
),
);
}
}
2、结果截图
2)、课后练习
1、代码
import 'package:flutter/material.dart';
class PersonalCenterPage extends StatefulWidget {
@override
_PersonalCenterPageState createState() => _PersonalCenterPageState();
}
class _PersonalCenterPageState extends State<PersonalCenterPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: PersonalCenterContent(),
);
}
}
class PersonalCenterContent extends StatefulWidget {
@override
_PersonalCenterContentState createState() => _PersonalCenterContentState();
}
class _PersonalCenterContentState extends State<PersonalCenterContent> {
List listData = [
{"imgUrl":"assets/file_add_btn_scan.png","text":"扫一扫"},
{"imgUrl":"assets/file_add_btn_photo.png","text":"上传图片"},
{"imgUrl":"assets/file_add_btn_video.png","text":"上传视频"},
{"imgUrl":"assets/file_add_btn_note.png","text":"新建笔记"},
{"imgUrl":"assets/file_add_btn_file.png","text":"上传文档"},
{"imgUrl":"assets/file_add_btn_music.png","text":"上传音乐"},
{"imgUrl":"assets/file_add_btn_folder.png","text":"新建文件夹"},
{"imgUrl":"assets/file_add_btn_other.png","text":"上传其他文件"},
];// 数据列表
// 获取列表数据
List<Widget> _getListData(){
var list = listData.map((value){
return GridContent(value["imgUrl"],value["text"]);
});
return list.toList();
}
// 个人中心头部
Widget _personalHeader(){
return Row(
children: [
Container(
child: ClipOval(
child: Image.asset("assets/swan_app_user_portrait_pressed.png"),
),
width: 80.0,
height: 80.0,
),
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Row(
children: [
Text("移动开发",
style: TextStyle(
fontSize: 20.0,
color: Colors.grey
),
),
Container(
child: Image.asset("assets/home_identity_common.png"),
width: 25.0,
height: 25.0,
)
],
),
Container(
width: 300.0,
child: LinearProgressIndicator(
backgroundColor: Colors.grey,
value: 0.2,
valueColor: new AlwaysStoppedAnimation<Color>(Colors.blue)
),
),
Container(
alignment: Alignment(-1,0),
child: Text(
"668GB/3220GB",
style: TextStyle(
fontSize: 12.0,
color: Colors.grey
),
),
)
],
),
)
],
);
}
// 个人中心网格布局
Widget _gridViewList(){
return Container(
child: GridView.count(
crossAxisSpacing: 10,// 水平 子Widget 距离
mainAxisSpacing: 10,// 垂直 子Widget 距离
padding: EdgeInsets.all(10),
crossAxisCount: 4,// 控制一行widget的数量
childAspectRatio: 0.7,// 宽度和高度的比例
children: this._getListData(),
),
height: 400.0,
);
}
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(10),
child: Column(
children: [
SizedBox(height: 15.0,),
_personalHeader(),
SizedBox(height: 30.0,),
_gridViewList()
],
),
);
}
}
// 自定义网格组件
class GridContent extends StatelessWidget {
String imgUrl;
String text;
GridContent(this.imgUrl,this.text);
@override
Widget build(BuildContext context) {
return Container(
width: 240,
height: 240,
padding: EdgeInsets.all(10),
child: Column(
children: [
Container(
child: Image.asset(this.imgUrl),
),
// SizedBox(height: 20.0,),
Expanded(
flex: 1,
child: Text(
this.text,
style: TextStyle(
fontSize: 12.0
),
),
)
],
),
);
}
}
2、结果截图