Flutter布局练习

练习布局

  前段时间Flutter的文章超多,再加上以前的同事也在开始使用Flutter开发项目了,为了积累吹NB的资料,不得不了解一下,然后写个练习练练手。总体感觉还不错,虽然这类文章也很多。但毕竟是别人学习后的总结,跟自己敲一遍的理解是没法比的。看着永远比做着简单。(就像这段文字的缩进,之前我一直都用的全角空格。直到后来失效我才发现原来两个 就能实现这样的效果,当然还有别的方式)。
  废话不多说,撸个下面的界面就完事。
Flutter布局练习_第1张图片

1.分析

  先来分析一个这个界面。真没啥好分析的,最简单的就是一个线性布局,然后往里扔子控件就行了。当然Flutter中也用类似的控件。这里我选用ListView,为啥不用Column。因为在这个布局中如果用Column包裹TextField,当弹出键盘时会出现遮挡,而ListView是可滚动的不会出现遮挡,这里我懒得深入研究,所以投机取巧了。所以这界面就可以这么弄了,使用ListView作为子控件的容器,让后一次往里放图片,输入框和按钮就能完成这个界面。

2.定义一个输入框

  为了体现出练习的作用,当然这是借口。因为我没找到如何修改TextField边框高度的方法,所以在TextField外又包了一层。功能很简单就是当TextField焦点发生改变的时候,改变一下边框的颜色。下面直接甩出代码:

///输入控件
class MyInputView extends StatefulWidget {
  final TextEditingController controller;
  final bool obscureText;
  final String hintText;
  final StatelessWidget icon;

  MyInputView(this.hintText, this.icon,
      this.controller, {this.obscureText = false});

  @override
  State<StatefulWidget> createState() {
    return MyInputViewState(
        hintText, icon, obscureText, controller);
  }
}

///输入控件的状态控制器
class MyInputViewState extends State<MyInputView> {
  final controller;
  final obscureText;
  final hintText;
  final icon;
  final focusNode = FocusNode();

  MyInputViewState(this.hintText, this.icon,
      this.obscureText, this.controller);

  ///边框的默认颜色
  var borderColor = Colors.grey;
  var inputBorder;

  @override
  Widget build(BuildContext context) {
    ///监听输入框的焦点变化
    focusNode.addListener(() {
      setState(() {
        borderColor = focusNode.hasFocus ? Theme
            .of(context)
            .primaryColor : Colors.grey;
      });
    });
    ///设置边框
    inputBorder = BoxDecoration(
        border: Border.all(
          color: borderColor,
          width: 1.5,
        ),
        borderRadius: BorderRadius.all(
            Radius.circular(10.0)
        )
    );
    return Container(
      child: createInputView(
          hintText, icon, controller, obscureText),
    );
  }

  ///创建输入框
  createInputView(hint, icon, controller, obscureText) {
    return Container(
        padding: EdgeInsets.only(left: 10.0),
        child: TextField(
          focusNode: focusNode,
          controller: controller,
          decoration: InputDecoration(
              icon: icon,
              hintText: hint,
              border: InputBorder.none
          ),
          obscureText: obscureText,
        ),
        decoration: inputBorder
    );
  }
}

  为了证明这段代码还有点作用,我们来对比一下。先把控件放到界面中,然后运行看一下效果。

import 'package:flutter/material.dart';

void main() =>
    runApp(MaterialApp(
      home: MyApp(),
    ));

class MyApp extends StatelessWidget {

  final titleStyle = TextStyle(fontSize: 20.0);
  final titleColor = Colors.blue;

  @override
  Widget build(BuildContext context) =>
      Scaffold(
          appBar: AppBar(
              title: Text('对比'),
              centerTitle: true
          ),
          body: Padding(
            padding: EdgeInsets.all(10.0), //设置边距
            child: Column(
                mainAxisAlignment: MainAxisAlignment.center, //内容居中
                children: <Widget>[
                  createTitle('自定义的输入框'),
                  MyInputView(
                      '请输入姓名',
                      Icon(Icons.person),
                      TextEditingController()
                  ),
                  SizedBox(height: 10.0),
                  createTitle('默认的输入框'),
                  TextField(
                    decoration: InputDecoration(
                        hintText: '请输入姓名',
                        prefixIcon: Icon(Icons.person),
                        border: OutlineInputBorder()
                    ),
                  )
                ]
            ),
          )
      );

  createTitle(String title) =>
      Title(
          child: Text(title, style: titleStyle),
          color: titleColor);
}

  效果如下,自我感觉良好。
Flutter布局练习_第2张图片

3.完成练习

  接下来就好整了,向布局中依次添加logo、输入框和按钮。然后稍微优化一下布局,比如让子控件之间有点距离啥的。这样一个简单的登录界面就完成了。代码很简单,就是有点迷之缩进看着有点恶心。

import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';

void main() =>
    runApp(MaterialApp(
      home: MyApp(),
    ));

///登录界面
class MyApp extends StatelessWidget {

  final userNameController = TextEditingController();
  final passwordController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    const paddingValue = 30.0;
    var padding = Padding(
        padding: EdgeInsets.only(left: paddingValue, right: paddingValue),
        child: createColumn(context));
    return Scaffold(
        appBar: AppBar(
          title: Text('登录页'),
          centerTitle: true,
        ),
        body: padding
    );
  }

  ///设置界面中的视图效果
  createColumn(context) {
    return ListView(
      children: <Widget>[
        createColumnDriver(20.0),
        ///1、图片Logo
        Image.asset(
          'images/fish.png',
          color: Theme
              .of(context)
              .primaryColor,
          height: 160.0,
        ),
        createColumnDriver(20.0),
        ///2、用户输入框
        MyInputView(
            '请输入姓名', ImageIcon(AssetImage('images/userName_icon.png')),
            userNameController
        ),
        createColumnDriver(20.0),
        ///3、密码输入框
        MyInputView(
          '请输入密码', ImageIcon(AssetImage('images/password_icon.png')),
          passwordController,
          obscureText: true,
        ),
        createColumnDriver(30.0),
        ///4、登录按钮
        createLoginBtn(context)
      ],
    );
  }

  ///垂直间隔
  createColumnDriver(double height) => SizedBox(height: height);

  ///登录按钮
  createLoginBtn(context) {
    var loginBtn = RaisedButton(
      child: Padding(
        padding: EdgeInsets.all(10.0),
        child: Text('登录',
          style: TextStyle(
              fontSize: 15.0,
              fontWeight: FontWeight.bold
          ),
        ),
      ),
      onPressed: () =>
          Fluttertoast.showToast(
              msg: '账号:${userNameController.text}\n密码:${passwordController.text}'),
      textColor: Colors.white,
      highlightColor: Theme
          .of(context)
          .primaryColorDark,
      color: Theme
          .of(context)
          .primaryColor,
      shape: StadiumBorder(),
    );
    return Row(children: <Widget>[
      Expanded(
        child: loginBtn,
      )
    ]);
  }
}

  在输入框中输入内容,然后点击按钮。弹出一个Toast显示我们输入的内容。
Flutter布局练习_第3张图片

注意

  Fluttertoast这个是第三方库,多了不说反正很好用。

你可能感兴趣的:(Flutter练习记录)