Flutter 浅析之 登录页

技术无止境,只怕不学习啊,Flutter 我们开始吧

先上图来看一下要实现的效果:
Flutter 浅析之 登录页_第1张图片
页面结构
1.标题
2.手机号输入框
3.验证码输入框
4.获取验证码
5.60s倒计时
6.登录按钮
7.跳转到主页

下面直接上代码说明

/// (`InkWell`)可用时使用的字体样式。
final TextStyle _availableStyle = TextStyle(
  fontSize: 16.0,
  color: const Color(0xFF00CACE),
);

/// (`InkWell`)不可用时使用的样式。
final TextStyle _unavailableStyle = TextStyle(
  fontSize: 16.0,
  color: const Color(0xFFCCCCCC),
);

class LogInPage extends StatefulWidget {
  /// 倒计时的秒数,默认60秒。
  final int countdown;

  const LogInPage({Key key, this.countdown: 60}) : super(key: key);

  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return LogInPageState();
  }
} //

class LogInPageState extends State<LogInPage> {

  String _verifyStr = '获取验证码';
  /// 倒计时的计时器。
  Timer _timer;
  /// 当前倒计时的秒数。
  int _seconds;
  /// 按钮文案
  String _buttonName = "登录";
  /// 标题
  String title = "测试";

  /// 当前(`InkWell`)的字体样式。
  TextStyle inkWellStyle = _availableStyle;

  TextEditingController _userController = new TextEditingController(); // 手机号
  TextEditingController _passWordController =
      new TextEditingController(); // 验证码

  @override
  void initState() {
    super.initState();
    _seconds = widget.countdown;
  }

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return new Scaffold(
      body: new ListView(
        children: <Widget>[
          new Container(
            color: Colors.white, // 背景色
            padding: EdgeInsets.only(top: 78, left: 8, right: 17),
            child: new Column(
              crossAxisAlignment: CrossAxisAlignment.center, // 对齐方式
              children: <Widget>[
                _setTitle(title), // 设置标题
                _setAccount(),    //  账号
                _setCode(),       //  验证码
                _raisedButton()   //  按钮
              ], // 子集数组
            ),
          ),
        ], // listview 子集列表
      ), // 列表
    ); //控制整个布局添加标题 策划  顶部底部按钮等
  }

  /// 标题
  Widget _setTitle(String title) {
    return new Text(
      title,
      style: TextStyle(
          fontSize: 35, // 字体大小
          color: Colors.black // 字体颜色
          ),
    );
  }

  /// 手机号输入框
  Widget _setAccount() {
    return new Container(
      margin: EdgeInsets.only(top: 15),
      child: _createTextField(context, "请输入手机号码", 1, false, _userController),
    );
  } //

  /// 验证码输入框
  Widget _setCode() {
    return new Stack(
      children: <Widget>[
        _createTextField(context, "短信验证码", 2, true, _passWordController),
        new Container(
          height: 54.0,
          child: new Align(
            alignment: FractionalOffset.centerRight, // 右侧对齐
            child: GestureDetector(
              // 手势交互
              onTap: (){
                setState(() {
                  String user = _userController.text.toString();
                  if (user.isEmpty|!RegularMatch.isChinaPhoneLegal(user)) {
                    Fluttertoast.showToast(
                        msg: "请输入正确的电话号码!",
                        toastLength: Toast.LENGTH_SHORT,
                        gravity: ToastGravity.TOP,
                        fontSize: 12,
                        timeInSecForIos: 1);
                    return;
                  }
                  _startTimer(); // 倒计时
                });
              },
              child: new Visibility(
                  child: new Text(
                _verifyStr,
                style: TextStyle(
                  color: Colors.blue,
                  fontSize: 16,
                ),
              )),
            ),
          ), // 设置 布局的高宽适应
        ),
      ], // 子集列表
    ); // 叠加布局
  } //

  /// 登录按钮
  Widget _raisedButton() {
    return new Container(
      width: double.infinity,
      height: 45,
      margin: EdgeInsets.only(left: 19, top: 35),
      child: new RaisedButton(
        onPressed: () {
          // 点击事件
          String user = _userController.text;
          String pw = _passWordController.text;
//          RegExp exp = RegExp(
//              r'^((13[0-9])|(14[0-9])|(15[0-9])|(16[0-9])|(17[0-9])|(18[0-9])|(19[0-9]))\d{8}$');
          // 手机号校验
          if (null == user || user.length < 11 || !RegularMatch.isChinaPhoneLegal(user)) {
            Fluttertoast.showToast(
                msg: "请输入正确的电话号码!",
                toastLength: Toast.LENGTH_SHORT,
                gravity: ToastGravity.TOP);
            return;
          }
          // 验证码校验
          if (null == pw || pw.length < 4) {
            Fluttertoast.showToast(
                msg: "请输入正确的验证码!",
                toastLength: Toast.LENGTH_SHORT,
                gravity: ToastGravity.TOP);
            return;
          }
          // 路由页面跳转
          Navigator.pushNamed(
              context, '/Home'); //使用的是“命名导航路由”,具体去哪个界面,看main.dart 对应routeName('/Home')的界面
        },
        color: Color(0xff017EFF), // 按钮颜色
        shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.all(Radius.circular(5)),
        ), // 弧度
        child: new Text(
          _buttonName,
          style: TextStyle(
            color: Colors.white,
            fontSize: 17,
          ),
        ),
      ),
    );
  } //

  /// 输入框
  Widget _createTextField(BuildContext context, String hintText, int type,
      autovalidate, TextEditingController _controller) {
    return new Theme(
      data:
          new ThemeData(primaryColor: Colors.red, hintColor: Color(0xffa8afc3)),
      child: new ConstrainedBox(
        constraints: BoxConstraints(
          minHeight: 54, // 设置高度
        ),
        child: new Padding(
          padding: EdgeInsets.only(top: 19, left: 15),
          child: new TextFormField(
            obscureText: false, // 是否是密码
            controller: _controller, // 设置输入框
            keyboardType: TextInputType.number, // 唤起键盘输入方式
            inputFormatters: <TextInputFormatter>[
              LengthLimitingTextInputFormatter(1 == type ? 11 : 4)
            ], // 输入长度
            autovalidate: autovalidate, // 自我验证
            validator: (value) {
              return value.length < 4 && value.length > 0 ? "验证码长度不够4位" : null;
            }, // 输入的长度
            decoration: new InputDecoration(
              contentPadding: EdgeInsets.all(10.0),
              hintText: hintText, // 提示文案
              hintStyle: TextStyle(
                color: Color(0xffa8afc3), // 字体颜色
              ), // 提示文案的样式设置
              focusedBorder: UnderlineInputBorder(
                  borderSide: BorderSide(color: Colors.blue)), // 边框颜色
              border: UnderlineInputBorder(), // 设置装饰形状
            ),
          ),
        ),
      ),
    );
  } //

  /// 启动倒计时的计时器。
  void _startTimer() {

    if(_timer!=null){
      if(_timer.isActive){
        return;
      }
    }
    _timer = Timer.periodic(Duration(seconds: 1), (timer) {
      if (_seconds == 0) {
        _cancelTimer();
        _seconds = widget.countdown;
        inkWellStyle = _availableStyle;
        setState(() {});
        return;
      }
      _seconds--;
      _verifyStr = '${_seconds}s';
      setState(() {});
      if (_seconds == 0) {
        _verifyStr = '重新发送';
      }
    });
  } //
  /// 取消倒计时的计时器。
  void _cancelTimer() {
    // 计时器(`Timer`)组件的取消(`cancel`)方法,取消计时器。
    _timer?.cancel();
  }

} //

手机号校验

class RegularMatch{

  static const String PHONE_REG = r'^((13[0-9])|(14[0-9])|(15[0-9])|(16[0-9])|(17[0-9])|(18[0-9])|(19[0-9]))\d{8}$';
  ///校验用户手机号码
  static bool isChinaPhoneLegal(String str) {
    return new RegExp(PHONE_REG).hasMatch(str);
  }
}

Flutter 浅析之 登录页_第2张图片
主页面

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      routes: {
        '/': (BuildContext context) => new LogInPage(),
        '/Home': (BuildContext context) => new MyHomePage(title: '主页',),
      },
//      home: LogInPage(),
    );
  }
}

MyHomePage中什么界面就自己写吧
Flutter 浅析之 登录页_第3张图片

源码下载

你可能感兴趣的:(flutter,Android,IOS)