Developing for SailfishOS menu
In fact, the main type menu in Sailfish is a menu which is displayed on top of the screen. Since the platform is a large emphasis is on gestures and quick control with them, and in order to show this menu use the gesture — swipe your finger from top to bottom. It looks as follows: if the application on the screen menu, at the top of the screen appears a light strip

Even on full-size screenshot of this strip are difficult to see, but on real device it is visible. For comparison, below is a screenshot of the same screen but without the menu and, respectively, with the missing stripes.

If you pull the screen down, it will pop up the same menu:

An interesting feature of the interaction with the menu in SailfishOS is that you select any menu item in two ways. You can just do a swipe down for the menu to appear completely (as in the screenshot above). Then it will remain on the screen and you can simply poke the desired menu item. And you can pull down to the end and then at least the appearance of menu items will be highlighted as in the screenshot below:

If at this point remove your finger from the screen selects the highlighted menu item.
the
PullDownMenu
The implementation of such a menu in Sailfish is pretty simple. To do this in the Sailfish Silica component is present PullDownMenu. However, this component has several features that you need to know before you start to use it.
First, because the menu itself is displayed using a swipe gesture, then PullDownMenu can be used only inside containers that allow the gesture. In Sailfish Silica such containers are:
the
SilicaFlickable is the base container that allows you to scroll the screen if the content fully fits in the screen frame. This component inherits the standard QML component Flickable and should be used in cases when you need menu on the application page, but none of these containers is not suitable.
SilicaListView component displays a list of elements, which inherits the standard QML component ListView.
SilicaGridView — same as the previous component is used to display a list of items, but not in a vertical list, and grid view. Inherits the standard QML component GridView.
SilicaWebView — the component to display web content, the standard QML component inherits the WebView.
Second, the contents of PullDownMenu should be the components of type MenuItem or MenuLabel (actually no, see text below). The first is an interactive menu and has the following properties:
the
- color — the text color specified in the previous property.
text — the menu item text. the
horizontalAlignment — the horizontal alignment of the text of the menu item. Can be one of the following values: Text.AlignLeft, Text.AlignRight, Text.AlignHCenter (the default) or Text.AlignJustify.
down — the value of this property is true when the menu item was selected.
In addition to these properties, MenuItem also contains a large number of properties of the form font. for font setting menu items (you can read about in documentatie) and a signal handler onClicked(), which defines the actions to execute when this menu item.
MenuLabel is a static menu item that just displays some text and cannot be clicked. Such points are for example used as the title menu or as dividers between interactive menus. Of course, MenuLabel contains fewer properties than PullDownMenu:
the
- color — the text color specified in the previous property.
text is the text of the menu item. the
verticalOffset is the vertical spacing.
UPD: of Course, the contents of PullDownMenu, as well as other menu discussed in this article could be any component and not only MenuItem or MenuLabel. However, in the case of using other components of the whole logic of interaction the developer will have to implement yourself. And look such a menu will not native and, therefore, to use such a possibility is only in rare cases. In standard situations, enough MenuItem and MenuLabel, so the use of other components within the menu in this article will not be considered.
A minimal example of a page PullDownMenu will look as follows:
the
Page {
id: page
SilicaFlickable {
anchors.fill: parent
contentHeight: column.height
PullDownMenu {
MenuItem {
text: qsTr("menu Item 3")
onClicked: console.log("Clicked the third menu item")
}
MenuLabel {
text: qsTr("Subsection")
}
MenuItem {
text: qsTr("menu Item 2")
onClicked: console.log("Clicked the second menu item")
}
MenuItem {
text: qsTr("menu Item 1")
onClicked: console.log("Clicked the first menu item")
}
MenuLabel {
text: qsTr("application Menu")
}
}
Column {
id: column
width: page.width
spacing: Theme.paddingLarge
PageHeader {
title: qsTr("My app")
}
Label {
text: "Hello, Habr!"
width: page.width
horizontalAlignment: Text.AlignHCenter
font.pixelSize: Theme.fontSizeExtraLarge
}
}
}
}
The very same menu would look like this:

It is worth noting that the menu items within PullDownMenu are not defined in the order they appear on the screen when a swipe gesture, but in the order of their presence in the menu, top to bottom. This feature at first, may seem unusual. In addition, it should be noted that the examples above are for informational purposes only, in real applications it is not necessary to use too many items on the menu and especially MenuLabel components.
the
Properties PullDownMenu
PullDownMenu contains several properties that allow you to customize its appearance and behavior. For example, the indention component can be configured using the following properties:
the
spacing is the distance between the bottom edge of the menu and the top border of the page content. By default, this value is zero.
topMargin is the distance between the top menu (same as the top edge of the screen) and the top edge of the topmost menu item. By default, this value is Theme.itemSizeSmall.
bottomMargin is the distance between the lower edge of the lowermost menu item and the bottom of the menu.
An interesting feature of the last property (bottomMargin) is that its default value varies depending on the content menu. If the bottom menu item is a MenuLabel, the value property is 0. Otherwise, the value property is equal to the height of the component MenuLabel. To see the difference on the examples below:
![]() |
![]() |
As seen in the screenshots, this feature allows you to always have the same height, regardless of the presence or absence of it in the header, which in turn allows you to save the user experience when using the different menu types.
Besides size you can also change other appearance options PullDownMenu with the following properties:
the
-
the
- background — allows to describe a component that will be used as the menu background.
backgroundColor — the background color of the menu. It is noteworthy that the system applies the gradient to the specified color.
highlightColor — the highlight color of the selected menu item and the menu indicator displayed on top of the screen when the menu is closed.
menuIndicator — allows to describe a component that will be used as a menu indicator displayed on top of the screen when the menu is closed.
You can change the colors in menu in the example above to the following:
the
backgroundColor: "red"
highlightColor: "green"
Then get a menu:

Looks, of course, scary, but demonstrates how to work these properties. And background and menuIndicator can be set, for example, the picture in the background and the menu indicator.
The above properties can be useful if you want to make the menu, as well as all the app was made, for example, in the corporate colors. In addition to these properties, a component of PullDownMenu also contains properties that allow you to get the status of the menu or easy to modify its behavior:
the
-
the
- active — a Boolean property whose value is true if the menu is partially or fully present on the screen.
busy is a Boolean property. If its value is set to true, the indicator menu at the top of the screen will begin to "pulsate". While the menu is still available. This property is useful if you want to show the user that some process is still running.
flickable — you can use this property to specify the flickable component which is to be activated by menu. Ie instead of having to put PullDownMenu inside any container, you can simply specify this container value for this property.
quickSelect — a Boolean property that allows you to enable the quick selection menu. This function only works for menus with only one item. If this function is activated, when any scrollable menu (including through) will be automatically selected its only item.
Finally, PullDownMenu contains two methods. After selection of any menu item to close this menu and play the animation of closing. This animation can be canceled by using the method cancelBounceBack(), if, for example, invoke it in the handler for onClicked() the desired menu item. This can be useful in rare cases when the menu is closed, may prevent the action assigned to the menu item.
The method close() allows you to manually close the menu. It is possible as argument of this method, you can specify a true and then the menu will close instantly without animation. For example, in the code below, when selecting the menu item "menu 2", the menu will close without animation:
the
PullDownMenu {
id: menu
MenuItem {
text: qsTr("menu Item 2")
onClicked: menu.close(true)
}
MenuItem {
text: qsTr("menu Item 1")
onClicked: console.log("Clicked the first menu item")
}
}
the
PushUpMenu
Another type of menu — PushUpMenu is the same PullDownMenu, with the only difference that appears for this menu is not on top of the screen, and the bottom and, accordingly, is activated by a swipe gesture from the bottom up. PushUpMenu looks like PullDownMenu and all its properties and methods are similar to those of PullDownMenu, so the separate mention in this article, they don't need.
However, it is worth noting that, since PushUpMenu (as PullDownMenu) must be inside a container that allows swipe gestures, activation of the menu occurs only after the entire content of the container was scrolled to the end. In other words, if you put PushUpMenu on the list, then activate this menu will only happen after the user has scrolled the entire list to the end.
In this example the code will look like this:
the
Page {
id: page
SilicaListView {
PushUpMenu {
MenuItem {
text: qsTr("menu Item 3")
onClicked: console.log("Clicked the third menu item")
}
MenuItem {
text: qsTr("menu Item 2")
onClicked: console.log("Clicked the second menu item")
}
MenuItem {
text: qsTr("menu Item 1")
onClicked: console.log("Clicked the first menu item")
}
MenuLabel {
text: qsTr("application Menu")
}
}
id: listView
model: 20
anchors.fill: parent
header: PageHeader {
title: "Simple list"
}
delegate: BackgroundItem {
id: delegate
Label {
x: Theme.paddingLarge
text: "Element #" + index
anchors.verticalCenter: parent.verticalCenter
color: delegate.highlighted ? Theme.highlightColor : Theme.primaryColor
}
}
VerticalScrollDecorator {}
}
}
As a result, to get to the menu if you can only scroll the entire list to the end:
![]() |
![]() |
the
ContextMenu
The last type of menu to SailfishOS, which will be discussed in this article's context menu. It is implemented using a component ContextMenu is a pop-up menu that can be associated with any UI element. The contents of this menu is described in the same way as for PushUpMenu and PullDownMenu components MenuItem and MenuLabel.
Most of these menu items are used to implement a context menu for list items. For this component ListItem, which is used to describe delegates list, there is a special property menu. So you can add a context menu to list items from the last example. This will slightly change the delegate to be implemented through the ListItem, and add it to the menu itself:
the
delegate: ListItem {
id: delegate
Label {
id: label
x: Theme.paddingLarge
text: "Element #" + index
anchors.verticalCenter: parent.verticalCenter
color: delegate.highlighted ? Theme.highlightColor : Theme.primaryColor
}
menu: ContextMenu {
MenuLabel {
text: "Context menu"
}
MenuItem {
text: "bold"
onClicked: label.font.bold = !label.font.bold
}
MenuItem {
text: "italicize"
onClicked: label.font.italic = !label.font.italic
}
}
}
Now, when you long tap on a list item, under it will appear a context menu:

If you select this menu item to change the text style of a list item:
![]() |
![]() |
Context menu closes when you select one of the menu items, or simply tap outside the menu. However, the component ListItem contains the methods hideMenu() and showMenu() that allow you to hide or show the context menu manually. The latter method can be an option to transfer a list of component properties ContextMenu, which will be applied to the menu (of the component properties ContextMenu will be discussed later). In addition, the standard behavior for the context menu of the list item can be changed by setting the property showMenuOnPressAndHold component ListItem to false. In this case, the context menu will not appear when you long tap on the item. Finally, learn the shortcut menu is shown or not by using the properties of menuOpen component ListItem.
The context menu can be shown out of the list, linking them with conventional interface elements. For this component ContextMenu has a method show(), in which the argument is an element for which must be shown on the menu. The menu will be attached to the lower border of this element, and when the show will go up. A minimal example so the menu may be:
the
Page {
id: page
SilicaFlickable {
id: flickab
anchors.fill: parent
Column {
id: column
width: page.width
spacing: Theme.paddingLarge
PageHeader {
title: qsTr("My app")
}
Button {
id: button
text: "Click me"
width: page.width
onClicked: contextMenu.show(label)
}
Label {
id: label
height: page.height / 2
text: "plain text"
verticalAlignment: Text.AlignBottom
}
}
ContextMenu {
id: contextMenu
MenuLabel {
text: "Context menu"
}
MenuItem {
text: qsTr("menu Item 1")
onClicked: console.log("Clicked the first menu item")
}
}
}
}
This page looks like this:

And when you click on the button from the lower edge of the label leaves the menu:

It should be noted that the height of the inscription is not by accident was this big (half a page). The fact that the context menu that is shown inside the component specified in the method show(), and if the menu will be more of this element, it will simply cut off. To demonstrate this feature in the example above, the labels make an ordinary height, and between the button and the words to put a white rectangle:
the
Button {
id: button
text: "Click me"
width: page.width
onClicked: contextMenu.show(label)
}
Rectangle {
color: "white"
height: page.height / 2
width: parent.width
}
Label {
id: label
text: "plain text"
}
Then the page will look like the following:

And the menu when opened circumcised:

UPD: As noted by multiple people that the above examples are not chosen very well. In real projects, in cases when a context menu is larger item to which it relates, is to change the size of elements depending on, menu is open or not. The above code snippet, in this case, you should change, making the height of the component Label - dependent menu:
the
Label {
id: label
text: "plain text"
height: contentHeight + (contextMenu.visible ? contextMenu.height : 0)
}
Then the page itself will look like this:

And when you click on the menu button will visually go from the bottom of the inscription:

To close a context menu, you can use the method hide(), and learn openly it or not with the property active. In addition, a component of ContextMenu also contains the property closeOnActivation, with which you can set whether to close menu when selecting any of its items. And the property hasContent will help to see if the menu has any content. This property is used by the system: if the value of hasContent is false, the menu will not be displayed, even when the method is invoked show().
Finally ContextMenu contains the signal handler onActivated(), which is invoked each time was selected a menu item. The argument handler is the index of the selected menu item.
That's about it. In this article, I described the 3 main standard menu in SailfishOS, told how they can implement and what features are available with each type.
Author: Laura Dennis
UPD: the text of the article has been updated, taking into account all submitted comments. Thanks to everyone who sent comments and observations.
Комментарии
Отправить комментарий