This will download the code from GitHub into a directory calledgit clone https://github.com/alexziskind1/nativescript-calculator-demoapp.git
nativescript-calculator-demoapp. Navigate to that directory in your Terminal so you can execute NativeScript commands
Add the iOS platform to the project to prepare it for running on the simulator or devicecd
nativescript-calculator-demoapp
Now you’re ready to run the app. If you want to run the app in the iOS simulator, execute the emulate commandtns platform add ios
You could also run it directly on your iPhone, just connect the phone to your Mac via USB and execute the run commandtns emulate ios
The calculator should open in your simulator or device and will look like thistns run ios
The iOS calculator app has a slight gradient in the actions strip on the right side that ranges from West Side to Ecstacy. Or as I call them, from lighter orange to darker orange..label-back {
background-color
:
#202020
;
padding-top
:
50
;
}
GridLayout
for which the background image is set in the JavaScript code on load of the GridLayout
.This will load the image from the bundle and set the grid’s background to use the image. There are several techniques to set the background of the layout that are detailed in my post on the topic.function
actionsGridLoaded(args) {
var
theView = args.object._view;
if
(args.object.ios) {
theView.layer.contents = UIImage.imageNamed(
"app/res/calc-back-orange.png"
).CGImage;
}
}
exports.actionsGridLoaded = actionsGridLoaded;
Naturally, layouts should have the ability to be nested and NativeScript gives plenty of options to find the right combinations. The calculator app demonstrates the use of three layout types: DockLayout
, StackLayout
, and GridLayout
, with multiple levels of nesting.
<
DockLayout
stretchLastChild
=
"true"
>
<
StackLayout
dock
=
"top"
>
…
</
StackLayout
>
<
GridLayout
rows
=
"*, *, *, *, *"
columns
=
"*, *, *, *"
dock
=
"bottom"
>
…
<
GridLayout
rowSpan
=
"5"
col
=
"3"
rows
=
"*, *, *, *, *"
columns
=
"*"
>
…
</
GridLayout
>
</
GridLayout
>
</
DockLayout
>
While NativeScript supports a lot of common native functionality out of the box, there are times where you want to reach just a little further, do just a little extra with those controls. And the beauty of it is that you absolutely can do this since NativeScript lets you get down to the native level if you need it.
One such need is in the way the iOS calculator numeric display works. The size of the font stays the same until a certain number of digits are entered. Once the number of digits exceeds the width of the display, the font automatically starts to decrease in size. This is a great effect and natively supported by setting a property on a label in iOS.
We can tap into this ability by extending the label that comes with NativeScript. The following code shows how to extend the Label
element by setting the native underlying iOS label property called adjustsFontSizeToFitWidth
.
__extends
. You can see its definition at the end of the post.This code creates a new label type calledvar
ScalingLabel = (
function
(_super) {
__extends(ScalingLabel, _super);
function
ScalingLabel () {
_super.call(
this
);
this
.mylabel = UILabel.alloc().init();
this
._ios.adjustsFontSizeToFitWidth =
true
;
this
.ios.font = UIFont.fontWithNameSize(
"HelveticaNeue-UltraLight"
, 80);
this
.ios.addSubview(
this
.mylabel );
}
return
ScalingLabel;
})(label.Label);
exports.ScalingLabel = ScalingLabel;
ScalingLabel
which is going to automatically adjust its font size based on the number of digits that are shown in the calculator display. The calculator app has extra components such as the ScalingLabel
in the components folder in a file called calccomponents.ios.js.Page
element is provided with another attribute that points to the location of the code file that defines the ScalingLabel
.<
Page
xmlns:cc
=
"components/calccomponents"
xmlns
=
"http://schemas.nativescript.org/tns.xsd"
loaded
=
"pageLoaded"
>
...
</
Page
>
ScalingLabel
in our page<
cc:ScalingLabel
text
=
"{{ mainLabelText }}"
cssClass
=
"display"
/>
AVAudioPlayer
class that is part of the AVFoundation framework, which is exactly what we’ll be using here.To make the buttons produce the click sound, we create a new module in our NativeScript project. Only the iOS version will be shown here, but an android version can be just as easily created.
The file called clicker.ios.js contains the module that will maintain a living reference to the audio player. The module will create a new instance of theAVAudioPlayer
and expose a single function called click
to be triggered any time a button is tapped.In the view model we maintain a reference to the clicker class and call it when needed.var
Clicker =
function
(resource) {
var
soundPath = NSBundle.mainBundle().pathForResourceOfType(
"app/"
+resource,
"mp3"
);
var
soundUrl = NSURL.fileURLWithPath(soundPath);
var
player = AVAudioPlayer.alloc().initWithContentsOfURLError(soundUrl,
null
);
player.prepareToPlay();
this
.click =
function
() {
player.currentTime = 0.0;
player.play();
};
};
module.exports.Clicker = Clicker;
When a button in the UI is tapped, thevar
Calc = (
function
(_super) {
__extends(Calc, _super);
function
Calc() {
_super.call(
this
);
var
self =
this
;
this
.clicker =
new
clicker.Clicker(
"res/click_short"
);
…
}
}
click
function is called and the player plays the click sound.…
Calc.prototype.btnTapEq =
function
() {
this
.playSound();
this
.equalsPressed();
};
Calc.prototype.playSound =
function
() {
this
.clicker.click();
};
…
Our calculator app uses two types of UI elements that need to have their font updated
See my post on fonts for more details on font techniques with NativeScript, as well as using custom fonts.var
button = require(
"ui/button/button"
);
var
FontButton = (
function
(_super) {
__extends(FontButton, _super);
function
FontButton() {
_super.call(
this
);
this
.mybutton = UIButton.alloc().init();
this
.ios.font = UIFont.fontWithNameSize(
"HelveticaNeue-Thin"
, 80);
this
.ios.addSubview(
this
.mybutton );
}
return
FontButton;
})(button.Button);
exports.FontButton = FontButton;
If you’ve spent any time with NativeScript already, you must have noticed the loaded
attribute on the Page
element in the XML. Well, the Page
element is not the only UI Element that triggers the loaded
event. You can add load handlers to layouts, buttons, label, etc. All you have to do it add the loaded
attribute to the element in XML and specify the handler that’s exposed in the JavaScript code.
GridLayout
with an attached loaded
handler<
GridLayout
loaded
=
"actionsGridLoaded"
rowSpan
=
"5"
col
=
"3"
rows
=
"*, *, *, *, *"
columns
=
"*"
>
…
</
GridLayout
>
The loaded event handler received a reference to the underlying view object which we can manipulate and set the background image to the view’s layer property.function
actionsGridLoaded(args) {
var
theView = args.object._view;
if
(args.object.ios) {
theView.layer.contents = UIImage.imageNamed(
"app/res/calc-back-orange.png"
).CGImage;
}
}
exports.actionsGridLoaded = actionsGridLoaded;
If you haven’t already done so, grab the calculator code from GitHub, run it and see how all the pieces interact with each other. Use this post to help guide you through certain concepts that might not be in the documentation yet. Then go and build your own app!
__extends
function - this function simulates inheritance by copying all parent properties to child classes.var
__extends =
this
.__extends ||
function
(d, b) {
for
(
var
p
in
b)
if
(b.hasOwnProperty(p)) d[p] = b[p];
function
__() {
this
.constructor = d; }
__.prototype = b.prototype;
d.prototype =
new
__();
};