flutter学习日记 -- bilibili app -- day01 书写登录界面

Flutter 学习日记 – 制作bilibili app day01

首先要做的是登录界面如下,在这里插入图片描述

如果后期有空我再进行后台开发,并逐步完善app功能,现在首先先做前台样式。

打开Android Studio 新建flutter 工程 bilibili, 代码结构如下:在这里插入图片描述,core 负责核心的一些功能,后期的http请求都放在core里,这里我在core目录目前新建了两个文件夹,一个是extension 给我们的屏幕做适配,也就是说类似于微信小程序rpx功能,如果你对这个工具感兴趣,请阅读codedr why
Pages 文件夹里存放着我们所有的页面,目前我们首先要完成login 页面。在完成页面之前,我们首先在main.dart 文件创立我们的基本骨架

import 'package:bilibili/pages/theme_style/app_theme.dart';
import 'package:bilibili/core/extension/share.dart';
import 'package:bilibili/pages/login/login.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    SizeFit.initSize();  ## 这里调用的我们extension 里面的初始化屏幕方法,以便后期我们使用里面的方法
    return MaterialApp(
      home: LoginScreen(),  ## 这里暂且这样书写,后期用到路由再将此替换即可
      theme: AppThemeStyle.normalTheme ## 我们创建的 theme 主题 存放在一个单独文件夹里,在pages/theme_style 存放我们的主题
    );
  }

}

打开 pages/theme/ 创建一个新文件 app_theme.dart 在里面我们创立 一个类 AppThemeStyle 里面友静态方法 normalTheme 用来返回我们的主题
这里注意导入

import 'package:bilibili/core/extension/int_extension.dart';
import 'package:flutter/material.dart';
class AppThemeStyle {
  static Color normalColor = Colors.white;
  static double headline1FontSize = 25.px;
  static double headline2FontSize = 30.px;
  static double headline3FontSize = 45.px;
  static double headline4FontSize = 15.px;

  static final normalTheme = ThemeData(
      primaryColor: normalColor,
      accentColor: normalColor,
      canvasColor: Color.fromARGB(255, 230, 230, 230),
      textTheme: TextTheme(
          headline1: TextStyle(fontSize: headline1FontSize, color: Colors.black87),
          headline2: TextStyle(fontSize: headline2FontSize, color: Colors.black),
          headline3: TextStyle(fontSize: headline3FontSize, color: Colors.black),
          headline4: TextStyle(fontSize: headline4FontSize, color: Colors.black)
      )
  );

}

在这里我们的主题就创建完毕了,将主题单独抽放到文件,我们后期维护代码也十分方便。
打开pages/login 创立 login.dart

 import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'login_content.dart';

class LoginScreen extends StatelessWidget {
  const LoginScreen({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Center(child: Text("密码登录"))),
      body: LoginContent(),
    );
  }
}

这里注意,我们页面的内容,在新创立的文件 login_content 进行书写,这样代码看起来比较简洁,在pages/login 创立login_content 页面 新建一个StatefulWidget,取名为LoginContent()
这里 我将登录页面划分为两个模块,这是上半模块:在这里插入图片描述

观察页面结构,上半模块和下半模块就是column 两个子组件,也就是说,我们只需要一个column 将两个包裹即可,中间那部分我们用sizebox 设置一个height 即可 在_LoginContentState build 方法里面 return

Column(
  children: [
    LoginHeader.buildLoginHeader(context, imageNum, dividerColor, focusNode),
    SizedBox(height: 50.px,),
    LoginBottom.buildLoginBottom(),
  ],
);

分别创立两个文件用来 管理两个组件, login_header 和 login_bottom

Pages 结构如下 :在这里插入图片描述打开login_header 创立类LoginHeader, 里面存放静态方法buildLoginHeader , 观察 页面,我们发现 这里面也是由一个 column 构成, 最上面图片我们只需要用Image.asset,将图片从本地加载
Image.asset("images/login/login_image0$imageNum.jpg", fit: BoxFit.fitWidth,)
其中这里用了字符串拼接,这是由于页面你输入密码时登录图片会自动切换。这种效果在这里插入图片描述

所以我将imageNum 作为参数进行传递

输入框我们则单独封装一个widget
输入框是明显的Row 左边是 container 包裹一个 Text 右边则是一个textfields, 实现代码如下

Container(
  padding: EdgeInsets.zero,
  color: Colors.white,
  child: Row(
    children: [
      Container(
          width: 150.px,
          // color: Colors.red,
          padding: EdgeInsets.only(left: 30.px),
          child: Text(title, style: Theme.of(context).textTheme.headline2)
      ),
      Expanded(
        child: TextField(
          focusNode: focusNode, ## focusNode 做为可选参数传递,判断是否点击密码输入框
          cursorColor: Colors.pinkAccent, ## 光标颜色
          obscureText: obscureText, ## 参数传递,若为true 则隐藏输入内容
          cursorHeight: 40.px, ## 光标高度
          decoration: InputDecoration(
            hintText: hintText, ## 作为参数传递, 帮助提示文字
            hintStyle: Theme.of(context).textTheme.headline1!.copyWith(color: dividerColor), ## 这里使用了主题里面的headline 的字体样式
            border: InputBorder.none, ),
        ),
      ),
    ],
  ),

整体代码

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:bilibili/core/extension/int_extension.dart';

class LoginHeader {

  static Widget buildLoginHeader(BuildContext context, imageNum, Color dividerColor, FocusNode focusNode) {
    return Column(
      children: [
        Image.asset("images/login/login_image0$imageNum.jpg", fit: BoxFit.fitWidth,),
        buildInputFields(context, "账号", "请输入手机号或邮箱", false, dividerColor),
        buildDivider(dividerColor),
        buildInputFields(context, "密码", "请输入密码", true, dividerColor, focusNode: focusNode),
        buildDivider(dividerColor)
      ],
    );
}

  static Divider buildDivider(Color dividerColor) => Divider(indent: 30.px, height: 1.px, color: dividerColor,);

  static Widget buildInputFields(BuildContext context, String title, String hintText, bool obscureText, Color dividerColor, {FocusNode? focusNode}) {
    return Container(
      padding: EdgeInsets.zero,
      color: Colors.white,
      child: Row(
        children: [
          Container(
              width: 150.px,
              // color: Colors.red,
              padding: EdgeInsets.only(left: 30.px),
              child: Text(title, style: Theme.of(context).textTheme.headline2)
          ),
          Expanded(
            child: TextField(
              focusNode: focusNode,
              cursorColor: Colors.pinkAccent,
              obscureText: obscureText,
              cursorHeight: 40.px,
              decoration: InputDecoration(
                hintText: hintText,
                hintStyle: Theme.of(context).textTheme.headline1!.copyWith(color: dividerColor),
                border: InputBorder.none, ),
            ),
          ),
        ],
      ),
    );
  }

}

封装完 header 后 我们继续封装 bottom bottom 就是两个按钮 十分简单 这里就放代码了

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:bilibili/core/extension/int_extension.dart';

class LoginBottom {
  static final mainColor = Colors.pinkAccent;
  static final fixedSize = Size(325.px, 70.px);

  static Widget buildLoginBottom() {
    return Row(
      mainAxisAlignment: MainAxisAlignment.spaceAround,
      children: [
        OutlinedButton(
          onPressed: () {},
          child: Text("注册", style: TextStyle(color: mainColor),),
          style: OutlinedButton.styleFrom(side: BorderSide(color: mainColor), fixedSize: fixedSize),
        ),
        TextButton(
            onPressed: () {},
            child: Text("登录", style: TextStyle(color: Colors.white),),
            style: TextButton.styleFrom(backgroundColor: mainColor, fixedSize: fixedSize)
        )
      ],
    );
  }

}

最后我们login_content是这样的

import 'package:bilibili/pages/login/login_bottom.dart';
import 'package:bilibili/pages/login/login_header.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:bilibili/core/extension/int_extension.dart';

class LoginContent extends StatefulWidget {
  const LoginContent({Key? key}) : super(key: key);

  @override
  _LoginContentState createState() => _LoginContentState();
}

class _LoginContentState extends State<LoginContent> {
  FocusNode focusNode = FocusNode();
  final dividerColor = Color.fromARGB(255, 190, 190, 190);
  int imageNum = 1;

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    focusNode.addListener(() { 
      if(focusNode.hasFocus) setState(() {imageNum = 2;});
      else setState(() {imageNum = 1;});
    }); ## 这里对光标焦点进行监听, 之前我们将focusNode 传递到密码框中,所以这里就可以判断focusNode.hasFocus 属性作为点击密码切换的依据
  }
  @override
  void dispose() {
    // TODO: implement dispose
    super.dispose();
    focusNode.dispose();
  }
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        LoginHeader.buildLoginHeader(context, imageNum, dividerColor, focusNode),
        SizedBox(height: 50.px,),
        LoginBottom.buildLoginBottom(),
      ],
    );
  }


}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

quzah

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值