设计给的效果如下:
UI布局图拿到设计后,先把整体拆分成几个部分:
- “运营位”,使用自定义的旋转木马滑块组件实现可以滚动的运营位。
- “登录表单”,使用自定义的登录表单组件实现手机号、验证码登录的表单。
- “用户协议”,使用自定义的用户协议组件实现用户协议的声明文本。
然后就可以开始进行编码了。
第1步:绘制组件树
手机号登录页的组件树第2步:实现“运营位”
先把需要引用的自定义组件一次引入,carousel_with_indicator.dart
、login_form.dart
和user_agreement.dart
文件,它们分别对应《Flutter布局锦囊---轮播图片与滑块》、《Flutter布局锦囊---蜡笔画的表单》和《Flutter布局锦囊---用户协议声明》。
import 'package:flutter/material.dart';
import 'widgets/carousel_with_indicator.dart';
import 'widgets/login_form.dart';
import 'widgets/user_agreement.dart';
/// 登录页面组件。
class LoginPage extends StatefulWidget {
@override
_LoginPageState createState() => _LoginPageState();
}
实现“运营位”的UI很简单,因为在《Flutter布局锦囊---轮播图片与滑块》中,已经完成了具体的实现,你只需要调用CarouselWithIndicator
组件就可以了。
/// 与登录页面组件关联的状态子类。
class _LoginPageState extends State<LoginPage> {
@override
Widget build(BuildContext context) {
// TODO: 第4步:实现“用户协议”,实现“相对下方”布局。
// 脚手架(`Scaffold`)组件,实现基本Material设计视觉布局结构。
return Scaffold(
body: SafeArea(
child: ListView(
children: <Widget>[
CarouselWithIndicator(),
// TODO: 第3步:实现“登录表单”。
// TODO: 第4步:实现“用户协议”。
],
),
),
);
}
}
第3步:实现“登录表单”
同上,实现“登录表单”也只需要调用LoginForm
组件即可,具体实现在《Flutter布局锦囊---蜡笔画的表单》中。
// TODO: 第3步:实现“登录表单”。
LoginForm(),
第4步:实现“用户协议”
实现“用户协议”的时候比较困难,因为你需要相对于屏幕下方来放置组件。笔者没有在Flutter文档中找到能同时实现灵活布局和相对屏幕下方布局的方法,只能采取非常土的方法,先计算出屏幕上剩余的空间。
// TODO: 第4步:实现“用户协议”,实现“相对下方”布局。
/// 屏幕下方的剩余高度。
double screenHeight;
// 媒体查询(`MediaQuery`)类,建立媒体查询解析给定数据的子树,返回媒体查询数据(`MediaQueryData`)类。
// 媒体查询数据(`MediaQueryData`)类的方向(`orientation`)属性,媒体的方向,即设备是处于横向还是纵向模式。
if (MediaQuery.of(context).orientation == Orientation.portrait) {
// 媒体查询数据(`MediaQueryData`)类的大小(`size`)属性,逻辑像素中的媒体大小,即屏幕的大小。
// 媒体查询数据(`MediaQueryData`)类的填充(`padding`)属性,应用程序可以呈现的显示矩形每一侧的物理像素数。
// 填充(`padding`)属性的顶部(`top`)值是状态栏高度,底部(`bottom`)值是系统操作栏高度。
screenHeight = MediaQuery.of(context).size.height - MediaQuery.of(context).padding.top -
MediaQuery.of(context).padding.bottom - 536;
} else {
// 横屏时的高度,用于避免因为切换横竖屏导致的异常显示。
screenHeight = 82.0;
}
然后用大小框(SizedBox
)组件来占据屏幕剩余的空间,再通过垂直(Column
)组件的主轴对齐(mainAxisAlignment
)属性把UserAgreement
组件布局于屏幕下方。
// TODO: 第4步:实现“用户协议”。
// 通过大小框(`SizedBox`)组件来利用屏幕剩余的空间,实现从屏幕下方布局。
SizedBox(
height: screenHeight,
child: Align(
alignment: Alignment.bottomCenter,
child: Column(
// 垂直(`Column`)组件的主轴对齐(`mainAxisAlignment`)属性,如何将子组件放在主轴上。
mainAxisAlignment : MainAxisAlignment.end,
children: <Widget>[
UserAgreement(),
SizedBox(height: 20.0),
],
),
),
),
网友评论