此Demo是刚学习QtQuick时写的,看了下qml的文档后尝试的。第一次接触QtQuick是下载Qt5的时候在官网看到一个UI开发的演示,当时觉得Qt用C++还能把UI做的这么好看?花了4天时间认真学发现和界面上和C++关系不大,使用的是qml语言,取名qtquick意味快速开发出产品,所以我尝试这个Demo看看有多快。
功能需求
这个Demo实现类似iPhone的界面,仅仅类似,主屏幕可放置4x4数量的应用图标且三屏可滑动。底部可以放置单行4个应用图标,也可以左右滑动。主屏幕当前页的page indicator可以指示当前页,也可以触摸小白点翻页。以及下拉菜单。
主屏幕实现
因为是初学,所以遇到的第一个问题就是屏幕滑动的问题,想了很久的办法又是查文档又是科学谷歌。最后有一些思路:如果仅仅是能切换屏幕,就很简单,根据鼠标(手势)动作(比如在屏幕左边检测到鼠标左键按下,在屏幕右边检测到鼠标按键释放,可以判断该鼠标手势动作为向右滑动),实现隐藏或显示屏幕。但是这里需要的是滑动屏幕,滑动过程必须顺滑,并且在鼠标释放按键后页面必须刚好在显示范围内。在科学谷歌和查询文档之后,发现了自带的ListView可以完美实现主屏幕的功能。
这个功能可以不需要Listview,但是我尝试实现的效果实在不好,所以没有继续尝试。先使用现成的功能。
Listview设置如下:
ListView{
id: pageView
anchors.fill: parent
model: pageModel//数据模型
orientation: ListView.Horizontal//水平方向
snapMode: ListView.SnapOneItem//每次显示一个Item
highlightRangeMode: ListView.StrictlyEnforceRange
highlightMoveDuration: 400
cacheBuffer: 3 //cacheBuffer is not a pixel buffer,it only maintains additional instantiated delegate
}
上面那段代码功能就是将Listview水平放置,然后,snapMode属性的意思就是每滑动一次,刚好显示一个Item,也就是完整显示一个页面。如果继续用Listview再实现底部的应用栏,设置完全一样。所以,我们这里把这一块Listview的属性设置独立出来做成一个控件,在qml里面非常方便,只需要单独创建一个qml文件,然后文件名就能作为控件名,在其他qml文件中import路劲或者放在同一目录,就能直接调用,比如现在在同一目录我们创建一个PageView.qml,文件内容:
import QtQuick
ListView{
id: pageView
anchors.fill: parent
model: pageModel
orientation: ListView.Horizontal
snapMode: ListView.SnapOneItem
highlightRangeMode: ListView.StrictlyEnforceRange
highlightMoveDuration: 400
cacheBuffer: 3 //cacheBuffer is not a pixel buffer,it only maintains additional instantiated delegate
}
之后,我们在main.qml里就不需要使用Listview,直接使用PageView:
这一步就完成了UI的大体框架,完成这一步就实现了屏幕两个可滑动部分,下一步在View中显示model,就要用到对初学者来说有点难的重点内容了,model/view,以及delegate(去这个网站学习,很全面,比起中文的相关资料来说全面多了,而且其实非常好理解http://qmlbook.github.io/en/ch06/index.html)。view表示视图,就是代码最后呈现出来的视觉上的效果,比如listview:
如图所示,listview的显示效果就是这样单列多行的表,其基本单位就是一行,而model就是依托在这个view上显示,model中每一份数据都会使用listview的一行来显示。view和model相互独立,你可以把listview换成gridview,那样数据就会以下图右边的方式呈现:
model的用法不再多说,首先考虑在这里需要显示的数据,是应用图标,所以数据内容就有图标文件路径,应用名文本。因此可以单独再定义一个控件Button,新建Button.qml
import QtQuick 2.2
Rectangle {
id: button
property real buttonScale: 1
property bool pressed: false
width: 128*buttonScale
height: 144*buttonScale
color:"transparent"
//border.width: 3
property string label: ""
property string imageSource:""
signal buttonClick()
onButtonClick: {
buttonEvent.getButtonEvent(buttonLabel.text)
}
Image {
id:buttonImage
z:2
width: 120*buttonScale; height: 120*buttonScale
anchors.top: parent.top
anchors.topMargin: 8*buttonScale
anchors.horizontalCenter: parent.horizontalCenter
source: imageSource
MouseArea {
id: buttonMouseArea
hoverEnabled: true
anchors.fill: buttonImage
//onClicked: buttonClick()
onPressed: {
buttonClick()
}
}
}
Text {
id: buttonLabel
anchors.top: buttonImage.bottom
anchors.topMargin: 0
anchors.horizontalCenter: parent.horizontalCenter
font.pixelSize: 20*buttonScale;font.bold: true
color: "white"
text: label
}
}
然后将自定义的Button元素作为model的数据存放,设置delegate让model内数据以4X4格式显示。那么最后主页面呈现效果就示例图1所示了。并且每个Button(即应用图标)点击都会立马响应,格式统一。
page indicator(主屏上三个小白点)
直接上代码了:
Row {
id: mainPageIndicator
property ListView target: mainPageView
anchors.horizontalCenter: mainPageView.horizontalCenter
anchors.bottom: mainPageView.bottom
anchors.bottomMargin: 209 *windowScale
z: 1
spacing: 20*windowScale
Repeater {
opacity: 0.8
model: mainPageView.model.count
Rectangle {
width: 16*windowScale ; height: 16*windowScale
radius: 8*windowScale
color: mainPageView.currentIndex == index ? "white" : "grey"
MouseArea {
width: 20*windowScale ; height: 20*windowScale
anchors.centerIn: parent
onClicked: mainPageView.currentIndex = index
}
}
}
}
总结
博文写的没有条理,因为Demo虽然简单,但是涉及到的东西还是很多,作为初学者,还没有将这些知识系统化,所以,前言不搭后语。
Demo中用的知识技巧都是文档里面可以查询到的,个人感觉重要的事情就是一定要耐心看文档。当然google更少不了。