Custom Drawer Qt/QML || Mobile App Like Drawer || Custom Drawer In QML
PageDrawer.qml
import QtQuick 2.0
import QtQuick.Layouts 1.0
import QtQuick.Controls 2.0
import QtGraphicalEffects 1.0
Drawer {
id: drawer
//
// Default size options
//
implicitHeight: parent.height
implicitWidth: Math.min (parent.width > parent.height ? 320 : 280,
Math.min (parent.width, parent.height) * 0.90)
//
// Icon properties
//
property string iconTitle: ""
property string iconSource: ""
property string iconSubtitle: ""
property size iconSize: Qt.size (72, 72)
property color iconBgColorLeft: "#de6262"
property color iconBgColorRight: "#ffb850"
//
// List model that generates the page selector
// Options for selector items are:
// - spacer: acts an expanding spacer between to items
// - pageTitle: the text to display
// - separator: if the element shall be a separator item
// - separatorText: optional text for the separator item
// - pageIcon: the source of the image to display next to the title
//
property alias items: listView.model
property alias index: listView.currentIndex
//
// Execute appropiate action when the index changes
//
onIndexChanged: {
var isSpacer = false
var isSeparator = false
var item = items.get (index)
if (typeof (item) !== "undefined") {
if (typeof (item.spacer) !== "undefined")
isSpacer = item.spacer
if (typeof (item.separator) !== "undefined")
isSpacer = item.separator
if (!isSpacer && !isSeparator)
actions [index]()
}
}
//
// A list with functions that correspond with the index of each drawer item
// provided with the \a pages property
//
// For a string-based example, check this SO answer:
// https://stackoverflow.com/a/26731377
//
// The only difference is that we are working with the index of each element
// in the list view, for example, if you want to define the function to call
// when the first item of the drawer is clicked, you should write:
//
// actions: {
// 0: function() {
// console.log ("First item clicked!")
// },
//
// 1: function() {}...,
// 2: function() {}...,
// n: function() {}...
// }
//
property var actions
//
// Main layout of the drawer
//
ColumnLayout {
spacing: 0
anchors.margins: 0
anchors.fill: parent
//
// Icon controls
//
Rectangle {
z: 1
height: 120
id: iconRect
Layout.fillWidth: true
Rectangle {
anchors.fill: parent
LinearGradient {
anchors.fill: parent
start: Qt.point (0, 0)
end: Qt.point (parent.width, 0)
gradient: Gradient {
GradientStop { position: 0; color: iconBgColorLeft }
GradientStop { position: 1; color: iconBgColorRight }
}
}
}
RowLayout {
spacing: 16
anchors {
fill: parent
centerIn: parent
margins: 16
}
Image {
source: iconSource
sourceSize: iconSize
}
ColumnLayout {
spacing: 8
Layout.fillWidth: true
Layout.fillHeight: true
Item {
Layout.fillHeight: true
}
Label {
color: "#fff"
text: iconTitle
font.weight: Font.Medium
font.pixelSize: 16
}
Label {
color: "#fff"
opacity: 0.87
text: iconSubtitle
font.pixelSize: 12
}
Item {
Layout.fillHeight: true
}
}
Item {
Layout.fillWidth: true
Layout.fillHeight: true
}
}
}
//
// Page selector
//
ListView {
z: 0
id: listView
currentIndex: -1
Layout.fillWidth: true
Layout.fillHeight: true
Component.onCompleted: currentIndex = 0
delegate: DrawerItem {
model: items
width: parent.width
pageSelector: listView
onClicked: {
if (listView.currentIndex !== index)
listView.currentIndex = index
drawer.close()
}
}
ScrollIndicator.vertical: ScrollIndicator { }
}
}
}
DrawerItem.qml
import QtQuick 2.0
import QtQuick.Layouts 1.0
import QtQuick.Controls 2.0
ItemDelegate {
//
// Do not allow user to click spacers and separators
//
enabled: !isSpacer (index) && !isSeparator (index)
//
// Alias to parent list view
//
property ListModel model
property ListView pageSelector
//
// Returns true if \c spacer is defined and is equal to \c true
//
function isSpacer (index) {
if (typeof (model.get (index).spacer) !== "undefined")
return model.get (index).spacer
return false
}
//
// Returns true if \c link is defined and is equal to \c true
//
function isLink (index) {
if (typeof (model.get (index).link) !== "undefined")
return model.get (index).link
return false
}
//
// Returns true if \c separator is defiend and is equal to \c true
//
function isSeparator (index) {
if (typeof (model.get (index).separator) !== "undefined")
return model.get (index).separator
return false
}
//
// Returns the icon for the drawer item
//
function iconSource (index) {
if (typeof (model.get (index).pageIcon) !== "undefined")
return model.get (index).pageIcon
return ""
}
//
// Returns the title for the drawer item
//
function itemText (index) {
if (typeof (model.get (index).pageTitle) !== "undefined")
return model.get (index).pageTitle
return ""
}
//
// Returns \c true if separatoText is correctly defined
//
function hasSeparatorText (index) {
return isSeparator (index) && typeof (model.get (index).separatorText) !== "undefined"
}
//
// Decide if we should highlight the item
//
highlighted: ListView.isCurrentItem ? !isLink (index) : false
//
// Calculate height depending on the type of item that we are
//
height: {
if (isSpacer (index)) {
var usedHeight = 0
for (var i = 0; i < model.count; ++i) {
if (!isSpacer (i)) {
if (!isSeparator (i) || hasSeparatorText (i))
usedHeight += 48
else
usedHeight += 8
}
}
return Math.max (8, pageSelector.height - usedHeight)
}
if (enabled || hasSeparatorText (index))
return 48
return 8
}
//
// Separator layout
//
ColumnLayout {
spacing: 8
anchors.fill: parent
visible: isSeparator (index)
anchors.verticalCenter: parent.verticalCenter
Item {
Layout.fillHeight: true
}
Rectangle {
height: 0.5
opacity: 0.20
color: "#000000"
anchors {
left: parent.left
right: parent.right
}
}
Label {
opacity: 0.54
color: "#000000"
font.pixelSize: 14
font.weight: Font.Medium
text: hasSeparatorText (index) ? separatorText : ""
anchors {
margins: 16
left: parent.left
right: parent.right
}
}
Item {
Layout.fillHeight: true
}
}
//
// Normal layout
//
RowLayout {
spacing: 16
anchors.margins: 16
anchors.fill: parent
visible: !isSpacer (index)
Image {
smooth: true
opacity: 0.54
fillMode: Image.Pad
source: iconSource (index)
sourceSize: Qt.size (24, 24)
verticalAlignment: Image.AlignVCenter
horizontalAlignment: Image.AlignHCenter
anchors.verticalCenter: parent.verticalCenter
}
Item {
width: 36 - (2 * spacing)
}
Label {
opacity: 0.87
font.pixelSize: 14
text: itemText (index)
Layout.fillWidth: true
font.weight: Font.Medium
anchors.verticalCenter: parent.verticalCenter
}
}
}
SvgImage.qml
import QtQuick 2.0
//
// Used to avoid showing blurry SVG images on hDPI screens
// Taken from: https://stackoverflow.com/a/38636816
//
Item {
property alias image: img
property alias source: img.source
property alias fillMode: img.fillMode
property alias sourceSize: img.sourceSize
property alias verticalAlignment: img.verticalAlignment
property alias horizontalAlignment: img.horizontalAlignment
implicitWidth: sourceSize.width
implicitHeight: sourceSize.height
Image {
id: img
anchors.centerIn: parent
sourceSize.width: width * DevicePixelRatio
sourceSize.height: height * DevicePixelRatio
}
}
Main.qml
import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 1.4
import "./"
Window {
visible: true
width: 640
height: 480
title: qsTr("Custom Drawer In QML ")
Button{
width: 100
height: 60
onClicked: {
drawer.open()
}
}
PageDrawer {
id: drawer
//
// Icon properties
//
iconTitle: "Qt Drawer App"
iconSource: "qrc:/qt-logo.svg"
iconSubtitle: qsTr ("Version 1.0 Beta")
//
// Define the actions to take for each drawer item
// Drawers 5 and 6 are ignored, because they are used for
// displaying a spacer and a separator
//
actions: {
0: function() { console.log ("Item 1 clicked!") },
1: function() { console.log ("Item 2 clicked!") },
2: function() { console.log ("Item 3 clicked!") },
3: function() { console.log ("Item 4 clicked!") },
4: function() { console.log ("Item 5 clicked!") },
7: function() { console.log ("Item 6 clicked!") },
8: function() { console.log ("Item 7 clicked!") }
}
//
// Define the drawer items
//
items: ListModel {
id: pagesModel
ListElement {
pageTitle: qsTr ("Home")
pageIcon: "qrc:/house-user-solid.svg"
}
ListElement {
pageTitle: qsTr ("Scores Table")
pageIcon: "qrc:/mobile-screen-solid.svg"
}
ListElement {
pageTitle: qsTr ("Charts")
pageIcon: "qrc:/chart-line-solid.svg"
}
ListElement {
pageTitle: qsTr ("Leaderboard")
pageIcon: "qrc:/cash-register-solid.svg"
}
ListElement {
pageTitle: qsTr ("Settings")
pageIcon: "qrc:/sliders-solid.svg"
}
ListElement {
spacer: true
}
ListElement {
separator: true
}
ListElement {
pageTitle: qsTr ("Learn Romanian Whist")
pageIcon: "qrc:/star-half-stroke-solid.svg"
}
ListElement {
pageTitle: qsTr ("Feature Requests / Bugs")
pageIcon: "qrc:/bug-solid.svg"
}
}
}
}
Note : Download Icons From Fontawsome website and change icons Name