QML vs Swift (part 2)

In this part we’ll see how use the Button in both the languages.

In QML we define the button in this way:

Button {  text: "A button"  id: control  onClicked: {
   // Your action  }}



Where in the “text” property we set the label of the button and in the onClicked is executed what we need when the button is tapped/clicked. Instead in SwiftUI we have:

Button(action: {       // Your action
      }){
        Text("button")
             
      }



For the SwiftUI button the code to execute when the user clicks the button go in the action block. Instead for the property about the text can be changed modifying the properties of the object Text. A example to customization the button with QML:

Button {
    text: "A button"
    id: control

    onClicked: {
        
    }
    contentItem: Text {
            text: control.text
            font: control.font
            opacity: enabled ? 1.0 : 0.3
            color: control.down ? "#17a81a" : "#21be2b"
            horizontalAlignment: Text.AlignHCenter
            verticalAlignment: Text.AlignVCenter
            elide: Text.ElideRight
    }
    
    background: Rectangle {
        implicitWidth: 100
        implicitHeight: 25
        border.width: control.activeFocus ? 2 : 1
        border.color: "#888"
        radius: 40
        gradient: Gradient {

            orientation: Gradient.Horizontal
            GradientStop { position: 0 ; color: control.pressed ? "red" : "red" }
            GradientStop { position: 1 ; color: control.pressed ? "blue" : "blue" }
        }
    }
}



To change the properties of the text we must assign an Text Object to the contenrItem (in this case QML and SwiftUI are similar) and to change the bacground we can assign a rectangle with solid color or with gradient. It’s possible also use other object (i.e. image) for the background. A example to customization the button with SwiftUI:

Button(action: {}) {
            Text("Button")
                .fontWeight(.bold)
                .font(.title)
                .padding()
                //.background(Color.red)
                .background(LinearGradient(gradient: Gradient(colors: [Color.red, Color.blue]), startPoint: .leading, endPoint: .trailing))
                .cornerRadius(40)
                .foregroundColor(.white)
                .padding(10)
        }



In SwiftUI we change the background color (solid or not) modifying only the properties of the Text object because the Text object is used to “show” the button. If we want use an image for the button we must replace the Text object with the Image object.

QML VS. SwiftUI (part 1)

In this series I’ll show the difference between QML and SwiftUI. Both are declarative language, the first on is part of the Qt cross-platform library, the second is from Apple, introduced in the last summer.

The idea that is at the base of these languages is simplify the design of the GUI, with the dream that the designer can draw the interface with tools as Photoshop, Sketch or gimp and with some plugin have the code in some programming language, for both the languages we have some attempt in this direction. Done this introduction, let’s start to see a bit of code.

// QML TEXT
import QtQuick 2.12
import QtQuick.Window 2.12Window 
{
   title: qsTr("Hello World")   
   Text {     
       id: name     
       text: qsTr("text")     
       anchors.verticalCenter: parent.verticalCenter
       anchors.horizontalCenter: parent.horizontalCenter     
       font.family: "Helvetica [Cronyx]"    
    }
}



In the previous code, we show a the text “text” centered vertically and horizontally in window. To default in QML the object are positioned in the left/top corner.

In SwiftUI we have:

import SwiftUI

struct ContentView: View {
    var body: some View {
           Text("Hello, World!")
           .fontWeight(.bold)
    }
}



In SwiftUI the widgets are showed already centered in the View, so we have not specify the alignment how in QML, but if we want the Text in the left/top corner we must specify:

import SwiftUI

struct ContentView: View {
    var body: some View {
        VStack {
            HStack{
                Text("Hello, World!")
                .fontWeight(.bold)
                Spacer()
            }
            Spacer()
        }
    }
}



In the HStack (horizontal stack) we have the Text and the Spacer that fill the space not covered from the Text, so the Text is pushed on the left, in dual way for the Vertical Stack (VStack) the Spacer push on top the HStack.

The first visible difference between QML and SwiftUI is how the properties are set for the objects, in QML we have propertyName: value within the {} block of the element, instead in SwiftUI ther properties are set with .property after the {} block (when present).

QML VS SwiftUI (Appendix)

woman coding on computer

In the previous stories we shown the main difference between the QML and SwiftUI, both are declarative, QML has a lot of components because is more older but also because it used on a lot of platforms.

Honestly (also if I like Qt) build a mobile application with Qt having the native look and feel sometime can require a bit of work, I want consider in this moment only the GUI side (I know that I can reuse the base code also for other platform).

For this topic and for the people that prefer Qt how cross-platform tool I suggest a solution created on Qt: Felgo. I’m not Felgo employee! I would show an example, take the code from previous story (remove current item with right swipe action). List, with right swipe action, in swift:

struct People: Identifiable {
    var id = UUID()
    var name: String
    var image: String
}struct ContentView: View {
    @State var peoples = [People(name:"Albert", image: "albert.png"), People(name: "Tom", image: "tom.png"),People(name: "Jeff", image:"jeff.png"),People(name: "Jennifer",image: "jennifer.png"), People(name: "Steve", image: "steve.png"), People(name: "Bob", image: "bob.png")]
    var body: some View {
        List {
            ForEach(peoples, id: \.id) { people in
                HStack {
                    Text(people.name)
                    Image(people.image)
                }
            }
            .onDelete { (indexSet) in
                self.peoples.remove(atOffsets: indexSet)
            }
        }
    }
}


In pure Qt

ListView {
    id: listView
    anchors.fill: parent
    model: ListModel {
        ListElement { img: "bob.png"; name: "Bob" }
        ListElement { img: "jennifer.png"; name: "Jennifer" }
        ListElement { img: "tom.png"; name: "Tom" }
        ListElement { img: "denise.png"; name: "Denise" }
    }
    delegate: SwipeDelegate {
        id: swipeDelegate
        text: model.name
        width: parent.width
        
        ListView.onRemove: SequentialAnimation {
            PropertyAction {
                target: swipeDelegate
                property: "ListView.delayRemove"
                value: true
            }
            NumberAnimation {
                target: swipeDelegate
                property: "height"
                to: 0
                easing.type: Easing.InOutQuad
            }
            PropertyAction {
                target: swipeDelegate
                property: "ListView.delayRemove"
                value: false
            }
        }
        
        contentItem: Item {
            RowLayout {
                Text {
                    text: swipeDelegate.text
                    font: swipeDelegate.font
                    elide: Text.ElideRight
                    visible: swipeDelegate.text
                    horizontalAlignment: Text.AlignLeft
                    verticalAlignment: Text.AlignVCenter
                }
                Image {
                    source: model.img
                    visible: swipeDelegate.text
                    horizontalAlignment: Text.AlignLeft
                    verticalAlignment: Text.AlignVCenter
                }
            }
        }
        
        swipe.right: Label {
            id: deleteLabel
            text: qsTr("Delete")
            color: "white"
            verticalAlignment: Label.AlignVCenter
            padding: 12
            height: parent.height
            anchors.right: parent.right
            
            SwipeDelegate.onClicked: listView.model.remove(index)
            
            background: Rectangle {
                color: deleteLabel.SwipeDelegate.pressed ? Qt.darker("tomato", 1.1) : "tomato"
            }
        }
    }
}


Now with Felgo

AppListView {
    id: listView
    anchors.fill: parent

    model:  ListModel {
        ListElement { img: "bob.png"; name: "Bob" }
        ListElement { img: "jennifer.png"; name: "Jennifer" }
        ListElement { img: "tom.png"; name: "Tom" }
        ListElement { img: "denise.png"; name: "Denise" }
    }
   
    delegate: SwipeOptionsContainer {
        id: container
        SimpleRow {
            text: modelData.name
            imageSource: modelData.img
        }
        rightOption: IconButton {          
            color: "red"

            icon: IconType.trash
            height: row.height
            onClicked: {
                  listView.model.remove(index)
            }
        }
}


Using Felgo the number of lines of code are near to that of Swiftui and this code run also on Android!

From my point of view, if you want develop with Qt/QML and you must speed-up Felgo is a must for real project. I presented only the advantage from the GUI side, if we talk about notification, integration with social SSO with Qt prepare you to write a lot of native code and integrate it in your c++. It’s nice and cool from geek side (and I’m) but it’s could not cool from business side.