在这篇文章里,我们创建一个小的RSS阅读器。当我们完成这整个过程,我们将学会如何使用最基本的控件来展示内容,并使用不同的布局。
特别提醒:在模拟器中参阅文章"怎么在Ubuntu手机中打开开发者模式"打开开发者模式,这样才可以把应用部署到模拟器中。
让我们开始吧!
1)创建一个最基本的应用框架
首先,我们来打开自己的Qt Creator来创建一个名叫“developernews”的项目。我们使用"App with Simple UI"模版。
在这里注意maintainer的格式。如果有红色的错误显示,查看一下在“<”的左边有没有留有一个空格。如果你还没有安装好自己的SDK的话,请参照文章“Ubuntu SDK 安装”来完成自己的安装。我们可以直接运行已经创建好的应用。为了显示的更像一个是一个手机的界面,我们直接把“main.qml"中的尺寸设置如下:
width: units.gu(50)
height: units.gu(75)
分辨率无关:
Ubuntu的用户界面工具包的重要功能是把用户定义多个设备尺寸进行匹配。采取的方法是定义一个新的单元类型,网格单元(简写为gu)。网格单位转换为像素值取决于应用程序运行在屏幕上和设备的类型。下面是一些例子:
Device | Conversion |
Most laptops | 1 gu = 8 px |
Retina laptops | 1 gu = 16 px |
Smart phones | 1 gu = 18 px |
我们可以点击SDK屏幕左下方的绿色的运行按钮,或使用热键(Ctrl + R),运行应用。 如下图所示:
最原始的应用其实没有什么。你可以按一下按钮改变方框中的文字。下面我们来开始设计我们的应用。
2)删除我们不需要的代码
3)加入一个PageStack
import QtQuick 2.0
import Ubuntu.Components 1.1
MainView {
// objectName for functional testing purposes (autopilot-qt5)
objectName: "mainView"
// Note! applicationName needs to match the "name" field of the click manifest
applicationName: "com.ubuntu.developer.liu-xiao-guo.developernews"
/*
This property enables the application to change orientation
when the device is rotated. The default is false.
*/
//automaticOrientation: true
width: units.gu(50)
height: units.gu(75)
PageStack {
id: pageStack
anchors.fill: parent
Component.onCompleted: {
console.log('pagestack created')
pageStack.push(listPage)
}
Page {
id: listPage
title: i18n.tr("Articles")
visile: false
}
}
}
pagestack created
这说明我们的代码是成功运行的。
4)加入我们自己的控件
4)定义ArticleListView
import QtQuick 2.0
import QtQuick.XmlListModel 2.0
import Ubuntu.Components 1.1
import Ubuntu.Components.ListItems 1.0
UbuntuListView {
id: listView
property alias status: rssModel.status
model: XmlListModel {
id: rssModel
source: "https://developer.ubuntu.com/en/blog/feeds/"
query: "/rss/channel/item"
XmlRole { name: "title"; query: "title/string()" }
XmlRole { name: "published"; query: "pubDate/string()" }
XmlRole { name: "content"; query: "description/string()" }
}
delegate: Subtitled {
text: published
subText: { return "<b>" + title + "</b>"; }
progression: true
}
// Define a highlight with customized movement between items.
Component {
id: highlightBar
Rectangle {
width: 200; height: 50
color: "#FFFF88"
y: listView.currentItem.y;
Behavior on y { SpringAnimation { spring: 2; damping: 0.1 } }
}
}
focus: true
highlight: highlightBar
Scrollbar {
flickableItem: listView
}
}
import QtQuick 2.0
ListModel {
ListElement {
title: "This is a beautiful night!"
published: "Fri, 05 Dec 2014 15:04:00 +0000"
content: "This is a beautiful night!"
}
ListElement {
title: "We miss the days we were together"
published: "Fri, 05 Dec 2014 15:04:00 +0000"
content: "We miss the days we were together"
}
ListElement {
title: "This the most wonderful thing I've had"
published: "Fri, 05 Dec 2014 15:04:00 +0000"
content: "This is a good thing I like"
}
ListElement {
title: "This is the city I like"
published: "Fri, 05 Dec 2014 15:04:00 +0000"
content: "This is the most beautiful city I've ever visited!"
}
ListElement {
title: "I enjoy the training very much"
published: "Fri, 05 Dec 2014 15:04:00 +0000"
content: "This is so nice!"
}
ListElement {
title: "I enjoy the training very much"
published: "Fri, 05 Dec 2014 15:04:00 +0000"
content: "This is so nice!"
}
ListElement {
title: "I enjoy the training very much"
published: "Fri, 05 Dec 2014 15:04:00 +0000"
content: "This is so nice!"
}
ListElement {
title: "I enjoy the training very much"
published: "Fri, 05 Dec 2014 15:04:00 +0000"
content: "This is so nice!"
}
ListElement {
title: "I enjoy the training very much"
published: "Fri, 05 Dec 2014 15:04:00 +0000"
content: "This is so nice!"
}
ListElement {
title: "I enjoy the training very much"
published: "Fri, 05 Dec 2014 15:04:00 +0000"
content: "This is so nice!"
}
ListElement {
title: "I enjoy the training very much"
published: "Fri, 05 Dec 2014 15:04:00 +0000"
content: "This is so nice!"
}
ListElement {
title: "I enjoy the training very much"
published: "Fri, 05 Dec 2014 15:04:00 +0000"
content: "This is so nice!"
}
ListElement {
title: "I enjoy the training very much"
published: "Fri, 05 Dec 2014 15:04:00 +0000"
content: "This is so nice!"
}
ListElement {
title: "I enjoy the training very much"
published: "Fri, 05 Dec 2014 15:04:00 +0000"
content: "This is so nice!"
}
ListElement {
title: "I enjoy the training very much"
published: "Fri, 05 Dec 2014 15:04:00 +0000"
content: "This is so nice!"
}
ListElement {
title: "I enjoy the training very much"
published: "Fri, 05 Dec 2014 15:04:00 +0000"
content: "This is so nice!"
}
}
UbuntuListView {
id: listView
...
model: Model {}
...
}
通过这样的方法,我们可以使得我们的练习可以做下去。对于可以链接网路的同学们来说,不需要做这个步骤。大家可以参考源码:
5)使用ArticleListView
ArticleListView {
id: articleList
objectName: "articleList"
anchors.fill: parent
clip: true
}
import "components"
6)创建一个新的Component
import QtQuick 2.0
import Ubuntu.Components 1.1
Item {
property alias text: content.text
Flickable {
id: flickableContent
anchors.fill: parent
Text {
id: content
textFormat: Text.RichText
wrapMode: Text.WordWrap
width: parent.width
}
contentWidth: parent.width
contentHeight: content.height
clip: true
}
Scrollbar {
flickableItem: flickableContent
}
}
7)把ArticleContent和app的其它内容连起来
signal clicked(var instance)
2) 在“Subtitled"项加入如下的代码:
|
|
8)添加一个reload按钮
/*
Functions can be added to any Component definition, and can be called on
using any instance of that Component. Here we will define a 'reload'
function that we can call from our main application file that will cause
the interal XmlListModel to reload it's content
*/
function reload() {
console.log('reloading')
rssModel.update()
}
挑战自己:请查看 XmlListModel。你将发现上面的"update()"方法其实不是真正的方法。请找出正确的方法替换它。
| Action是一个可以重复使用的控件,并可以在多处被引用 在这里定义并给于其一个id使得它可以在多处被引用。 |
3) 在"listPage"中,加入如下的ToolbarButton。
| 在article的contengPage,我们想显示一个toolbar按钮 在browser中打开该文章。因为我们已经定义好了一个 可以重复使用的的Action,我们只需要引用它的即可 |
9)挑战自己
ListModel {
id: model
}
XmlListModel {
id: picoRssModel
source: "http://my.poco.cn/rss_gen/poco_rss_channel.photo.php?sub_icon=figure"
query: "/rss/channel/item[child::enclosure]"
onStatusChanged: {
if (status === XmlListModel.Ready) {
for (var i = 0; i < count; i++) {
// console.log("title: " + get(i).title);
// console.log("published: " + get(i).published );
// console.log("image: " + get(i).image);
var title = get(i).title.toLowerCase();
var published = get(i).published.toLowerCase();
var content = get(i).content.toLowerCase();
var word = input.text.toLowerCase();
if ( (title !== undefined && title.indexOf( word) > -1 ) ||
(published !== undefined && published.indexOf( word ) > -1) ||
(content !== undefined && content.indexOf( word ) > -1) ) {
model.append({"title": get(i).title,
"published": get(i).published,
"content": get(i).content,
"image": get(i).image
})
}
}
}
}
XmlRole { name: "title"; query: "title/string()" }
XmlRole { name: "published"; query: "pubDate/string()" }
XmlRole { name: "content"; query: "description/string()" }
XmlRole { name: "image"; query: "enclosure/@url/string()" }
}
GridView {
id: gridview
width: parent.width
height: parent.height - inputcontainer.height
clip: true
cellWidth: parent.width/2
cellHeight: cellWidth + units.gu(1)
x: units.gu(1.2)
model: model
delegate: GridDelegate {}
Scrollbar {
flickableItem: gridview
}
}
10)玩一玩应用的一些属性
automaticOrientation: true
useDeprecatedToolbar: false
11)更多教程