目录
一、界面框架
二、首页(未登录)
三、验证码登录
四、密码登录
五、帐号注册
六、忘记密码
本项目的交流QQ群:701889554
物联网实战--入门篇https://blog.csdn.net/ypp240124016/category_12609773.html
物联网实战--驱动篇https://blog.csdn.net/ypp240124016/category_12631333.html
本项目资源文件https://download.csdn.net/download/ypp240124016/89280540
一、界面框架
从结构上看,页面内容会比较多,整体上分为两部分,一是登录页面,二是控制中心页面。现阶段是设计帐号登录相关的页面,如上图所示的绿色字体部分;控制中心页面分为首页、设备、消息和我的四部分,APP打开后首先进入首页,首页有两种状态,未登录状态和已登录状态,如果之前没登录过或者退出了,那么就进入未登录状态,需要引导用户登录;控制中心具体的放在后面来讲,现在分析下登录页面的流程。
打开后,首先展示的是未登录首页,页面中间有“前往登录”按钮,点击后会跳转到验证码登录页面,该页面有“密码登录”按钮,点击后会跳转到密码登录页面,此页面有两个文字按钮,分别是“账号注册”和“忘记密码”按钮。至此,登录相关界面就全了,在返回过程中如上图蓝色指示线所示,密码登录返回验证码登录,最后返回首页。以下是具体软件的录屏视频。
APP界面设计
下图是工程项目的界面目录结构,其中大部分是以SwipeView切换界面为主,实现不同页面之间的跳转。
以下是主页面的QML前端代码,核心是放着CenterSwipeView控制中心和LoginSwipeView登录页面,这里面有部分是捕捉安卓手机返回键的代码Keys.onPressed,逻辑是快速点击返回键几下就可以退出APP了。
import QtQuick 2.7
import QtQuick.Controls 2.0
import "base"
//主页面,可以在控制中心和登录页面之间切换
SwipeView {
id:id_mainSwipeView
anchors.fill: parent
interactive: false//禁用手滑切换
currentIndex: 0
MsgDialog01
{
id:id_msgDialog
}
property var pressTime: 0
Timer {
interval: 500; running: true; repeat: true
onTriggered:
{
if(pressTime>0)
{
pressTime--
}
}
}
Keys.onPressed:
{
if(event.key === Qt.Key_Back)
{
console.log("login Key_Back!")
if(pressTime>0)
{
console.log("app quit!")
Qt.quit()
}
else
{
pressTime=2
event.accepted = true;
id_msgDialog.funOpen("再按一次退出!")
}
}
}
CenterSwipeView //控制中心界面
{
id:id_centerSwipeView
}
LoginSwipeView //登录界面
{
id:id_loginSwipeView
onSiqLoginBackLevel1://登录界面返回按钮
{
id_mainSwipeView.currentIndex=0
}
}
Component.onCompleted:
{
}
Connections
{
target: theAccountMan
onSiqSetLoginState:
{
console.log("set login state=", state)
if(state>0)//登录成功
{
id_mainSwipeView.currentIndex=0
}
else//去登录
{
id_mainSwipeView.currentIndex=1
}
}
onSiqShowMsg:
{
id_msgDialog.funOpen(msg)
}
}
function funSetFocus()
{
focus=true
}
}
二、首页(未登录)
这是未登录的首页页面,第一次打开APP便是这个页面,目的是引导用户注册和登录,布局也相对简洁,LOGO+设备背景图+按钮,点击前往登录 按钮就能进入下一个页面,下面是具体代码。两者结合起来看,其实QML代码也是非常简单的,核心作用还是布局。代码里有三个注意点,一个是使用Gradient产生渐变色,这样背景比较不会单调;二是开头import "../base"引入了base文件夹,里面放着一些常用的、定制化的基础模块,比如这里的BaseButton02,就是圆角按钮;三是在BaseButton02内部的前后端交互接口theAccountMan,这个是在C++主程序里定义的。
import QtQuick 2.7
import QtQuick.Controls 2.0
import "../base"
//未登录home画面
Rectangle {
anchors.fill: parent
gradient: Gradient {
GradientStop { position: 0.0; color: "#CFD5E6" }
GradientStop { position: 1.0; color: "#F5F6F8" }
}
//LOGO
Image
{
id: id_logoImg
width: height
height: 40
mipmap: true
anchors
{
left:parent.left
leftMargin:width*0.3
top:parent.top
topMargin:height*0.2
}
source: "qrc:/mainImgRC/images/logo.png"
}
Label{
id:id_headLabel
height: id_logoImg.height
width: height*4
anchors
{
verticalCenter:id_logoImg.verticalCenter
left:id_logoImg.right
leftMargin:10
}
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignLeft
font.pointSize: height*0.40
font.family:"宋体"
color: "black"
text:"端点物联M2M Lite"
}
Label{
id:id_myDevLabel
height: id_logoImg.height
width: height*4
anchors
{
bottom:id_centerRect.top
bottomMargin:5
left:id_centerRect.left
leftMargin:10
}
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignLeft
font.pointSize: height*0.45
font.family:"宋体"
color: "black"
text:"我的设备"
}
Rectangle //中心登录空白矩形
{
id:id_centerRect
width:parent.width*0.9
radius:10
anchors
{
top:id_logoImg.bottom
topMargin:id_logoImg.height*2
horizontalCenter:parent.horizontalCenter
bottom:parent.bottom
bottomMargin:20
}
Image //冰箱等智能家居设备图片
{
id: id_devicesImg
width: parent.width*0.8
height: width/1.6
mipmap: true
anchors
{
horizontalCenter:parent.horizontalCenter
top:parent.top
topMargin:parent.height*0.08
}
source: "qrc:/mainImgRC/images/home/home_devices.png"
}
BaseButton02
{
height: 50
width: 150
buttonText: "前往登录"
anchors
{
horizontalCenter:parent.horizontalCenter
bottom:parent.bottom
bottomMargin:height*3
}
onSiqClickedLeft:
{
theAccountMan.setLoginState(0)
}
}
}
}
三、验证码登录
import QtQuick 2.7
import QtQuick.Controls 2.0
import "../base"
//验证码登录界面
Rectangle {
signal siqLoginBackLevel0()
signal siqGotoPasswdLogin()
MsgDialog01
{
id:id_msgDialog
}
Keys.onPressed:
{
if(event.key === Qt.Key_Back)
{
console.log("phone Key_Back!")
event.accepted = true;
siqLoginBackLevel0()
}
}
ImageButton01//返回按钮
{
source: "qrc:/mainImgRC/images/login/back.png"
anchors
{
left:parent.left
leftMargin:20
top:parent.top
topMargin:20
}
onSiqClickedLeft:
{
siqLoginBackLevel0()
}
}
HeadView
{
id:id_headView
textValue: "手机验证码登录"
anchors
{
horizontalCenter:parent.horizontalCenter
top:parent.top
topMargin:80
}
}
BaseText01
{
id:id_phoneText
height: 50
width: parent.width*0.8
anchors
{
horizontalCenter:parent.horizontalCenter
top:id_headView.bottom
topMargin:30
}
placeholderText: "请输入手机号"
maximumLength: 11
}
VerCodeView//验证码模块
{
id:id_verCodeView
height: id_phoneText.height
agreeCheckState: id_userAgreement.checkState
phoneNumber: id_phoneText.text
anchors
{
horizontalCenter:parent.horizontalCenter
top:id_phoneText.bottom
topMargin:10
}
}
BaseButton02
{
id:id_loginButton
height: id_phoneText.height
width: id_phoneText.width
anchors
{
horizontalCenter:parent.horizontalCenter
top:id_verCodeView.bottom
topMargin:10
}
buttonText: "登录"
onSiqClickedLeft:
{
if(id_userAgreement.checkState==0)
{
id_msgDialog.funOpen("请先同意用户协议!")
return
}
var ok=theAccountMan.isPhoneNumber(id_phoneText.text)
if(!ok)
{
id_msgDialog.funOpen("请输入正确的手机号!")
return
}
ok=theAccountMan.isNumber(id_verCodeView.verCode)
if(ok!==4)
{
id_msgDialog.funOpen("请输入正确的验证码!")
return
}
theAccountMan.requestLoginByVerCode(id_phoneText.text, id_verCodeView.verCode)
}
}
UserAgreement//隐私政策
{
id:id_userAgreement
anchors
{
left:id_phoneText.left
top:id_loginButton.bottom
topMargin:10
}
}
BaseButton02
{
id:id_switchButton
height: id_phoneText.height
width: id_phoneText.width
releaseColor: "#F0F0F0"
pressedColor: "#E0E0E0"
buttonColor:"#505050"
anchors
{
horizontalCenter:parent.horizontalCenter
top:id_userAgreement.bottom
topMargin:30
}
buttonText: "密码登录>>"
onSiqClickedLeft:
{
siqGotoPasswdLogin()
}
}
}
这个页面几乎是用的base里的页面模块,HeadView是LOGO+标题模块,内容可以更改;BaseText01是文字输入模块,用户名、密码什么的都是用的这个模块;VerCodeView是验证码模块,包含了文字输入模块和按钮模块;还有个隐私政策模块UserAgreement,这在跟账户操作上都需要用到的模块,包括注册、登录、改密码等等;最后,还有个返回按钮ImageButton01,点击后返回到首页,与捕捉返回键的功能一样。在页面底部,有个按钮模块,是切换到账户密码登录方式用的,从这里也可以看出,现在主流的APP都是默认提倡直接手机登录的,对C端用户比较友好便捷。
四、密码登录
import QtQuick 2.7
import QtQuick.Controls 2.0
import "../base"
//账号密码登录页面
//还有注册和忘记密码两个切换页面
SwipeView {
signal siqPasswdBackLevel0()
id:id_passwdSwipeView
interactive: false//禁用手滑切换
MsgDialog01
{
id:id_msgDialog
}
Keys.onPressed:
{
if(event.key === Qt.Key_Back)
{
console.log("passwd Key_Back!")
event.accepted = true;
siqPasswdBackLevel0()
}
}
Rectangle{ //账号密码登录页面
ImageButton01//返回到验证码登录页面
{
id:id_backButton
source: "qrc:/mainImgRC/images/login/back.png"
anchors
{
left:parent.left
leftMargin:20
top:parent.top
topMargin:20
}
onSiqClickedLeft:
{
siqPasswdBackLevel0()
}
}
HeadView
{
id:id_headView
textValue: "密码登录"
anchors
{
horizontalCenter:parent.horizontalCenter
top:parent.top
topMargin:60
}
}
BaseText01//账户
{
id:id_accountText
height: 50
width: parent.width*0.8
anchors
{
horizontalCenter:parent.horizontalCenter
top:id_headView.bottom
topMargin:30
}
placeholderText: "用户名/手机号"
maximumLength: 30
}
BaseText01//密码
{
id:id_passwdText
height: id_accountText.height
width: id_accountText.width
anchors
{
horizontalCenter:parent.horizontalCenter
top:id_accountText.bottom
topMargin:10
}
placeholderText: "密码"
maximumLength: 30
echoMode: TextInput.Password//密码模式
}
UserAgreement//隐私政策
{
id:id_userAgreement
anchors
{
left:id_passwdText.left
top:id_passwdText.bottom
topMargin:10
}
}
BaseButton02//登录按钮
{
id:id_loginButton
height: id_passwdText.height
width: id_passwdText.width
anchors
{
horizontalCenter:parent.horizontalCenter
top:id_userAgreement.bottom
topMargin:10
}
buttonText: "登录"
onSiqClickedLeft:
{
if(id_userAgreement.checkState==0)
{
id_msgDialog.funOpen("请先同意用户协议!")
return
}
theAccountMan.requestLogin(id_accountText.text, id_passwdText.text, 1)
}
}
Rectangle{ //注册+忘记密码 行
width: parent.width*0.55
height: 40
anchors
{
horizontalCenter:parent.horizontalCenter
top:id_loginButton.bottom
topMargin:30
}
TextButton01{
id:id_regText
textValue: "注册"
textColor: "#303030"
anchors
{
verticalCenter:parent.verticalCenter
left:parent.left
}
onSiqClickedLeft:
{
id_passwdSwipeView.currentIndex=1//跳转页面
}
}
TextButton01{
id:id_forgetText
textValue: "忘记密码"
textColor: "#303030"
anchors
{
verticalCenter:parent.verticalCenter
right:parent.right
}
onSiqClickedLeft:
{
id_passwdSwipeView.currentIndex=2//跳转页面
}
}
}
}
RegView //账号注册
{
onSiqGoBackLevel0:
{
id_passwdSwipeView.currentIndex=0
}
}
ForgetView //忘记密码
{
onSiqGoBackLevel0:
{
id_passwdSwipeView.currentIndex=0
}
}
}
因为有注册和忘记密码两个页面需要切换,所以开头需要使用SwipeView,把密码登录页面收缩起来就是下图的样子,本质上就是3个页面进行切换。密码登录页面跟验证码登录类似,就是内容上有些差异,其中的TextButton01是文字按钮,注册和忘记密码靠这个按钮进行切换的。
五、帐号注册
import QtQuick 2.7
import QtQuick.Controls 2.0
import "../base"
//注册帐号页面
Rectangle {
signal siqGoBackLevel0()
MsgDialog01
{
id:id_msgDialog
}
Keys.onPressed:
{
if(event.key === Qt.Key_Back)
{
console.log("reg Key_Back!")
event.accepted = true;
siqGoBackLevel0()
}
}
ImageButton01
{
source: "qrc:/mainImgRC/images/login/back.png"
anchors
{
left:parent.left
leftMargin:20
top:parent.top
topMargin:20
}
onSiqClickedLeft:
{
siqGoBackLevel0()
}
}
HeadView
{
id:id_headView
textValue: "帐号注册"
anchors
{
horizontalCenter:parent.horizontalCenter
top:parent.top
topMargin:60
}
}
BaseText01
{
id:id_accountText
height: 50
width: parent.width*0.8
anchors
{
horizontalCenter:parent.horizontalCenter
top:id_headView.bottom
topMargin:30
}
placeholderText: "请输入用户名"
maximumLength: 30
}
BaseText01//密码
{
id:id_passwdText
height: id_accountText.height
width: id_accountText.width
anchors
{
horizontalCenter:parent.horizontalCenter
top:id_accountText.bottom
topMargin:10
}
placeholderText: "输入密码"
maximumLength: 30
echoMode: TextInput.Password//密码模式
}
BaseText01//确认密码
{
id:id_confirmText
height: id_accountText.height
width: id_accountText.width
anchors
{
horizontalCenter:parent.horizontalCenter
top:id_passwdText.bottom
topMargin:10
}
placeholderText: "确认密码"
maximumLength: 30
echoMode: TextInput.Password//密码模式
}
BaseText01
{
id:id_phoneText
height: 50
width: parent.width*0.8
anchors
{
horizontalCenter:parent.horizontalCenter
top:id_confirmText.bottom
topMargin:10
}
placeholderText: "请输入手机号"
maximumLength: 11
}
VerCodeView//验证码模块
{
id:id_verCodeView
height: id_phoneText.height
agreeCheckState: id_userAgreement.checkState
phoneNumber: id_phoneText.text
anchors
{
horizontalCenter:parent.horizontalCenter
top:id_phoneText.bottom
topMargin:10
}
}
UserAgreement//隐私政策
{
id:id_userAgreement
anchors
{
left:id_verCodeView.left
top:id_verCodeView.bottom
topMargin:10
}
}
BaseButton02//注册按钮
{
id:id_loginButton
height: id_passwdText.height
width: id_passwdText.width
anchors
{
horizontalCenter:parent.horizontalCenter
top:id_userAgreement.bottom
topMargin:10
}
buttonText: "立即注册"
onSiqClickedLeft:
{
if(id_userAgreement.checkState==0)
{
id_msgDialog.funOpen("请先同意用户协议!")
return
}
var result=theAccountMan.checkAccount(id_accountText.text)
if(result===1)
{
id_msgDialog.funOpen("账户名长度不能小于5!")
return
}
else if(result===2)
{
id_msgDialog.funOpen("不能以admin作为账户名!")
return
}
else if(result===3)
{
id_msgDialog.funOpen("不能纯数字作为账户名!")
return
}
result=theAccountMan.checkPasswd(id_passwdText.text)
if(result===1)
{
id_msgDialog.funOpen("密码长度要大于8!")
return
}
if(id_passwdText.text!==id_confirmText.text)
{
id_msgDialog.funOpen("两次密码不一致!")
return
}
var ok=theAccountMan.isPhoneNumber(id_phoneText.text)
if(!ok)
{
id_msgDialog.funOpen("请输入正确的手机号!")
return
}
ok=theAccountMan.isNumber(id_verCodeView.verCode)
if(ok!==4)
{
id_msgDialog.funOpen("请输入正确的验证码!")
return
}
theAccountMan.requestReg(id_accountText.text, id_passwdText.text, id_phoneText.text, id_verCodeView.verCode, )
}
}
}
帐号注册内容比较多,但是基本就是那几个基础模块的组合了,没什么特殊的东西。基本逻辑是用手机验证码的形式注册新账户。
六、忘记密码
import QtQuick 2.7
import QtQuick.Controls 2.0
import "../base"
//忘记密码页面
Rectangle {
signal siqGoBackLevel0()
MsgDialog01
{
id:id_msgDialog
}
Keys.onPressed:
{
if(event.key === Qt.Key_Back)
{
console.log("forget Key_Back!")
event.accepted = true;
siqGoBackLevel0()
}
}
ImageButton01
{
source: "qrc:/mainImgRC/images/login/back.png"
anchors
{
left:parent.left
leftMargin:20
top:parent.top
topMargin:20
}
onSiqClickedLeft:
{
siqGoBackLevel0()
}
}
HeadView
{
id:id_headView
textValue: "重置密码"
anchors
{
horizontalCenter:parent.horizontalCenter
top:parent.top
topMargin:60
}
}
BaseText01
{
id:id_accountText
height: 50
width: parent.width*0.8
anchors
{
horizontalCenter:parent.horizontalCenter
top:id_headView.bottom
topMargin:30
}
placeholderText: "请输入用户名"
maximumLength: 30
}
BaseText01//密码
{
id:id_passwdText
height: id_accountText.height
width: id_accountText.width
anchors
{
horizontalCenter:parent.horizontalCenter
top:id_accountText.bottom
topMargin:10
}
placeholderText: "输入密码"
maximumLength: 30
echoMode: TextInput.Password//密码模式
}
BaseText01//确认密码
{
id:id_confirmText
height: id_accountText.height
width: id_accountText.width
anchors
{
horizontalCenter:parent.horizontalCenter
top:id_passwdText.bottom
topMargin:10
}
placeholderText: "确认密码"
maximumLength: 30
echoMode: TextInput.Password//密码模式
}
BaseText01
{
id:id_phoneText
height: 50
width: parent.width*0.8
anchors
{
horizontalCenter:parent.horizontalCenter
top:id_confirmText.bottom
topMargin:10
}
placeholderText: "请输入手机号"
maximumLength: 11
}
VerCodeView//验证码模块
{
id:id_verCodeView
height: id_phoneText.height
agreeCheckState: id_userAgreement.checkState
phoneNumber: id_phoneText.text
anchors
{
horizontalCenter:parent.horizontalCenter
top:id_phoneText.bottom
topMargin:10
}
}
UserAgreement//隐私政策
{
id:id_userAgreement
anchors
{
left:id_verCodeView.left
top:id_verCodeView.bottom
topMargin:10
}
}
BaseButton02//重置按钮
{
id:id_loginButton
height: id_passwdText.height
width: id_passwdText.width
anchors
{
horizontalCenter:parent.horizontalCenter
top:id_userAgreement.bottom
topMargin:10
}
buttonText: "立即重置"
onSiqClickedLeft:
{
if(id_userAgreement.checkState==0)
{
id_msgDialog.funOpen("请先同意用户协议!")
return
}
var result=theAccountMan.checkAccount(id_accountText.text)
if(result===1)
{
id_msgDialog.funOpen("账户名长度不能小于5!")
return
}
else if(result===2)
{
id_msgDialog.funOpen("不能以admin作为账户名!")
return
}
result=theAccountMan.checkPasswd(id_passwdText.text)
if(result===1)
{
id_msgDialog.funOpen("密码长度要大于8!")
return
}
if(id_passwdText.text!==id_confirmText.text)
{
id_msgDialog.funOpen("两次密码不一致!")
return
}
var ok=theAccountMan.isPhoneNumber(id_phoneText.text)
if(!ok)
{
id_msgDialog.funOpen("请输入正确的手机号!")
return
}
ok=theAccountMan.isNumber(id_verCodeView.verCode)
if(ok!==4)
{
id_msgDialog.funOpen("请输入正确的验证码!")
return
}
theAccountMan.requestResetPasswd(id_accountText.text, id_passwdText.text, id_phoneText.text, id_verCodeView.verCode)
}
}
}
与账户注册类似,也需要手机验证码进行身份确认。