Flutter布局锦囊---手机号登录页

设计给的效果如下:

UI布局图

拿到设计后,先把整体拆分成几个部分:

  1. “运营位”,使用自定义的旋转木马滑块组件实现可以滚动的运营位。
  2. “登录表单”,使用自定义的登录表单组件实现手机号、验证码登录的表单。
  3. “用户协议”,使用自定义的用户协议组件实现用户协议的声明文本。

然后就可以开始进行编码了。

第1步:绘制组件树

手机号登录页的组件树

第2步:实现“运营位”

先把需要引用的自定义组件一次引入,carousel_with_indicator.dartlogin_form.dartuser_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),
                  ],
                ),
              ),
            ),

第5步:还原效果

手机号登录页的还原效果

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 酷酷鲨 设计师:CSDN官方博客 返回首页