当前位置: 代码迷 >> 综合 >> flutter学习日记 -- bilibili app -- day01 书写登录界面
  详细解决方案

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

热度:22   发布时间:2023-12-13 18:54:19.0

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