Learn what Felgo offers to help your business succeed. Start your free evaluation today! Felgo for Your Business

Getting Started with Felgo Apps

Felgo Apps includes components for developing feature-rich, cross-platform apps with a native look and feel to interfaces and user experience patterns.

This document contains code samples, design patterns, and useful information for developers starting to learn Felgo.

Use this guide to build upon your coding knowledge and quickly learn the similarities and differences compared to cross-platform development with Felgo.

Compiling your Felgo app for a specific platform will present you with a native application package. The build process relies on the native build tools of each platform. Similar to any other native app, you can e.g. run the application on your chosen device, or upload the bundle to a store for release.

If you do not yet have Felgo installed or want to learn more about deploying Felgo Apps, see these guides:

QML Tutorial: Create Native Mobile Apps with Qt and Felgo | Free Udemy Course

Learn to build Qt-based cross platform apps for Desktop, iOS and Android with QML and Felgo! We created a comprehensive online course on Udemy to show you how:

The online course is a perfect fit for both beginners and advanced developers, as it contains many QML best practices and QML architecture tips: QML Tutorial: How to Create Native Cross Platform Apps with Qt and Felgo | Free Udemy Course

Why to use Felgo?

Felgo utilizes QML + Javascript as the main coding language and is based on Qt, a well-known and feature-rich C++ framework.

This allows to save up to 90% of code compared to other languages and frameworks. It is also a cross-platform tool. This means you can compile your application for different platforms using the same code base. In this area, Felgo supports iOS, Android and even Desktop platforms and embedded systems.

One of the biggest advantages of Felgo lies in the way you can compose your UI views, create layouts and add animations. This is where the power of QML comes into action. Felgo moves the view composition and widget rendering away from the platform directly into your app. Instead of heavy-weight and hard to animate widgets that are rendered by the platform, you can create your UI with easily extensible and customizable items.

Building your UI this way saves code, makes it easier to maintain and feels natural. It also follows the trend to move away from 'cookie cutter' apps that were common a few years ago. Modern apps focus more on custom designs that follow your brand and provide a rich user experience.

The simplicity of QML speeds up development, but the customizability and extensibility make it so powerful. You have full control over your UI items and layout while taking advantage of theme-able UI components that match the native user experience of iOS or Android widgets. Combined with ready-to-use native features, backend services and the power of C++ Qt, Felgo is the perfect choice for any app use-case.

It is also possible to put your existing iOS or Android coding knowledge to use and extend Felgo with custom native integrations if needed. Felgo already offers many cross-platform plugins that integrate native frameworks and communicate with iOS or Android.

For an overview of how to tackle different tasks in Felgo, we've summed up the most important topics and questions for you:

Introduction to QML

What is the basic UI Item in Felgo?

For Felgo, everything that you see on the screen is a QML Item. The Item type comes with everything you need to show, layout and compose UI elements of your app.

Based on your UI code that consists of QML Items, the Felgo application builds a tree of Item instances. You do not require to handle when to redraw those Items. Whenever Items change their visual state, the QML engine updates the UI automatically.

The QML rendering engine is a highly-optimized piece of C++ code, which renders your QML UI within a native view in your app. Lightweight, fast and easy to work with. The Felgo App Components offer many different items that incorporate the native iOS or Android design guidelines. With these types, you can use the power of QML to create a native-styled app. Run the app on iOS or Android, and the components will change their look to use native styles and gestures instead - without touching the code.

iOS Android

Every Felgo app begins with a single App component defined as the root of the QML tree. The following example shows a content AppPage with a centered text item:

 import Felgo

 App {
   AppPage {
     AppText {
       text: "Hello World"
       anchors.centerIn: parent
     }
   }
 }

How do I update Items?

This is a question that you no longer need to worry about. The QML Items update automatically if required. Furthermore, whenever properties of an Item change, other elements get notified. This is possible with the power of property bindings:

 import Felgo
 import QtQuick

  App {
    // property for counting # of clicks
    property int clickCount: 0

    // main content page with a text
    AppPage {

      // text, anchored to the page center
      AppText {
        text: "You clicked " + clickCount + " times!" // property binding!
        anchors.centerIn: parent
      }

      // handle touch/click on full page
      MouseArea {
        anchors.fill: parent
        onClicked: clickCount = clickCount + 1 // AppText updates automatically
      }
    }
  }

These few lines of QML code present us with a full-screen AppPage that comes with a white background. It contains a text, which is centered and prints the value of the App's clickCount property. A touch anywhere on the Page is handled by the MouseArea, which increases the counter.

Due to the property binding feature, each change of the clickCount property triggers a new evaluation of the AppText's text property. This is because the bound expression relies on the clickCount property. The AppText then updates accordingly and shows the new text value.

How do I lay out my Items?

In Felgo, you use QML to layout your app. By nesting QML items you can compose UI elements on the fly. For example, to show a text and a button on a page:

iOS Android

 import Felgo
 import QtQuick

 // App is the root item and represents the app window
 App {

   // NavigationStack can hold pages includes a navigation bar
   NavigationStack {

     // the main page with a title and content items
     AppPage {
       title: "Sample App"

       // centered text item
       AppText {
         text: "I am centered."
         anchors.centerIn: parent
       }

       // button at the bottom
       AppButton {
         text: "I am centered at the bottom."
         onClicked: console.log("Button clicked!")
         anchors.horizontalCenter: parent.horizontalCenter
         anchors.bottom: parent.bottom
       }
     }
   }
 }

Every Felgo app starts with a single App component defined as the root of the QML tree. Every app then usually includes a navigation item and some AppPage items for your content views.

How do I add or remove a component from my layout?

If you don't mind keeping the item instance in the QML tree alive, you can control the visibility of each item as you like. Items thus do not require to be re-created and can keep their state while being hidden.

This example toggles between two items with an AppButton:

 import Felgo

 App {
   AppPage {
     AppText {
       id: appTextItem
       text: "Some Text"
       anchors.centerIn: parent
     }
     AppButton {
        text: "A Button"
        visible: !appTextItem.visible // hide button if text is visible and vice versa
        onClicked: console.log("Button clicked!")
        anchors.centerIn: parent
     }

     AppButton {
       anchors.bottom: parent.bottom
       flat: false
       text: "Toggle"
       onClicked: appTextItem.visible = !appTextItem.visible // show/hide text
     }
   }
 }

How do I animate an Item?

Felgo offers an extensive animation framework with the Animation QML components. It is possible to animate every basic property of your UI elements. You can even define behaviors to automatically animate properties whenever they change.

The following example allows to fade a text by animating its opacity:

 import Felgo
 import QtQuick

 App {
   AppPage {

     // button at the bottom allows to toggle the text
     AppButton {
      anchors.horizontalCenter: parent.horizontalCenter
      anchors.bottom: parent.bottom
      text: "Toggle Text Item"
      onClicked: textItem.opacity = textItem.visible ? 0 : 1 // toggle textItem visibility
     }

     // centered text which fades when opacity changes
     AppText {
       id: textItem
       anchors.centerIn: parent
       text: "Hello World!"
       visible: opacity != 0 // also set invisible when fully transparent

       // when opacity changes ...
       Behavior on opacity {
         NumberAnimation { duration: 500 } // ... animate to reach new value within 500ms
       }
     }

   }
 }

Here is another example of how you can create complex animations. For this, you can use the SequentialAnimation and ParallelAnimation types to nest your animations. You can combine those types in any order.

 import Felgo
 import QtQuick

 App {
   NavigationStack {
     AppPage {
       title: "Complex Animation"

       AppButton {
         anchors.centerIn: parent
         text: "Move!"
         flat: false
         onClicked: {
           // Start the animation by calling start() of the top-most item
           complexAnimation.start()
         }
       }

       Rectangle {
         id: rectangle
         width: dp(100)
         height: dp(100)
         color: "black"
       }

       // All child animations will be executed one after the other
       SequentialAnimation {
         // You can start the whole animation by calling start() of the top-most item
         id: complexAnimation

         // 1. Move to right
         NumberAnimation {
           target: rectangle
           property: "x"
           to: dp(200)
           duration: 1000
         }

         // 2. Move down and change color
         // All child animations will be executed in parallel
         ParallelAnimation {
           NumberAnimation {
             target: rectangle
             property: "y"
             to: dp(400)
             duration: 1000
             easing.type: Easing.InOutQuad
           }
           ColorAnimation {
             target: rectangle
             property: "color"
             to: "blue"
             duration: 1000
           }
         }

         // 3. Move left, change color and rotate
         // All child animations will be executed in parallel
         ParallelAnimation {
           NumberAnimation {
             target: rectangle
             property: "x"
             to: 0
             duration: 1000
           }
           ColorAnimation {
             target: rectangle
             property: "color"
             to: "black"
             duration: 1000
           }
           NumberAnimation {
             target: rectangle
             property: "rotation"
             from: 0
             to: 360
             duration: 1000
           }
         }

         // 4. Move up
         NumberAnimation {
           target: rectangle
           property: "y"
           to: 0
           duration: 1000
           easing.type: Easing.InBack
         }
       }
     }
   }
 }

You can find even more animation examples on this page: Add Animations to your App

How do I draw to the screen?

Felgo and QML offer the Canvas item that allows drawing straight and curved lines, simple and complex shapes, graphs, and referenced graphic images. It can also add text, colors, shadows, gradients, and patterns, and do low-level pixel operations.

The width and height properties of the Canvas item define the drawing area. If it requires rendering, the paint signal fires. When handling the signal, you can draw to the Canvas using a Context2D object:

 import Felgo
 import QtQuick

 App {
   Canvas {
     id: mycanvas
     width: 100
     height: 200
     onPaint: {
       var ctx = getContext("2d");
       ctx.fillStyle = Qt.rgba(1, 0, 0, 1);
       ctx.fillRect(0, 0, width, height);
     }
   }
 }

How do I build custom QML Items?

Each .qml file of your project defines a reusable QML Component. The specified root QML Item determines the base component, which your new item extends. The new QML type can then add properties, signals, and functions, which form the public interface of the component.

To define the layout for the item, add some child elements and position them in the view. Each child element may also be extended with new features and properties directly where it is used. You do not require to create an own QML Item to make small additions to a single item instance in your UI.

The following example shows a clickable CustomButton.qml component with a background and text. Once imported, you can use the new type in your app:

 import Felgo
 import "relative-path-to-directory-of-custom-button"

 App {
   CustomButton {
     anchors.centerIn: parent

     // new count property only for this button instance
     property int count: 0

     text: "You clicked "+count+" times."
     backgroundColor: "yellow"
     onClicked: count++
   }
 }
 import QtQuick

 // CustomButton extends Item, which is the base type for all UI elements
 Item {
   // the default (implicit) size is based on the size of the child text element
   // the width and height thus depend on the actual text value
   implicitWidth: textItem.implicitWidth
   implicitHeight: textItem.implicitHeight

   // public properties and signals
   property color backgroundColor: "green"
   property string text: "Click Me!"
   signal clicked()

   // child elements
   Rectangle {
     anchors.fill: parent
     color: parent.backgroundColor
   }

   Text {
     id: textItem // id for referencing this text item within the component
     text: parent.text
     anchors.centerIn: parent
   }

   // handle touch/click and fire signal when the click happens
   MouseArea {
     anchors.fill: parent
     onClicked: parent.clicked() // emits clicked signal of CustomButton
   }
 }

You can rely on the App Navigation components to switch between different Pages in your app:

The most basic navigation model is a page stack which can push and pop page items. Usually a page stack makes use of a navigation bar for navigating back and forth between pages.

For that purpose, Felgo provides an item called NavigationStack.

 import Felgo

 App {
   NavigationStack {

     AppPage {
       title: "Main Page"

       AppText {
         text: "Hello World"
         anchors.centerIn: parent
       }
     }

   }
 }

This will look like the following on iOS and Android:

iOS Android

To add new pages to the stack you call NavigationStack::push(), providing the new page as a parameter. To navigate back to a previous page your users can either use the back button in the provided navigation bar or you can manually pop back in the stack by calling NavigationStack::pop().

For passing data between pages, the easiest solution is to make relevant settings or properties available in a common parent scope. Public properties, functions, and signals of an ancestor in the QML tree are available for direct access:

 import Felgo
 import QtQuick

 App {
   id: app

   property int count: 0

   // main page
   NavigationStack {
     AppPage {
       id: mainPage
       title: "Main"

       Column {
         anchors.centerIn: parent

         // text to show the current count and button to push the second page
         AppText {
           anchors.horizontalCenter: parent.horizontalCenter
           text: "Count " + app.count
         }
         AppButton {
           text: "Push Counter Page"
           onClicked: mainPage.navigationStack.push(counterPageComponent)
         }
       }
     }
   }

   // inline-definition of a component, which is later pushed on the stack
   Component {
     id: counterPageComponent
     AppPage {
       title: "Change Count"
       property AppPage target: null

       Column {
         anchors.centerIn: parent

         // buttons to increase or decrease the count, which is displayed on the main page
         AppButton {
           text: "Count ++"
           onClicked: {
             app.count++
           }
         }
         AppButton {
           text: "Count --"
           onClicked: {
             app.count--
           }
         }
       }
     }
   }
 }

Apart from the NavigationStack, which which allows to navigate back and forth between pages, the Navigation type is the main component to create your app menu:

 import Felgo

 App {
   Navigation {
     // enable both tabs and drawer for this demo
     // by default, tabs are shown on iOS and a drawer on Android
     navigationMode: navigationModeTabsAndDrawer

     NavigationItem {
       title: "Home"
       iconType: IconType.home

       NavigationStack {
         AppPage {
          title: "Main Page"
         }
       }
     }

     NavigationItem {
       title: "Lists"
       iconType: IconType.list

       NavigationStack {
         AppPage {
          title: "Lists"
         }
       }
     }

   }
 }

This example shows how to add two root navigation options to your app. On iOS the Navigation item displays an iOS-style tab bar on the bottom of the screen. On Android the navigation options are provided within a navigation drawer, sliding in from the left edge of the screen.

As you can see in the example it's also possible to stack different navigation concepts into each other. The example shows two tabs as the main navigation concept with an included NavigationStack each.

For more information about the Navigation item, read the full documentation here.

How do I navigate to another app?

In iOS, to send the user to another application, you use a specific URL scheme. You can use those URL schemes with Felgo with the NativeUtils::openApp() or NativeUtils::openUrl() methods.

Threading & Asynchronous Code

How do I write asynchronous code?

As Felgo relies on QML and Javascript, updates to the UI are already handled in a highly asynchronous and event-driven way. You weave-in your Javascript code as part of signal handlers that execute when certain events or user interactions happen. The QML rendering engine is highly optimized, so you do not need to worry about blocking the UI when adding your view logic.

Communication with your application backend is also easy, as you can use the asynchronous HttpRequest.

This example fetches a JSON response containing the URL to an image. The request happens asynchronously. The returned URL is then set as the AppImage source, which is able to asynchronously load an image from an URL:

 import Felgo
 import QtQuick

 App {

   property string serverUrl: "https://jsonplaceholder.typicode.com/photos/1"
   property var jsonData: undefined

   // handler function to be executed when the App Item is fully created, starts web requests
   Component.onCompleted: {
     // the 3rd parameter of open(...) is the asynchronous flag
     var request = HttpRequest
       .get(serverUrl)
       .then(function(res) {
         jsonData = res.body // keep JSON result
       })
       .catch(function(err) {
         console.log(err.message)
         console.log(err.response)
       });
   }

   AppPage {

     // just some spinning icon to show asynchronous loading of image
     AppIcon {
       anchors.centerIn: parent
       iconType: IconType.refresh
       NumberAnimation on rotation {
         loops: Animation.Infinite
         from: 0
         to: 360
         duration: 1000
       }
     }

     AppImage {
       // expression for source relies on the jsonData property (property binding!)
       // the REST api returns the web url to an image, which we can set directly to load the image
       source: jsonData !== undefined ? jsonData.url : ""
       anchors.fill: parent
       fillMode: AppImage.PreserveAspectFit
       // additionally you can make the image loading itself asynchronous
       // this is recommended for images loaded from web source
       asynchronous: true
     }
   }
 }

After request completion, the result is stored to the jsonData property. The expression for the image source relies upon on the property, so the AppImage will automatically update and show the image as soon as the data arrives - nothing more to do.

How to Access REST Services with Qt and Felgo?

REST and RESTful web services are the most common way to access data through the Internet. In addition to the Felgo HttpRequest type of the above example, you can also use the XMLHttpRequest object, which QML supports by default. This article gives detailed insights on how to create an App and connect to a REST service with Felgo using XmlHttpRequest: How to Access REST Services: Weather Service Example App

However, we recommended to connect to REST services with the new Felgo HttpRequest type, as it offers more features and an easier API.

How do you move work to a background thread?

For long-running and data-intense operations, it still makes sense to actively use a separate thread and notify your UI once the work is done. To quickly spawn a new thread in QML, you can add a WorkerScript item:

 import Felgo
 import QtQuick

 App {
   AppText {
     id: myText
     text: 'Click anywhere'
   }

   WorkerScript {
     id: myWorker
     source: "script.js" // script to run on new thread

     onMessage: msg => myText.text = msg.reply
   }

   MouseArea {
     anchors.fill: parent
     onClicked: myWorker.sendMessage({ 'x': mouse.x, 'y': mouse.y })
   }
 }

The above worker script specifies a JavaScript file, script.js, which is handled in a new thread. Here is an example script.js, which simply returns the passed mouse position:

 WorkerScript.onMessage = function(message) {
     // ... long-running operations and calculations are done here
     WorkerScript.sendMessage({ 'reply': 'Mouse is at ' + message.x + ',' + message.y })
 }

For more control over your threads and the best possible performance, you also have the full power of Qt C++ at your hands. You can find a guide how to mix Felgo QML code with Qt C++ components here: How to Expose a Qt C++ Class with Signals and Slots to QML.

Stepping into the C++ world also gives access to e.g. advanced networking features like a socket or Bluetooth connection.

The demo is also available with the Felgo SDK here: <Path to Felgo>/Examples/Felgo/appdemos/cpp-qml-integration

Project structure, localization, dependencies and assets

How do I include multi-resolution image assets for Felgo?

Felgo projects come with an assets folder by default. To bundle the folder content along with your application, the CMakeLists.txt project configuration includes a setup like:

 file(GLOB_RECURSE AssetsFiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} assets/*)
 deploy_resources("${AssetsFiles}")
 

Assets are any type of file, not just images. For example, you might also have a JSON file located in the assets folder.

In addition, your project also holds platform directories, like the android or ios folder. They handle platform-specific configurations like the android/AndroidManifest.xml, ios/Project-Info.plist file or your app icon configuration.

For images, Felgo follows a simple density-based format. The MultiResolutionImage component automatically chooses the best image version for each device's screen.

By default, Felgo allows you to provide three different images, for example:

  • imageSwitching.png (e.g. 50×20 px)
  • +hd/imageSwitching.png (e.g. 100×40 px)
  • +hd2/imageSwitching.png (e.g. 200×80 px)

This code snippet selects the best version of the above image automatically:

 import Felgo

 App {

   MultiResolutionImage {
     source: Qt.resolvedUrl("../assets/imageSwitching.png") // relative path from QML file to image

     // for the size, we specify density independent pixels
     width: dp(50)
     height: dp(20)
   }

 }

To specify density-independent sizes for your UI elements, you can rely on the App::dp() function. Many of the Felgo Apps Components are already set up to have the same physical size on all screens - regardless of their density.

For more information about density-independence in Felgo, see Supporting Multiple Screen Sizes & Screen Densities with Felgo Apps.

Where do I store strings? How do I handle localization?

Felgo is based on the Qt platform, so you can rely on Qt Linguist tools for your translations. Adding translations to your app then requires these three steps:

  • Use the qsTr() function to mark texts for translation in your QML code.
  • Generate translation files for all strings (in XML format).
  • Translate the texts.
  • Release translation binaries for usage in your app.

See here for a full guide about internationalization and string translation: Internationalization with Felgo

How do I add dependencies?

For iOS, Felgo creates a native iOS IPA app file using the same iOS build tools that you already know. To configure the iOS app and build, you have access to a generated Xcode project file that you can configure to your needs. To configure the Android build, you have access to the AndroidManifest.xml and build.gradle in the android folder of your project.

When working with Felgo Plugins for native features, only a single dependency per plugin includes all required frameworks. See the plugin documentation page for more information about plugin integration.

Layouts

Layout and Positioning

There are many different layouting mechanisms and components available with Felgo. For a short introduction, please see Create Layouts and Position Components in Your App.

How do I handle landscape transitions in Felgo?

The App::portrait or App::landscape properties allow to optimize your layout for different orientations. Similar other properties in QML, you can add handlers for property changes or use property bindings to adapt the UI automatically.

 import Felgo

 App {
   id: app
   onPortraitChanged: {
     if(portrait)
       console.log("orientation changed to portrait")
     else
       console.log("orientation changed to landscape")
   }

   AppText {
     text: app.landscape ? "Landscape Mode" : "Portrait Mode"
     anchors.centerIn: parent
   }
 }

You can also manually change the orientation settings at runtime, e.g. like this:

 import Felgo
 import QtQuick

 App {
   NavigationStack {
     AppPage {
       title: "Orientation Lock"

       Column {
         AppButton {
           text: "Lock to landscape"
           onClicked: NativeUtils.preferredScreenOrientation = NativeUtils.ScreenOrientationLandscape
         }
         AppButton {
           text: "Remove orientation lock"
           // Resets to the orientation defined in AndroidManifest.xml / Project-Info.plist
           onClicked: NativeUtils.preferredScreenOrientation = NativeUtils.ScreenOrientationDefault
         }
       }
     }
   }
 }

Gesture detection and touch event handling

How do I add an onClick listener to an item in Felgo?

If an item already supports user interaction, you can directly handle the events in your code. The following example adds an AppButton and handles the clicked signal:

 import Felgo

 App {

   AppButton {
     text: "Click Me!"
     anchors.centerIn: parent
     onClicked: text = "Thanks!"
   }

 }

To handle clicks for a custom Item, you can add a MouseArea:

 import Felgo
 import QtQuick

 App {

    Rectangle {
     width: dp(200)
     height: dp(200)
     color: "lightyellow"
     anchors.centerIn: parent

     MouseArea {
       anchors.fill: parent
       onClicked: parent.color = "lightgreen"
     }
   }

 }

How do I handle other gestures on items?

You can work with different MouseArea signals to adapt it for your use-case. However, the MouseArea can only handle a single touch point. For more information on gestures and handling multiple touch points, please see: Handle Touch and Gestures in Your App.

ListViews & Models

What is the alternative to a ListView in Felgo?

The easiest way to create a list is to use the AppListView type together with a SimpleRow delegate for the list cells:

Android iOS

 import Felgo

 App {
   NavigationStack {
     AppPage {
       title: "Basic List Example"

       AppListView {
         delegate: SimpleRow {}
         model: [
           {
             text: "Apple",
             detailText: "A delicious fruit with round shape",
             iconType: IconType.apple
           },

           {
             text: "Beer",
             detailText: "A delicous drink",
             iconType: IconType.beer
           }
         ]
       }
     }
   }
 }

The model-delegate system also supports JSON data structures for your data model. This makes it easy to work with and display data from REST APIs.

How do I know which list item is clicked on?

The SimpleRow::selected signal allows to handle click events on a list cell. For custom delegate items, you can add your own MouseArea for handling touch input.

 import Felgo

 App {
   NavigationStack {
     AppPage {
       title: "Clickable List Example"

       AppListView {
         delegate: SimpleRow {
           onSelected: console.log("Clicked Item #"+index+": "+JSON.stringify(modelData))
         }
         model: [
           {
             text: "Apple",
             detailText: "A delicious fruit with round shape",
             iconType: IconType.apple
           },

           {
             text: "Beer",
             detailText: "A delicous drink",
             iconType: IconType.beer
           }
         ]
       }
     }
   }
 }

How do I update ListViews dynamically?

The list view updates its UI automatically whenever the model changes - at least when you describe your model as a ListModel type. For plain JSON-based models, the list is not notified when some data values within the JSON structure change. In this case, you can manually trigger a property-changed signal, which in turn updates the UI of the list:

 import Felgo

 App {
   NavigationStack {
     AppPage {
       id: page
       title: "Append List Item Example"

       property var listData: [
           {
             text: "Apple",
             detailText: "A delicious fruit with round shape",
             iconType: IconType.apple
           },

           {
             text: "Beer",
             detailText: "A delicous drink",
             iconType: IconType.beer
           }
         ]

       AppListView {
         id: listView
         model: page.listData
         delegate: SimpleRow {
           onSelected: {
             page.listData.push(modelData) // add copy of clicked element at end of model
             page.listDataChanged() // signal change of data to update the list
           }
         }
       }
     }
   }
 }

More list examples are available here: Use ScrollViews and ListViews in Your App

Styling and Themes

Every Felgo application comes with a set of default styles, depending on the underlying platform. As seen above, a simple app with a navigation stack looks like the following on iOS and Android:

iOS Android

Usually you want an app's style to match your app or company CI, or just want to add some color to it. For that purpose Felgo provides a global Theme object which makes it easy to change styling for all components within your app.

The root component of all apps, the App component, offers a signal handler which allows overriding the default styles. Let's have a look at some examples:

Tint Color

A lot of Felgo Apps components use a special color reference, called the tint color, for their main outline color. You can change that color by overriding the Theme's tintColor property:

 import Felgo

 App {

   onInitTheme: {
     Theme.colors.tintColor = "red"
   }

   AppPage {
     AppSwitch {
       anchors.centerIn: parent
     }
   }
 }

This example sets the global tint color to red, which is then also applied to the AppSwitch component.

This will look like the following on iOS and Android:

iOS Android

Style the Navigation Bar

If you use the NavigationStack component you can style the included navigation bar in the following manner:

 import Felgo

 App {

   onInitTheme: {
     Theme.navigationBar.titleColor = "white"
     Theme.navigationBar.backgroundColor = "#57adee" // blue color
     Theme.colors.statusBarStyle = Theme.colors.statusBarStyleWhite
   }

   NavigationStack {

     AppPage {
       title: "Main Page"

       AppText {
         text: "Hello World"
         anchors.centerIn: parent
       }
     }

   }
 }

The resulting app includes a blue navigation bar with white title text and a white status bar on iOS.

This will look like the following on iOS and Android:

iOS Android

Change the Platform Theme

The default Theme settings implement platform-specific styles, like the default iOS style on iOS or Material Style on Android, for a native look and feel on both platforms. The following example shows how to manually change the used platform theme in your code:

 import Felgo

 App {

   Navigation {
     NavigationItem {
       title: "Main"
       iconType: IconType.heart

       NavigationStack {
         AppPage {
           title: "Main Page"
           AppButton {
             text: "Switch Theme"
             onClicked: Theme.platform = Theme.isAndroid ? "ios" : "android"
             anchors.centerIn: parent

           }
         }
       }
     }

     NavigationItem {
       title: "Second"
       iconType: IconType.thlarge

       NavigationStack {
         AppPage {  title: "Second Page" }
       }
     }
   }
 }

Felgo allows you to style your app with many app-wide theme settings. This is in most cases more convenient than styling every single component itself. You can see Style Your App with Themes for some simple theming examples.

Fonts

Felgo components make use of two different fonts, the Theme::normalFont and the Theme::boldFont. By default these fonts match the platform's default font for Felgo Apps components.

If you want to explicitly provide your own font you can override the Theme properties with a FontLoader object:

 import Felgo
 import QtQuick

 App {

   onInitTheme: {
     Theme.normalFont = arialFont
   }

   FontLoader {
     id: arialFont
     source: "fonts/Arial.ttf" // loaded from your assets folder
   }

   AppPage {
     AppText {
       text: "I'm in Arial"
     }
   }
 }

Make sure to add your custom fonts to your app's assets and to provide the correct path in the FontLoader object.

You can then also use the custom font in your own app components, like the following example:

 Text {
  // Set reference to the global app font
  font.family: Theme.normalFont.name

  text: "Custom text item"
 }

Instead of replacing the general Theme font, you can also use a FontLoader and only overwrite the font.family property for certain text items.

How do I style my Text items?

Along with the font, you can customize many other styling properties of a Text item, such as:

  • color
  • elide
  • font.bold
  • font.capitalization
  • font.family
  • font.italic
  • font.letterSpacing
  • font.pixelSize
  • font.weight
  • font.wordSpacing
  • horizontalAlignment
  • lineHeight
  • maximumLineCount
  • verticalAlignment
  • wrapMode

Form input

Input Hints

Input controls like AppTextInput or AppTextField own a placeHolderText property, which you can use for your hint text.

 import Felgo
 import QtQuick

 App {
   AppPage {

     // remove focus from textedit if background is clicked
     MouseArea {
       anchors.fill: parent
       onClicked: textEdit.focus = false
     }

     // background for input
     Rectangle {
       anchors.fill: textEdit
       anchors.margins: -dp(8)
       color: "lightgrey"
     }

     // input
     AppTextInput {
       id: textEdit
       width: dp(200)
       placeholderText: "What's your name?"
       anchors.centerIn: parent
     }
   }
 }

Validation Errors

The text input components provide predefined validators that you can use, they are called inputMethodHints.

You can also add custom validators to restrict the accepted input to a certain input type or expression. Input that does not match the validator is not accepted. To do custom validations and show errors for accepted input, you can add simple checks and control the visibility of errors with property bindings:

 import Felgo
 import QtQuick

 App {
   // background for input
   Rectangle {
     anchors.fill: textInput
     anchors.margins: -dp(8)
     color: "lightgrey"
   }

   // input
   AppTextInput {
     id: textInput
     width: dp(200)
     placeholderText: "What's your name?"
     anchors.centerIn: parent

     // only allow letters and check length
     validator: RegularExpressionValidator {
       regularExpression: /[A-Za-z]+/
     }
     property bool isTooLong: textInput.text.length >= 6
   }

   // show error if too long
   AppText {
     text: "Error: Use less than 6 letters."
     color: "red"
     anchors.top: textInput.bottom
     anchors.topMargin: dp(16)
     anchors.left: textInput.left
     visible: textInput.isTooLong
   }
 }

Native Utils and Felgo Plugins

GPS Positioning and Sensors

Felgo allows you to access various device sensors, with the Qt Sensors QML Types. The components for Positioning, Maps and Navigation are found in the Qt Positioning and Qt Location modules.

For an easy and convenient way to show a map with the current user position, you can also rely on the AppMap type:

 import Felgo
 import QtLocation
 import QtQuick

 App {
   // show the map
   AppMap {
     anchors.fill: parent

     // configure map provider
     plugin: Plugin {
       name: "maplibregl"
       // configure your styles and other parameters here
       parameters: [
         PluginParameter {
           name: "maplibregl.mapping.additional_style_urls"
           value: "https://api.maptiler.com/maps/streets/style.json?key=get_your_own_OpIi9ZULNHzrESv6T2vL"
         }
       ]
     }

     // configure the map to try to display the user's position
     showUserPosition: true
     zoomLevel: 13

     // check for user position initially when the component is created
     Component.onCompleted: {
       if(userPositionAvailable)
         center = userPosition.coordinate
     }

     // once we successfully received the location, we zoom to the user position
     onUserPositionAvailableChanged: {
       if(userPositionAvailable)
         zoomToUserPosition()
     }
   }
 }

Camera Access

The Felgo NativeUtils allow to conveniently trigger native device features from within your QML code. For example to show dialogs, open the camera, access the gallery or work with contacts.

This simple example allows to take a photo with the device camera:

 import Felgo
 import QtQuick

 App {
   AppImage {
     id: image
     anchors.fill: parent
     fillMode: AppImage.PreserveAspectFit
     autoTransform: true
   }

   AppButton {
     text: "Take Photo"
     anchors.centerIn: parent
     onClicked: NativeUtils.displayCameraPicker()
   }

   Connections {
     target: NativeUtils
     onCameraPickerFinished: (accepted, path) => {
       image.source = ""
       if(accepted) {
         image.source = path
       }
     }
   }
 }

To embed a camera view directly in your app, you can use the Camera and VideoOutput types:

 import Felgo
 import QtQuick
 import QtMultimedia

 App {
   CaptureSession {
     camera: Camera {
       active: true
     }
     videoOutput: videoOutput
   }

   VideoOutput {
     id: videoOutput
     anchors.fill: parent
     fillMode: VideoOutput.PreserveAspectCrop
   }
 }

Push Notifications

Felgo supports both server-triggered and local notifications with Felgo Plugins. All plugins offer a platform-agnostic API and rely on native frameworks for each platform.

See the GoogleCloudMessaging Plugin or the OneSignal Plugin to add server-triggered notifications. Local notifications are available with the Notification Plugin. The following example schedules a notification to be fired after 5 seconds and trigger the notificationFired signal. You can also try to put the app in the background, to get the notification on your home screen. In this case, the notificationFired signal will be called when you enter the app after clicking on the notification.

 import QtQuick
 import Felgo

 App {
   NotificationManager {
     id: notificationManager
     onNotificationFired: notificationId => {
       NativeUtils.displayMessageBox("Notification", "id: "+notificationId, 1)
     }
   }

   Notification {
     id: idleNotification
     notificationId: "idleNotification"
     message: "Anyone here? Haven't seen you in a while..."
     timeInterval: 5 // in seconds
   }

   AppButton {
     text: "Schedule Notification (5s)"
     anchors.centerIn: parent
     onClicked: {
       // Cancel old notification if scheduled
       notificationManager.cancelNotification(idleNotification.notificationId)
       // Schedule idleNotification
       notificationManager.scheduleNotification(idleNotification)
     }
   }
 }

Secure Keychain Storage

On iOS and Android, you can use the native Keychain to store, read and delete data securely and persistently.

On iOS, each stored value is handled as a separate keychain item representing a generic password. On Android, each value is persisted in SharedPreferences with AES-256 encryption. The automatically generated encryption key is securely stored via the Android KeyStore system.

Here is an example how to use the Keychain storage functionality using the Felgo NativeUtils:

 import Felgo
 import QtQuick

 App {

   AppButton {
     text: "Store in Keychain"
     onClicked: NativeUtils.setKeychainValue("identifier", "value")
   }

   AppButton {
     text: "Read Keychain"
     onClicked: NativeUtils.getKeychainValue("identifier")
   }

   AppButton {
     text: "Delete from Keychain"
     onClicked: NativeUtils.clearKeychainValue("identifier")
   }
 }

Facebook Login

Felgo allows integrating Facebook with the Facebook Plugin. See the plugin documentation for more information and detailed integration steps.

Google Firebase Integration

The Firebase Plugin is the right tool for integrating Firebase Authentication, Real-time Database or Cloud Storage features. See the plugin page for more information and detailed integration steps.

The Firebase Plugin has seen lots of improvements and new features lately. In case you are missing anything or run into issues, don't hesitate to get in touch!

How do I build my own custom native integrations?

In Felgo you code with QML, so going native first means to step into the Qt C++ world. You can find a guide how to mix Felgo QML code with Qt C++ components here: How to Expose a Qt C++ Class with Signals and Slots to QML

The demo is also available with the Felgo SDK: <Path to Felgo>/Examples/Felgo/appdemos/cpp-qml-integration

Working with native Android code from C++ then requires JNI as the bridge between the two languages. Weaving in native iOS code is a little easier, as Objective-C is directly compatible with C++. But before you dive in too deep: Our developers are experts at building such native integrations, and we're happy to add features or build extensions as part of our support package offering!

Databases and Local Storage

App Settings

The App::settings property allows to store simple key/value pairs in a local database. If you format the value as a JSON string, you can also store more complex data in a very easy way.

 import Felgo
 import QtQuick

 App {
   id: app
   // this property holds how often the app was started
   property int numberAppStarts

   Component.onCompleted: {
     // getValue() returns undefined, if no setting for this key is found, so when this is the first start of the app
     numberAppStarts = app.settings.getValue("numberAppStarts") || 0 // defaults to '0' if 'undefined' is returned
     numberAppStarts++

     app.settings.setValue("numberAppStarts", numberAppStarts)
   }

   NavigationStack {

     AppPage {
       title: "Settings"

       AppText {
         anchors.centerIn: parent
         text: "App starts: " + numberAppStarts
       }
     }
   }
 }

The App settings in the above example internally rely on the Storage component. You can also add your own Storage to save your key-value pairs to a distinct database. You can find more info on storage, data and Firebase here: Store Data Persistent

SQLite Databases

You can access a local SQLite Database using the Qt Quick Local Storage QML Types.

Felgo Apps Video Tutorials

Fast-forward your development with the help of our video tutorials: Felgo Video Tutorials

There's also a comprehensive online course available on Udemy. It contains 44 lectures and more than 4 hours of video course material. The lectures focuse on many important topics for beginners as well as advanced developers: QML Tutorial: How to Create Native Cross Platform Apps with Qt and Felgo | Free Udemy Course

More App Use-Case Examples

In the documentation navigation on the left-hand side, you can find tons of useful examples grouped into the main use-cases for app developers. Make sure to check them out!

Further Reading

Felgo Apps includes components for developing cross-platform apps with a native look and feel to interfaces and user experience patterns.

In addition to Felgo Apps components, you will probably make use of components from the QtQuick module provided by the Qt framework itself.

Writing applications with Felgo Apps Components

QML and QtQuick documentation

Qt_Technology_Partner_RGB_475 Qt_Service_Partner_RGB_475_padded