Qt Design Studio - Sketch Bridge Tutorial Part 2

Welcome back to this Sketch Bridge for Qt Design Studio Tutorial, in the last part we created our first button and got it working with it's different states in Qt Design Studio (referred to as qds for the rest of the tutorial). In this part we're going to go back in and create a menu component from instances of this button and look at overriding the icons and text for each instance. If you missed the first part of the tutorial or would like to go back to check something you can find that here - https://www.qt.io/blog/qt-design-studio-sketch-bridge-tutorial-part-1

Part 2.1 - Building a menu component using instances of our buttons.


So let’s open up our Sketch file and start by creating our menu background, we can make it large enough to fit four of our buttons on and let’s keep it fairly simple, just a rectangle for now.

Again we want to create the rectangle, convert it into a symbol and then delete this instance and work on the master symbol on our symbol page.


Here we can adjust the size and colors of our rectangle until we are happy with it and in this case we can leave the single settings set to merge as we just want a simple single asset for this to begin with.

We'll also give our background a good qml id, in this case myMenu_Symbol_background


Once we have that menu background we can start to use our symbols to create the instances of our buttons from the master button component we created in sketch and added our interaction functionality in Design Studio.

To do this we want to go to the Sketch Menu for adding assets, the plus button at the top, and navigate to symbols / document - this shows you the current symbols available in the document, at the moment there is only one symbol here, our button, so let’s go ahead and drop that into our new menu component.

We now have our first instance and we can just repeat this process, copy paste or use alt + drag to add three more buttons to our menu.


After this is done what we need to do is check the qml ids assigned to the new symbol instances, while we do this we can also make sure our menu has a good qml id.

So, let’s start with the menu, as this is also a symbol itself let’s use a similar naming scheme as our last one and call it - myMenu_Symbol

Now we can look at the buttons themselves, so in this case we will use the following naming scheme for these instances. We could go for something like this:

myButton_myMenu_1
myButton_myMenu_2
myButton_myMenu_3
myButton_MyMenu_4

But what would be even better is a specific name for each button role, so let’s think about what we want these buttons to do based on what this UI could be, and we can come up with an even clearer naming scheme for these buttons.

One thing we shouldn’t do is change these ids mid project, although in theory this is possible due to the merge mechanism keeping track of these id changes, it is good practice to stick with your name scheme through the whole process.

So, instead of that let’s use these ids instead:

myButton_myMenu_home
myButton_myMenu_dashboard
myButton_myMenu_profile
myButton_myMenu_settings

Which is much clearer about exactly what each instance is for and also ensures we have unique ids for each instance of our symbol.

 

At this point we could re-export it to qds already but while we’re here let's prepare a couple of things extra in our buttons by adding a label and an icon.

 

Part 2.2 - Preparing a symbol for override properties

 

To start with we want to add these to the master symbol of the button so let’s go back to that now and start working on it. We can start with the label and we want to make sure it’s visible but still underneath the mouse area hotspot we added first.

Now let’s go to the Sketch Menu with the + symbol again and choose the text item and add that to our design, making sure it’s the second layer, directly underneath the mouse area.

What we also want to do now is make sure that the text box has a fixed size that spans the whole width of the button and also that the text object is center aligned, this way when we override this text in our instances the new label will be centered and when we export to qds these properties will be carried over as well.

As we want to override this text let’s just use “default text” as the placeholder here.



And once again we want to make sure that the text object has a good qml id, let's call it myButton_Symbol_label  and then we can drag it so it's underneath the mouse area and also make sure the layer has the same name as the qml id.



Now to add an icon, or in fact three versions of one icon, and again at this point we’re going to use a placeholder icon for the master symbol and come back and change the individual icons later, so we can just drag out another shape, something simple like a triangle, by going to the shapes menu in sketch, selecting a triangle and dragging it out.

We want to make sure this is also underneath the mouse area but above the background layers. Once we have this in place we can duplicate it twice to have a version for each state of our button (default, hover, pressed) and make a slight change to each version so it’s easy to test later in qds.

In this case I’m just going to adjust the colors a bit, as these are placeholder graphics we intend to replace later it doesn’t matter too much what we do here, as long as we can tell them apart.



Now, as we do with all layers we want to change the ids and check the export settings, making sure that in this case all the icons are set to export as child. And we’ll name the ids as so:

myButton_icon_placeholder_default
myButton_icon_placeholder_hover
myButton_icon_placeholder_pressed

We will also make sure the layers have the same name as the ids, are set to export as children and then drag them underneath our mouse area in the layer navigator.



With this set we can move back over to our menu symbol and see the effect this has had on our instances, and as we can see they all now have the icons and text labels. Later we’re going to come back and deal with the icons, as there are a few different approaches we can take to this and I want to go through them in detail but for now we can use the labels to create the first of our override properties.

As a short explanation to override properties, with symbols in sketch you can change certain parts of a symbol instance to something new, this will not effect the original master symbol but only make those changes in the local instance you make the change in.

Although there are many different types of symbol override in sketch, with qds we only support a few of them, the main one being text. The other is to override the symbol itself but as this is a fairly advanced concept we won’t cover that yet and instead just focus on the text option.

To do this we can go to the first instance of our button, which we have called home, and in the property panel of sketch for our button we can see there is a new field for the text override. To use it we can simply type our new text in here, so for this first one we can just add “Home” to the override text and we will see that in this first instance only we have our new text.

When we re-import this later into design studio what happens is we create an alias property on the button component for this text field, and automatically add the “Home” text to the alias of this instance. For now let’s finish adding a new text label to all our buttons and then we can export our design and carry on with some more steps in qds.

So let’s add the text to the second instance, in our case “Dashboard”, third is “Profile”, fourth is “Settings”.

We can also now see why we made the text box the fixed width of our button and used the center alignment option, as our text is now always well centered in our button design regardless of the text length.



Ok, so let’s export this again, this time we will get a warning that we would override our metadata, which is fine so let’s continue and when that’s finished we will move back over to qds.

 

Part 2.3 - Merging our import

 

In qds we want to make sure we’re in the correct project and then repeat the steps to import our metadata file, by clicking on the import assets button in the qml library and bringing up the asset importer, at this point it is very important to make sure we select the merge option for the import, if we forget to do this it will overwrite all the work we did in our previous tutorial, so please, make sure you now have that merge option selected before continuing. This setting is persistent between sessions so you should only have to do this once but we will be checking it each time we import for safety's sake.

As long as merge is turned on we can go ahead and import our designs, and provided we didn’t make any mistakes there should be no errors or warnings here, so we can go ahead and look at our import.

The first thing we can check is our new menu component, so let’s look in the project folder for myMenu_Symbol.ui.qml and open that up in the form editor.

We should see our menu with the four buttons and the alias text for each, as we already created the states and interactions for these buttons this menu should be fully functional, expect for the icons changes, which we’ll do in a minute.

 

So let's test it by running the live preview and then hovering and clicking on the buttons, as we see thanks to the work we did in the previous tutorial we have the hover and pressed state for each new button we’ve added, without having to duplicate any work. This should hopefully help to show you the power of good componentization, something the developers you will be handing this work to will surely appreciate.

 

 

Now when we want to make changes to the overall behavior of these buttons we only have to go into the main component, make our changes there and they will be automatically applied to all instances. Which we will do now by making the icons appear in the correct states.

So, let’s switch now to our button component and work on the icons.

With the button component active we can see in our navigator the three new asset layers for each icon, we want to repeat the steps we took in part 1 and make each icon visible in each state, so let's click through each state and use the visibility flag in the properties to do that. Making sure that default is the only visible one in default, hover in hover and pressed in pressed.

With that done we can test our button directly with the live preview button and we should now see that working straight away, we can also quickly test this in our menu component to see that it works with all of our instances.

 

In the next step we want to go back to sketch and create the individual icons. Before that though we’re going to prepare this button for swapping out the icons in each instance and we’re going to do this by making our own aliases here in qds, so let’s do that by making sure we’re in the base state of our component, and then selecting the asset for the first of our icons, the default one.

Then we can look in our properties panel with this selected in the navigator and the property we are interested in, our icon's source file, then use the action icon to bring up the menu and select the add alias option. This will mean that from the instances of the icon in our menu component we can set a new icon asset for this button.

Let’s repeat this step for each of our icon assets, hover and then pressed. With the icon source alias set up we can take a look at our menu component.

So let’s load the myMenu_Symbol Component in the form editor and now select one of our button instances, with this selected we can see in the properties panel on the right all the available aliases for this instance, which shows us the text alias we added in sketch and the three different icon state aliases we just added here in qds.


We’ll come back to these again after we create some icons in sketch and change them later.

 

Part 2.4 - Designing our icon assets

 

With sketch open what we are going to do is create an artboard just for our icons, artboards are normally always components in qds after import, and we’re going to use these more later when we come to designing our screens, but for this case we are just going to import the assets from this artboard and not generate any qml, but more about that later.

For now we can utilize a feature of Sketch to create a separate page for assets so we keep them separated from our screen design later on, so let’s add a new page in the top left sketch menu and we can call this assets, then we want to drag out an artboard to start designing some icons, it doesn’t matter too much about the exact dimensions for this artboard as it’s just going to be a place to hold our assets for now, so just make sure it’s big enough to contain the artwork and then we can focus on creating our icons.

We’re going to draw these directly in sketch and use some combined shapes to take a look at a good way for using the merge feature of the bridge plugin.



So, let’s start with drawing a home icon, a rectangle and a triangle should do the trick, once we have these two together we can use combine shape to create a single element that will become our icon and then take a look at the structure of our composition works here with the bridge plugin.

So, the combined shape looks a little like a mini component of it’s own, with the combined shape acting as the parent for the two child layers we drew underneath and as we only want a single icon asset here we can make sure that the combined shape itself is a child and the two child layers are set to merge. What this will do is merge these two layers into one image in the export, which will become the combined shape, so will have the id from this item.

This is a particularly useful technique when considering a non destructive workflow as we minimize the assets in our project but can always come back and change the individual parts of the design in sketch.

So as we want to make some variants for each icon we can simply copy this twice. With the two extra versions of our icons copied we can make some adjustments to the colors, also as we’re not using this artboard as an actual screen in our design we can put all our icons next to each other and not worry about positioning them over each other. While I'm doing this first icon I'm also making sure to create unique qml ids for each of my icon variants and the sub-shapes.

 

With the first icon done we can quickly make the remaining three, using the same technique as before, creating combined shapes from multiple pieces, making sure the child layers of the combined shapes are set to merge and the combined shape itself is a child, copying the icon twice and making the three variants per icon.

I've sped these videos up a bit to save some time, but as I'm designing I'm also making sure each time to rename my qml ids and layers and check that only the top combined shape is set to export a child and all sub shapes are set to merge.

 

 

So now we have 4 icons with three variants per icon, let’s review all these qml ids and make sure they are unique and meaningful for our project.

First let's look at the artboard itself, we can call something simple like iconAssets, even though we are not going to generate qml from this artboard it's good practice to make sure we are always checking our ids hopefully at some point it will become second nature.

myButton_icon_home_default
myButton_icon_home_hover
myButton_icon_home_pressed

myButton_icon_dashboard_default
myButton_icon_dashboard_hover
myButton_icon_dashboard_pressed

myButton_icon_profile_default
myButton_icon_profile_hover
myButton_icon_profile_pressed

myButton_icon_settings_default
myButton_icon_settings_hover
myButton_icon_settings_pressed

We should also make sure all the child layer's ids unique too, even though they won’t be part of the project and therefore are not that important, we are trying to make sure we don’t get any errors during the import process. So rather than working from a naming scheme we’ll just enumerate them here in a simple way.

For example, the home icon uses this pattern for the merged shapes.

homeSquare1
homeTriangle1

homeSquare2
homeTriangle2

homeSquare3
homeTriangle3

Now with all our icons set up and the qml ids checked we can re-export the project and go back into qds to bring these icons into our buttons. So let’s hit the export button and again choose to overwrite the metadata.

 

Now we can go back to qds and go back to the asset importer, this time we'll use another feature of the importer and only import the new icon assets by deselecting generate qml, we'll make sure that merge is still checked for the future anyway and go ahead and import our project again.

 

 

Part 2.5 - Swapping the icon's source

 

Now we can see that we have all our icon assets in here, we didn't need to generate any new qml as we are going to simply swap the correct versions of our icons using the alias properties of the instances. So let's select the first component instance and take advantage of the alias properties we created earlier for this purpose, to do this we can click our first button, the home icon and in the properties panel simply use the dropdown box to select our new assets for the icon, so for each state we will pick the appropriate assets and then we can test this in the live preview.

Now we have our new working icons for the first button let’s repeat that process for the remaining icons until we have correct icons in each instance, then test it again in live preview to make sure all the states work.

 

So, that's it for this part, in the next of the series we are going to go back to sketch and build up some different screen designs, using our menu component and look at some more advanced things you can do with the bridge.

 

Here are all the project files:

https://www.dropbox.com/sh/0hirm3a8ut5n3w5/AABqukZ-Xc88QCT7RFVYzDDZa?dl=0

And I'll put the qml code for both of our components below:

MyButton_Symbol.ui.qml



import QtQuick 2.8
 
Item {
    id: myButton_Symbol
    width: 211
    height: 211
    property alias myButton_icon_placeholder_defaultSource: myButton_icon_placeholder_default.source
    property alias myButton_icon_placeholder_pressedSource: myButton_icon_placeholder_pressed.source
    property alias myButton_icon_placeholder_hoverSource: myButton_icon_placeholder_hover.source
    state: "default"
    property alias myButton_Symbol_labelText: myButton_Symbol_label.text
 
    Image {
        id: myButton_SymbolAsset
        x: 0
        y: 0
        source: "assets/myButton_Symbol.png"
    }
 
    Image {
        id: myButton_Symbol_default
        x: 0
        y: 0
        source: "assets/myButton_Symbol_default.png"
    }
 
    Image {
        id: myButton_Symbol_hover
        x: 0
        y: 0
        source: "assets/myButton_Symbol_hover.png"
    }
 
    Image {
        id: myButton_Symbol_pressed
        x: 0
        y: 0
        source: "assets/myButton_Symbol_pressed.png"
    }
 
    Text {
        id: myButton_Symbol_label
        x: 6
        y: 150
        width: 200
        height: 23
        color: "#ff818181"
        text: "default text"
        font.styleName: "Light"
        horizontalAlignment: Text.AlignHCenter
        font.family: "Helvetica Neue"
        font.pixelSize: 20
        verticalAlignment: Text.AlignVCenter
    }
 
    Image {
        id: myButton_icon_placeholder_pressed
        x: 70
        y: 55
        source: "assets/myButton_icon_placeholder_pressed.png"
    }
 
    Image {
        id: myButton_icon_placeholder_hover
        x: 70
        y: 55
        source: "assets/myButton_icon_placeholder_hover.png"
    }
 
    Image {
        id: myButton_icon_placeholder_default
        x: 70
        y: 55
        source: "assets/myButton_icon_placeholder_default.png"
    }
 
    MouseArea {
        id: myButton_Symbol_MouseArea
        x: 0
        y: 0
        width: 211
        height: 211
        hoverEnabled: true
    }
    states: [
        State {
            name: "default"
            when: !myButton_Symbol_MouseArea.containsMouse
                  && !myButton_Symbol_MouseArea.pressed
            PropertyChanges {
                target: myButton_Symbol_hover
                visible: false
            }
 
            PropertyChanges {
                target: myButton_Symbol_pressed
                visible: false
            }
 
            PropertyChanges {
                target: myButton_icon_placeholder_pressed
                visible: false
            }
 
            PropertyChanges {
                target: myButton_icon_placeholder_hover
                visible: false
            }
        },
        State {
            name: "hover"
            when: myButton_Symbol_MouseArea.containsMouse
                  && !myButton_Symbol_MouseArea.pressed
            PropertyChanges {
                target: myButton_Symbol_pressed
                visible: false
            }
 
            PropertyChanges {
                target: myButton_Symbol_default
                visible: false
            }
 
            PropertyChanges {
                target: myButton_icon_placeholder_pressed
                visible: false
            }
 
            PropertyChanges {
                target: myButton_icon_placeholder_default
                visible: false
            }
        },
        State {
            name: "pressed"
            when: myButton_Symbol_MouseArea.pressed
            PropertyChanges {
                target: myButton_Symbol_default
                visible: false
            }
 
            PropertyChanges {
                target: myButton_Symbol_hover
                visible: false
            }
 
            PropertyChanges {
                target: myButton_icon_placeholder_default
                visible: false
            }
 
            PropertyChanges {
                target: myButton_icon_placeholder_hover
                visible: false
            }
        }
    ]
}


myMenu_Symbol.ui.qml



import QtQuick 2.8
 
Item {
    id: myMenu_Symbol
    width: 250
    height: 850
 
    Image {
        id: myMenu_SymbolAsset
        x: 0
        y: 0
        source: "assets/myMenu_Symbol.png"
    }
 
    MyButton_Symbol {
        id: myButton_myMenu_settings
        x: 20
        y: 639
        width: 211
        height: 211
        myButton_icon_placeholder_defaultSource: "assets/myButton_icon_settings_default.png"
        myButton_icon_placeholder_hoverSource: "assets/myButton_icon_settings_hover.png"
        myButton_icon_placeholder_pressedSource: "assets/myButton_icon_settings_pressed.png"
        myButton_Symbol_labelText: "Settings"
    }
 
    MyButton_Symbol {
        id: myButton_myMenu_profile
        x: 20
        y: 428
        width: 211
        height: 211
        myButton_icon_placeholder_defaultSource: "assets/myButton_icon_profile_default.png"
        myButton_icon_placeholder_hoverSource: "assets/myButton_icon_profile_hover.png"
        myButton_icon_placeholder_pressedSource: "assets/myButton_icon_profile_pressed.png"
        myButton_Symbol_labelText: "Profile"
    }
 
    MyButton_Symbol {
        id: myButton_myMenu_dashboard
        x: 20
        y: 217
        width: 211
        height: 211
        myButton_icon_placeholder_defaultSource: "assets/myButton_icon_dashboard_default.png"
        myButton_icon_placeholder_hoverSource: "assets/myButton_icon_dashboard_hover.png"
        myButton_icon_placeholder_pressedSource: "assets/myButton_icon_dashboard_pressed.png"
        myButton_Symbol_labelText: "Dashboard"
    }
 
    MyButton_Symbol {
        id: myButton_MyMenu_home
        x: 20
        y: 6
        width: 211
        height: 211
        myButton_icon_placeholder_defaultSource: "assets/myButton_icon_home_default.png"
        myButton_icon_placeholder_hoverSource: "assets/myButton_icon_home_hover.png"
        myButton_icon_placeholder_pressedSource: "assets/myButton_icon_home_pressed.png"
        myButton_Symbol_labelText: "Home"
    }
}

 


Blog Topics:

Comments