一、理解qml模型和視圖
qt的發展是迅速的,雖然在每一個release版本中或多或少都有bug,但是作為一個龐大的gui庫,no,應該說是一個開發框架開說,qt已經算是做的相當好。qml部分是qt4.7的時候推出的,當時qml只是為了移動端而設計的開發語言,隨着it行業的發展,桌面端也產生了一定的需求,這就使得qml也必須支持桌面端的開發。使用qml可以做出絢麗的界面,並把邏輯和界面展示分開,qml和C++就好比html和JavaScript。
qt中有大量的model/view類,視圖類:QTableView、QListView和QTreeView,模型類:QAbstractTableModel、QAbstractListModel和QAbstractProxyModel,這三個模型類都是繼承自QAbstractItemModel。對於qml語言來說,也有model和view,他們分別就是GridView、ListView和PathView,其中GridView和ListView在qt中都有對於的實現類,PathView是最難理解的view,也是最靈活的view,他可以做出各種各樣比較絢麗的效果。
二、效果展示
這一節我們主要是說明qml中的視圖類,如下效果圖展示的那樣,圖1是用GridView實現,圖2是用ListView實現,view的item項都是用代理進行繪制;圖3是用PathView實現的一個效果圖,類似於一個卡牌彈出彈入效果。
順道提一嘴,qml文件都是可以使用qmlscene.exe來預覽
圖1 gridview效果圖
圖2 listview效果圖
圖3 pathview效果圖
三、源碼分析
每一個示例中都有大量的注釋,具體細節可以參看注釋
1、GridView增刪
如圖1所示,這是一個GridView的簡單示例,示例完成單擊Add Item按鈕實現新增項,點擊項實現刪除等功能。
1 import QtQuick 2.0 2 3 Rectangle { 4 width: 480; 5 height: 300; 6 7 //背景色漸變 8 gradient: Gradient { 9 GradientStop { position: 0.0; color: "#dbddde"; } 10 GradientStop { position: 1.0; color: "#5fc9f8"; } 11 } 12 13 //list模型默認9項 14 ListModel { 15 id: theModel 16 17 ListElement { number: 0; } 18 ListElement { number: 1; } 19 ListElement { number: 2; } 20 ListElement { number: 3; } 21 ListElement { number: 4; } 22 ListElement { number: 5; } 23 ListElement { number: 6; } 24 ListElement { number: 7; } 25 ListElement { number: 8; } 26 ListElement { number: 9; } 27 } 28 29 //Add Item按鈕 30 Rectangle { 31 anchors.left: parent.left; 32 anchors.right: parent.right; 33 anchors.bottom: parent.bottom; 34 anchors.margins: 20; 35 36 height: 40; 37 38 color: "#53d769"; 39 border.color: Qt.lighter(color, 1.1); 40 41 Text { 42 anchors.centerIn: parent; 43 44 text: "Add item!"; 45 } 46 47 //點擊時新增項 實現model的動態新增 48 MouseArea { 49 anchors.fill: parent; 50 51 onClicked: { 52 theModel.append({"number": ++parent.count}); 53 } 54 } 55 56 property int count: 9;// 57 } 58 59 GridView { 60 anchors.fill: parent; 61 anchors.margins: 20; 62 anchors.bottomMargin: 80; 63 64 clip: true; 65 66 model: theModel;//綁定數據源 67 68 cellWidth: 45;//設置項大小 69 cellHeight: 45; 70 71 delegate: numberDelegate;//設置繪制代理 72 } 73 74 //自定義繪制代理 75 Component { 76 id: numberDelegate; 77 78 Rectangle { 79 id: wrapper; 80 81 width: 40; 82 height: 40; 83 84 //首先是一個漸變的矩形框 85 gradient: Gradient { 86 GradientStop { position: 0.0; color: "#f8306a"; } 87 GradientStop { position: 1.0; color: "#fb5b40"; } 88 } 89 90 //文本值是number的數值 91 Text { 92 anchors.centerIn: parent; 93 94 font.pixelSize: 10; 95 96 text: number; 97 } 98 99 //鼠標點擊代理時,移除點擊項 100 MouseArea { 101 anchors.fill: parent; 102 103 onClicked: { 104 if (!wrapper.GridView.delayRemove)//是否延遲移除 105 { 106 theModel.remove(index); 107 } 108 } 109 } 110 111 //GridView移除項 順序動畫 112 GridView.onRemove: SequentialAnimation { 113 //屬性變化 114 PropertyAction { 115 target: wrapper; 116 property: "GridView.delayRemove"; 117 value: true; 118 } 119 //數字動畫 120 NumberAnimation { 121 target: wrapper;//目標對象 122 property: "scale";//執行動畫的屬性 123 to: 0;//結束值 124 duration: 250;//動畫持續時長 125 easing.type: Easing.InOutQuad;//動畫執行曲線 126 } 127 PropertyAction { 128 target: wrapper; 129 property: "GridView.delayRemove"; 130 value: false; 131 } 132 } 133 134 //GridView新增項 順序動畫 135 GridView.onAdd: SequentialAnimation { 136 NumberAnimation { 137 target: wrapper; 138 property: "scale"; 139 from: 0;//開始值 140 to: 1; 141 duration: 250; 142 easing.type: Easing.InOutQuad; 143 } 144 } 145 } 146 } 147 }
2、列表
如圖2所示,是一個使用ListView實現的列表控件,點擊列表控件中的項,可以實現最大化來展示列表的詳細信息
1 import QtQuick 2.0 2 3 Item { 4 width: 300; 5 height: 480; 6 7 //漸變別景色 8 Rectangle { 9 anchors.fill: parent; 10 gradient: Gradient { 11 GradientStop { position: 0.0; color: "#4a4a4a"; } 12 GradientStop { position: 1.0; color: "#2b2b2b"; } 13 } 14 } 15 16 //主界面列表視圖 17 ListView { 18 id: listView; 19 20 anchors.fill: parent; 21 22 delegate: detailsDelegate;//設置繪制代理 23 model: planets;//綁定數據源 24 } 25 26 ListModel { 27 id: planets; 28 29 ListElement { 30 name: "Mercury"; 31 imageSource: "images/mercury.jpeg"; 32 facts: "Mercury is the smallest planet in the Solar System. It is the closest planet to the sun. It makes one trip around the Sun once every 87.969 days." ; 33 } 34 ListElement { 35 name: "Venus"; 36 imageSource: "images/venus.jpeg"; 37 facts: "Venus is the second planet from the Sun. It is a terrestrial planet because it has a solid, rocky surface. The other terrestrial planets are Mercury, Earth and Mars. Astronomers have known Venus for thousands of years."; 38 } 39 ListElement { 40 name: "Earth"; 41 imageSource: "images/earth.jpeg"; 42 facts: "The Earth is the third planet from the Sun. It is one of the four terrestrial planets in our Solar System. This means most of its mass is solid. The other three are Mercury, Venus and Mars. The Earth is also called the Blue Planet, 'Planet Earth', and 'Terra'."; 43 } 44 ListElement { 45 name: "Mars"; 46 imageSource: "images/mars.jpeg"; 47 facts: "Mars is the fourth planet from the Sun in the Solar System. Mars is dry, rocky and cold. It is home to the largest volcano in the Solar System. Mars is named after the mythological Roman god of war because it is a red planet, which signifies the colour of blood."; 48 } 49 } 50 51 Component { 52 id: detailsDelegate; 53 54 Item { 55 id: wrapper; 56 57 width: listView.width; 58 height: 30; 59 60 //列表項文本 61 Rectangle { 62 anchors.left: parent.left; 63 anchors.right: parent.right; 64 anchors.top: parent.top; 65 66 height: 30; 67 68 color: "#333"; 69 border.color: Qt.lighter(color, 1.2); 70 Text { 71 anchors.left: parent.left; 72 anchors.verticalCenter: parent.verticalCenter; 73 anchors.leftMargin: 4; 74 75 font.pixelSize: parent.height-4; 76 color: '#fff'; 77 78 text: name;//ListElement中的name 79 } 80 } 81 82 //列表項圖標 83 Rectangle { 84 id: image; 85 86 width: 26; 87 height: 26; 88 89 anchors.right: parent.right; 90 anchors.top: parent.top; 91 anchors.rightMargin: 2; 92 anchors.topMargin: 2; 93 94 color: "yellow"; 95 96 Image { 97 anchors.fill: parent; 98 99 fillMode: Image.PreserveAspectFit; 100 101 source: imageSource;//ListElement中的imageSource 102 } 103 } 104 105 //鼠標點擊列表項 進行狀態前切換, 106 MouseArea { 107 anchors.fill: parent; 108 onClicked: parent.state = "expanded";//切換到展開狀態 109 } 110 111 //詳情頁展開時,文本詳細信息 112 Item { 113 id: factsView; 114 115 anchors.top: image.bottom;//位於放大后的圖標底部 116 anchors.left: parent.left; 117 anchors.right: parent.right; 118 anchors.bottom: parent.bottom; 119 120 opacity: 0;//默認透明不顯示 當點擊代理項時該屬性會慢慢變得可見 121 122 Rectangle { 123 anchors.fill: parent; 124 125 gradient: Gradient { 126 GradientStop { position: 0.0; color: "#fed958"; } 127 GradientStop { position: 1.0; color: "#fecc2f"; } 128 } 129 border.color: '#000000'; 130 border.width: 2; 131 132 Text { 133 anchors.fill: parent; 134 anchors.margins: 5; 135 136 clip: true;//可剪切 137 wrapMode: Text.WordWrap;//文本支持換行 138 color: '#1f1f21'; 139 140 font.pixelSize: 12; 141 142 text: facts; 143 } 144 } 145 } 146 147 //項最大化時 右上角關閉按鈕 148 Rectangle { 149 id: closeButton; 150 151 anchors.right: parent.right; 152 anchors.top: parent.top; 153 anchors.rightMargin: 2; 154 anchors.topMargin: 2; 155 156 width: 26; 157 height: 26; 158 159 color: "#157efb"; 160 border.color: Qt.lighter(color, 1.1); 161 162 opacity: 0; 163 164 MouseArea { 165 anchors.fill: parent; 166 onClicked: wrapper.state = "";//點擊恢復到默認狀態 167 } 168 } 169 170 //自定義代理狀態 171 states: [ 172 State { 173 name: "expanded"; 174 //在點擊列表項后 各項屬相變化 175 176 //代理高度鋪滿視圖高度 177 PropertyChanges { target: wrapper; height: listView.height; } 178 //列表項的圖標放大 179 PropertyChanges { 180 target: image; 181 width: listView.width; 182 height: listView.width; 183 anchors.rightMargin: 0; 184 anchors.topMargin: 30//距離頂部30像素 185 } 186 //文本詳細信息可見 187 PropertyChanges { target: factsView; opacity: 1; } 188 //關閉按鈕可見 189 PropertyChanges { target: closeButton; opacity: 1; } 190 //列表項視圖 191 PropertyChanges { 192 target: wrapper.ListView.view; 193 contentY: wrapper.y; 194 interactive: false 195 } 196 } 197 ] 198 199 //項變化時 過程 200 transitions: [ 201 Transition { 202 NumberAnimation { 203 duration: 200; 204 properties: "height,width,anchors.rightMargin,anchors.topMargin,opacity,contentY"; 205 } 206 } 207 ] 208 } 209 } 210 }
3、卡牌效果
示例代碼可以直接放在qml文件中使用qmlscene.exe來預覽
1 import QtQuick 2.6 2 3 Rectangle { 4 id: root; 5 width: 480; 6 height: 300; 7 8 PathView 9 { 10 anchors.fill: parent; 11 12 delegate: flipCardDelegate; 13 model: 100; 14 15 path: Path{ 16 startX: root.width / 2; 17 startY: 0 18 19 PathAttribute { name: "itemAngle"; value: -45.0; } 20 PathAttribute { name: "itemScale"; value: 0.5; } 21 PathAttribute { name: "itemZ"; value: 0; }//屬性值附加到代理上面 22 PathLine { x: root.width/2; y: root.height*0.4; }//路徑元素定義 23 PathPercent { value: 0.48; }//控制兩個元素之間的路徑所占百分比 24 PathLine { x: root.width/2; y: root.height*0.5; } 25 PathAttribute { name: "itemAngle"; value: 0.0; } 26 PathAttribute { name: "itemScale"; value: 1.0; } 27 PathAttribute { name: "itemZ"; value: 100 } 28 PathLine { x: root.width/2; y: root.height*0.6; } 29 PathPercent { value: 0.52; } 30 PathLine { x: root.width/2; y: root.height; } 31 PathAttribute { name: "itemAngle"; value: 45.0; } 32 PathAttribute { name: "itemScale"; value: 0.5; } 33 PathAttribute { name: "itemZ"; value: 0; } 34 } 35 36 pathItemCount: 17;//可見元素數目 37 38 preferredHighlightBegin: 0.5; 39 preferredHighlightEnd: 0.5; 40 } 41 Component{ 42 id: flipCardDelegate; 43 44 Rectangle{ 45 id: wrapper; 46 47 width: 64; 48 height: 64; 49 antialiasing: true;//反鋸齒 50 51 //代理背景色漸變 52 gradient: Gradient{ 53 GradientStop { position: 0.0; color: "#2ed5fa"; } 54 GradientStop { position: 1.0; color: "#2467ec"; } 55 } 56 57 visible: PathView.onPath;//在PathView上的項可見,不在視圖上的項不可見 58 59 scale: PathView.itemScale;//縮放 60 z: PathView.itemZ;//z值 數值大的在上面 61 62 property variant rotX: PathView.itemAngle;//屬性別名 主要是因為要在底下這個旋轉過程中使用 63 64 //動畫過程旋轉 65 transform: Rotation { 66 axis { x: 1; y: 1; z: 1; }//繞x軸旋轉 67 angle: wrapper.rotX;//旋轉角度 68 origin { x: 32; y: 32; }//旋轉基點 69 } 70 Text{ 71 anchors.horizontalCenter: parent.horizontalCenter; 72 anchors.verticalCenter: parent.verticalCenter; 73 text: index; 74 } 75 } 76 } 77 }
四、相關文章