CalculatorApp Tutorial

Learn to develop a native, cross platform calculator app for Android and iOS using Swift
Level : SCADE Beginner / Intermediate

The Calculator App

The CalculatorApp demonstrates many capabilities and features of the SCADE platform:

  • Creating a project and building an app on Android and iOS
  • SCADE Simulator
  • AutoLayout
  • Beginner and intermediate Grid Layout design
  • Click and Touch Events
  • Model / View Bindings
  • Third party Library integration
  • SPM Manager Support

📘

Source Code

The source code can be found here https://github.com/scadedoc/UgExamples/tree/master/UgCalculator

Create the project

Follow these simple steps

  1. In the IDE, right click and choose New > SCADE project
  2. Enter the name of the project, i.e. UgCalculator and press next.
  3. Expand the project and open the empty main.swift.page
  4. Select the UgCalculator project from the launchbar and select SCADE Simulator as the target
  5. Press the RUN button to start the SCADE Simulator and startup your empty app.

The SCADE Simulator

With the SCADE Simulator, developers can run and test their app immediately. It has much faster startup times compared with iOS or Android simulators. It's capable of displaying 95% of all mobile phone features and a great way of testing you app.

The App Layout

  • The app consists of one page (main.swift.page)
  • The layout type of each page is by default AutoLayout
  • The app consists of two parts:
  • Part 1: The number display part of the top consists of a horizontal container and a label control
  • Part 2: The keypad display consists of a 4 x 5 grid control. The container contains 19 buttons for the different numbers and operators. It also contains of some additional elements to display the 0 key nicely.

Create the number display panel

Drag and drop a horizontal container onto the page and autolayout it

  • name it viewNumberDisplay
  • Set the background color to #313438
  • Click on AutoLayout constraint and
  • match the top, right, left and bottom and set the constant to 0

Adjust the bottom constraint to set the display height to100 px

  • In the Layout / Constraints list, select the viewNumberDisplay.bottom = ... constraint
  • Change the target anchor to Top
  • Set the constant to 100

Drag and Drop a text label control into the horizontal container

  • Set the name to lbNumberDisplay
  • Set the text / title label to "0"
  • Set the text alignment to right

Set the layout

  • Set horizontal layout to right, Match parent, Fill space
  • Set the vertical layout to bottom, wrap content, Fill space

Set the font

  • Set the font to Open Sans, Light, 40
  • Set the font color to color snow

Create the visual keypad

The visual keypad consists of a Grid control that is 4 columns wide and 5 rows deep. Each of the keys is represented by a button.

The SCADE layout manager supports automatic scaling, so that the controls display nicely and correctly on any device. We will set the buttons' layouts to Fill space and Match parent in order to always use the maximal horizontal and vertical space available.

Follow these steps to create the keypad:

Add grid control and autolayout it

  • Drag and drop a grid container control onto the page
  • Autolayout grid control and set top to bottom of viewNumberDisplay
  • Set grid control's left and right side to the main page
  • Set grid's bottom to the main page bottom
  • Set the background color to color Licorice

📘

Copying controls

Use Command + C and Command + V to copy controls

Add buttons for the AC, +/-, % and divide keys

  • Drag and drop a button into the upper left corner of the grid
  • Set the font to Open Sans Regular, Size 24
  • Set the background color to #45474C
  • Set the horizontal layout to match parent and fill space
  • Set the vertical layout to Middle, match parent and fill space
  • Copy and paste the button and add 3 additional buttons
  • Set the text to AC, +/- , % and /
  • Name the AC button btnClear

Add buttons for the number keys 0..9 and .

  • Copy a button
  • Set the background color to #646568
  • Copy the button 10 more times and arrange the buttons in the grid
  • Set the title label (Text) to the numbers 0 .. 9 and "."
  • For the "." key, set General > Baseline to hanging
  • Set the name for each button as btnNumber, so the 1 key is names btnNumber1

Add the operator keys for divide, multiple, plus, minus and equal

  • Set the background color of the divide button to #FF9E0B
  • Copy it 4 times and arrange it within the grid to represent the operator keys
  • Set the title label using this unicode characters : ÷, × , − , + , =
  • Name the buttons btnDivide, btnPlus, btnMinus, btnMultiply and btnEqual

Adjust spacing and margins to polish the look

  • Lets add some spacing. Click on the grid1 and set vertical and horizontal spacing to 1
  • Wow, so much nicer !!
  • Adjust the margins to 0, except for the top margin. Set the top margin to 2

Using model view binding in SCADE

In order to bind a variable to a control you use SCADE's model view binding. Therefore you need to make sure the model is annotated correctly and you set the binding in the binding editor.

Annotating the model

The model needs to be annotated with @objc dynamic to be used as source for model-view binding. In our tutorial, we introduce a variable called buffer that holds the input of the calculator's key presses and bind it to the text attribute of a label control called lbNumberDisplay

import ScadeKit
import Expresion

class MainPageAdapter: SCDLatticePageAdapter {
	
  // variable buffer is used a model for model-view binding  
  @objc dynamic var buffer:String = "0"
  ...

Bind control and variable

We then switch to the binding view and bind the variable to the lbNumberDisplay text attribute:


Making the 0 key beautiful

👍Congrats, you made it through 60% of the tutorial and already acquired a lot of SCADE knowledge. Now, this chapter introduces an intermediate level concept, called "grid horizontal span". Don't worry, we take you through this step by step.

Making the 0 key beautiful - Part I

The current issue with the 0 key is that the key is restricted to its single cell, and is not expanding and including its adjacent cell to the right. Two different buttons are used, instead of one and the spacing divides these two buttons.

Goal: We want to merge the two buttons into one button.
In order to do this, we use the grid control's horizontal span feature. Horizontal span means that a cell is spanning across the space of multiple adjacent cells and taking their place.

To do this, in the page editor, we

  • STEP 1 : click into the cell we like to expand / span horizontally
  • STEP 2 : click on the advanced properties button
  • STEP 3 : goto the horizontal span row and change the 1 value to a 2 value
  • Finally, remove the redundant button that is not needed anymore
--

Making the 0 key beautiful - Part 2

So, this looks better, but there is still one problem. If we try to align the number 0 with the other numbers above, there is no way to make sure that the character 0 is nicely aligned with the number from the other keys above:

When trying to left align the key, the result is not good looking:

The future desired outcome looks like this. Nicely aligned with the other keys.

To achieve this, we need to create two cells that have the same width as the above cell into our newly created, merged cell. In that way, the left cell holding the 0 character will always be 100% aligned and good looking on all devices!

Remember out app layout graphics from above ?

Here the steps to achieve this:

A. Replace the 0 button with a horizontal container

  • Remove the button that represents the "0" key, btnNumber0
  • In its place, insert a horizontal container
  • Set the horizontal span of the container to 2
  • Set the background color of the container to the same color of the other keys (#646568)
  • Important. Name the container btnNumber1 (yes, its not a button in the strict sense, but its clickable)

B. Insert two labels

  • Insert two labels into the container
  • For each label, set the horizontal layout to match parent, fill space
  • For each label, set the vertical layout to match parent, fill space
  • For the 1st label (from left), set the text to "0""
  • For the 1st label (from left), set the Text Alignment to center
  • For the 1st label (from left), set the the font to match the other keys (Open Sans, Regular, 24, color Snow)
  • Remove the text of the second label by setting it to empty space

👏 Congratulations, you mastered an intermediate level concept and made your calculator look perfect on every device:

Adding Touch effect

Whenever we press a key on the keypad, we want the background color to change. When we lift the finger, the key's background color should return to its default color.
We use the Pan Gesture and capture the Began and Ended status to set the respective color.

👍

Gesture Guide

Please see the gesture guide Gesture Guide for more details on handling gestures.

func setupButtonActionsAndEffect(){ 

  // 1. change background color when pressed. 2. link actions to buttons
  for (btnName,input) in self.buttonNameInputs {

   	// get button reference, but cast it to higher class SCDWidgetsWidget,
		// because the 0 button is not button, but a container and 
		// SCDWidgetsWidget represents both
    if let btn = self.page!.getWidgetByName(btnName) as? SCDWidgetsWidget {

      // create gesture
      let gestureHandler = SCDSvgPanGestureRecognizer{ tap in 
        switch(tap!.state) {
          case .began:
            btn.backgroundColor = input.2 // pressed color
          case .ended:
            btn.backgroundColor = input.1 // default color
            self.process(input.0)  // process input
          default: 
            return
        }
     }
   // Add gesture to button
   btn.drawing!.gestureRecognizers.append(gestureHandler)
  }
 } //fornext
}

The color depends on the kind of key we are pressing. We specified the colors when a key was pressed and released in the buttonNameInputs array.

// Button ids and input (keyInput, colorDefault, colorKeyDown)
lazy var  buttonNameInputs = 
  [("btnNumber1", ("1", colorNumberKeyDefault, colorNumberKeyDown) ), 
    ("btnNumber2", ("2", colorNumberKeyDefault, colorNumberKeyDown) ), 
    ("btnNumber3", ("3", colorNumberKeyDefault, colorNumberKeyDown) ), 
    ("btnNumber4", ("4", colorNumberKeyDefault, colorNumberKeyDown) ),  .....

Using a 3rd party library

SCADE Swift compiler for Android compiles Swift code to Android native code, so you can easily include any 3rd party library that uses Swift and Swift Foundation. One such library is Nick Lockwood's Expression library, an advanced library for parsing and evaluating mathematical expressions in Swift.

Add library reference to build file

Nick Lockwood's library
• is located at https://github.com/nicklockwood/Expression
• Please use version 0.13.2 or above! (the video still shows 0.13.1, that is incorrect)

Open the SCADE's project build file and modify the file as shown below

Import library and use it

Now use the import statement to import the library. The function solveEquation uses the Expression library to solve our mathematical expressions.

import Expression

...

func solveEqualtion(equation:String) -> String {
  let expression = Expression(equation)
  if let result = try? expression.evaluate()  { 
    return String(result) 
  }
  return "Error"
}

Add processing logic

The logic that handles the key inputs, creates the mathematical expression and displays the input and results are implemented in the process() function. We will not discuss it, as it doesn't help learning about SCADE, but you can always review it in the source code.

Compile to IPA binary and run on iPhone

Let's compile to an iPA binary, transfer it to your iPhone and run the app

Compile to IPA

  • On the launchbar, choose iOS Device as target for your UgCalculator project
  • Check the buildfile, check for correct profile and certification entries
  • Press the RUN button
  • Wait for IPA to be created

Transfer to iphone

  • Make sure your device is connected
  • Start iTunes
  • In Finder, locate your UgCalculator.ipa file
  • Drag and drop the IPA file into the device section
  • Wait for successful transer

Start on Iphone

  • Startup your UgCalculator App !

📘

Project structure and compilation guide

For details on the project structure and compiling to Android and iOS, please see the guide here Project structure & Compilation

Compile to APK binary and run on Android

Now, let's compile to Android and run it there.

Compile to APK

  • On the launchbar, choose Android Device (arm) and General device as target for your UgCalculator project
  • Press the Run button
  • Wait for the APK to be created. The first build takes about 1+ minute. Additional builds are much faster

Transfer to Android device

  • Connect your Android phone to your MAC using an USB cable
  • Goto the tools-platform directory
  • List your existing devices using ./adb devices
  • Install your app using ./adb -s install -r command
  • The -r option overwrites existing installs

Congratulation. You have successfully installed your app on the android device.