Qt Quick中有個(gè)StackView,我在《Qt Quick核心編程》一書中沒有講到,最近有人問起,趁機(jī)學(xué)習(xí)了一下,把它的基本用法記錄下來。
我準(zhǔn)備分兩次來講。第一次講基本的用法,包括StackView的適用場(chǎng)景、基本屬性和方法的用法。第二次講一些稍微復(fù)雜點(diǎn)的東西,比如被StackView管理的view的生命周期、delegate定制、查找等。
示例會(huì)用到動(dòng)態(tài)創(chuàng)建組建,可以參考我之前的文章“Qt Quick 組件與對(duì)象動(dòng)態(tài)創(chuàng)建詳解”。也會(huì)用到錨布局,參考“Qt Quick 布局介紹”。還會(huì)用到Button、Rectangle、MouseArea、Text等基本元素,請(qǐng)參考《Qt Quick核心編程》一書。
StackView介紹
StackView實(shí)現(xiàn)了一個(gè)棧式的導(dǎo)航。“棧”大家都知道是怎么回事兒,就是一種數(shù)據(jù)結(jié)構(gòu),先進(jìn)后出(FILO),支持pop、push等操作。StackView用于棧類似的行為方式管理一系列的View(頁(yè)面或視圖),這些View之間可能有內(nèi)在聯(lián)系,根據(jù)業(yè)務(wù)需要,可以一級(jí)一級(jí)向深處的跳轉(zhuǎn),當(dāng)前的View上發(fā)生點(diǎn)兒什么事兒,就可能會(huì)產(chǎn)生一個(gè)新的View或返回之前的頁(yè)面。
舉兩個(gè)簡(jiǎn)單的場(chǎng)景。
比如注冊(cè)賬號(hào)這個(gè)場(chǎng)景,有一種做法是分幾個(gè)步驟,比如第一步先讓你輸入用戶名、密碼,你點(diǎn)擊下一步之后呢,會(huì)出現(xiàn)新的頁(yè)面,接著讓你輸入姓名、愛好、郵箱、社交方式等。
比如你在某個(gè)招聘網(wǎng)站提交簡(jiǎn)歷,先是填寫基本信息,如姓名、畢業(yè)院校、聯(lián)系方式、求職意向等,然后下一步,就讓你添加工作經(jīng)驗(yàn)……一路Next下去即可。說到這里你可以看看我之前寫的一篇文章,史上最全的程序員求職渠道總結(jié)。
StackView是FocusScope的子類,F(xiàn)ocusScope是Item的子類。從這個(gè)繼承關(guān)系來看,StackView要作為一個(gè)Window的孩子(孩子的孩子也可以,孩子的孩子的孩子也可以……)來使用。當(dāng)然如果你用QQuickView來加載main.qml的話,StackView也可以作為main.qml的根節(jié)點(diǎn),不必嵌套在一個(gè)Window里。
StackView有幾個(gè)屬性:
- busy 指示StackView是否正在應(yīng)用過渡動(dòng)畫,為true時(shí)表示正在應(yīng)用動(dòng)畫??梢酝ㄟ^屬性變化信號(hào)處理器onBusyChanged來響應(yīng)busy屬性變化,結(jié)合我們的業(yè)務(wù)需求來做一些處理,比如在動(dòng)畫期間禁止用戶點(diǎn)擊。
- currentItem 指向棧頂?shù)腣iew(Item),可能為空。
- delegate 用于定制頁(yè)面切換時(shí)的過渡動(dòng)畫。
- depth 棧的深度,StackView中沒有子頁(yè)面時(shí),depth為0,有一個(gè)子頁(yè)面時(shí),depth為1……
- initialItem 初始的View(Item)。我們可以通過這個(gè)屬性來指定StackView管理的第一個(gè)頁(yè)面(View),如果你在初始化時(shí)給initalItem賦值,效果就相當(dāng)于我們?cè)贑omponent.onCompleted信號(hào)處理器中調(diào)用 push(yourItem)。如果你不顯式給initalItem賦值,當(dāng)?shù)谝粋€(gè)頁(yè)面被push進(jìn)StackView時(shí),這個(gè)屬性也會(huì)被自動(dòng)賦值。
StackView有幾個(gè)方法:
- clear(),顧名思義,干掉StackView管理的所有頁(yè)面
- pop(item),出棧操作。無參調(diào)用pop時(shí),講棧頂?shù)捻?yè)面彈出。如果帶參數(shù),則將參數(shù)指定的頁(yè)面之后的所有頁(yè)面都彈出。舉個(gè)例子吧,現(xiàn)在棧內(nèi)頁(yè)面時(shí)醬紫的,[A,B,C,D,E],pop()調(diào)用后,就變?yōu)閇A,B,C,D]。你再調(diào)用pop(B),就會(huì)變成[A,B]。
- push(item),入棧操作,參數(shù)是Item,將一個(gè)頁(yè)面壓入StackView。這個(gè)頁(yè)面(Item)一般是動(dòng)態(tài)創(chuàng)建的。待會(huì)兒我們的示例可以看到。有一個(gè)特別的用法,可以替換棧頂元素,比如你的棧是[A,B,C,D],push(E, replace),就會(huì)用E替換棧頂?shù)腄,棧就會(huì)變?yōu)閇A,B,C,E]。關(guān)于push,還有一些其它用法,參考Qt幫助吧。
- find(func, onlySearchLoadedItems),查找StackView管理的某個(gè)頁(yè)面。find將對(duì)棧內(nèi)的每個(gè)頁(yè)面應(yīng)用func方法,當(dāng)func返回true時(shí),表示找到了,查找過程就會(huì)停止,然后find會(huì)返回找到的那個(gè)Item。
- completeTransition(),立即結(jié)束過渡動(dòng)畫。
再啰嗦幾句吧。StackView本身其實(shí)是一個(gè)正常的Item,這從它的類繼承關(guān)系可以看出來。所以呢,你可以指定它的大小(width、height),也可以使用anchors等布局。StackView管理的頁(yè)面,都會(huì)作為StackView的孩子,這些子View們,默認(rèn)會(huì)充滿StackView的可用區(qū)域,我們不能使用anchors來布局子頁(yè)面,假如你為子View使用了anchors,那頁(yè)面切換時(shí)的動(dòng)畫效果就會(huì)失效。還有一點(diǎn),指定子頁(yè)面的大?。╳idth、height)也不管用。所以,省事兒啦。
StackView示例
設(shè)計(jì)了一個(gè)非常簡(jiǎn)單的示例,效果如下圖所示:

我們看到,在上面的GIF中,點(diǎn)擊Next按鈕會(huì)新創(chuàng)建一個(gè)頁(yè)面并將這個(gè)頁(yè)面加入到StackView中,頁(yè)面切換時(shí)有一個(gè)動(dòng)畫效果。這個(gè)動(dòng)畫效果是StackView提供的默認(rèn)效果,如果我們想改變它,就可以通過delegate屬性來定制。
所有代碼在這里了:
import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Window 2.2
Window {
title: "StackViewDemo";
width: 480;
height: 320;
visible: true;
StackView {
id: stack;
anchors.centerIn: parent;
width: 600;
height: 300;
property var home: null;
Text {
text: "Click to create first page";
font.pointSize: 14;
font.bold: true;
color: "blue";
anchors.centerIn: parent;
MouseArea {
anchors.fill: parent;
onClicked: if(stack.depth == 0)stack.push(page);
}
}
}
Component {
id: page;
Rectangle {
color: Qt.rgba(stack.depth*0.1, stack.depth*0.2, stack.depth*0.3);
Text {
anchors.centerIn: parent;
text: "depth - " + stack.depth;
font.pointSize: 24;
font.bold: true;
color: stack.depth <= 4 ? Qt.lighter(parent.color) : Qt.darker(parent.color);
}
Button {
id: next;
anchors.right: parent.right;
anchors.bottom: parent.bottom;
anchors.margins: 8;
text: "Next";
width: 70;
height: 30;
onClicked: {
if(stack.depth < 8) stack.push(page);
}
}
Button {
id: back;
anchors.right: next.left;
anchors.top: next.top;
anchors.rightMargin: 8;
text: "Back";
width: 70;
height: 30;
onClicked: {
if(stack.depth > 0) stack.pop();
}
}
Button {
id: home;
anchors.right: back.left;
anchors.top: next.top;
anchors.rightMargin: 8;
text: "Home";
width: 70;
height: 30;
onClicked: {
if(stack.depth > 0)stack.pop(stack.initialItem);
}
}
Button {
id: clear;
anchors.right: home.left;
anchors.top: next.top;
anchors.rightMargin: 8;
text: "Clear";
width: 70;
height: 30;
onClicked: {
if(stack.depth > 0)stack.clear();
}
}
}
}
}
簡(jiǎn)單解釋一下上面的代碼,id為stack的StackView,內(nèi)部放了一個(gè)Text元素,點(diǎn)擊時(shí)創(chuàng)建第一個(gè)頁(yè)面。頁(yè)面由內(nèi)嵌在main.qml中的Component提供。
id為page的組件,頂層元素是個(gè)Rectangle對(duì)象,顏色由StackView的depth屬性決定。這個(gè)Rectangle內(nèi)部,中間放了一個(gè)Text,底部放了Clear、Home、Back、Next幾個(gè)按鈕,在這些按鈕的onClicked信號(hào)處理器中,調(diào)用了StackView的clear、pop、push等方法。
你可以使用qmlscene來加載示例qml文檔,也可以通過Qt Creator創(chuàng)建一個(gè)Qt Quick App來查看效果。建議使用Qt SDK 5.3.0及以上版本。
OK,這次就先到這里了。下次我們來講StackView管理的頁(yè)面(View)的生命周期、查找View、動(dòng)畫定制等內(nèi)容。
更多Qt Quick文章請(qǐng)參考我的Qt Quick專欄,想系統(tǒng)學(xué)些Qt Quick(QML),請(qǐng)閱讀《Qt Quick核心編程》。
我開通了微信訂閱號(hào)“程序視界”,關(guān)注即可第一時(shí)間看到我的原創(chuàng)文章以及我推薦的精彩文章:
|