使用Nativescript和Angular2構(gòu)建跨平臺APP

前言

“一次構(gòu)建忘渔,多處運(yùn)行”高帖,跨平臺APP帶著這股風(fēng)潮把火燒到了前端,為開發(fā)者帶來無盡的遐想∑枇福現(xiàn)有的流行跨平臺框架有以下:

  1. 基于單WebView的開發(fā)框架散址。開發(fā)者可以使用現(xiàn)有的最新web技術(shù),開發(fā)出單頁面web應(yīng)用宣赔。同時利用JSBridge预麸,又能獲取原生的API,從而使web應(yīng)用具有了原生應(yīng)用的功能儒将。Cordova+IONIC可以說是這個潮流的代表吏祸,也是跨平臺APP的先鋒。然而這類跨平臺應(yīng)用的缺點(diǎn)是不流暢钩蚊,在安卓手機(jī)上體驗(yàn)較差贡翘。
  2. Hybrid方向。也就是原生應(yīng)用配合HTML5技術(shù)砰逻,讓APP具有了部分跨平臺的功能鸣驱。Hybrid也是現(xiàn)在各大互聯(lián)網(wǎng)企業(yè)采用較多的跨平臺開發(fā)方式。這類APP在體驗(yàn)上優(yōu)于單WebView的APP蝠咆,并且能夠極大提高開發(fā)效率踊东。然而這種方式離“一次構(gòu)建,多處運(yùn)行”的設(shè)想還是有很大距離刚操,畢竟依然需要針對不同的移動平臺進(jìn)行原生開發(fā)递胧。
  3. 使用Javascript開發(fā)純原生應(yīng)用。既然單WebView性能有缺憾赡茸,Hybrid技術(shù)棧又比較高,那么Javascript開發(fā)純原生應(yīng)用就孕育而生祝闻。這個方向的代表有ReactNative, Weex和我們今天的主角--Nativescript占卧。

和ReactNative相比,Nativescript最大的特點(diǎn)是可以獲得100%的原生API联喘。也就是說华蜒,開發(fā)者可以通過Javascript獲取和原生開發(fā)語言同樣多的原生接口。下面豁遭,我們通過實(shí)現(xiàn)一個簡單的計算器叭喜,來體會一下Nativescript的開發(fā)思想。同時蓖谢,我們能體會到“獲取所有原生API”帶來的巨大好處捂蕴。
你可以先在這里看到最終的結(jié)果譬涡。 注意輸入的數(shù)字的字體會隨著文本長度逐漸變小,想想這個功能怎么實(shí)現(xiàn)啥辨。

Nativescript計算器

Why Nativescript?

大家定會好奇涡匀,ReactNative這么火姨谷,大家都在談?wù)撍藁梗笥幸唤y(tǒng)天下的感覺蛇损,為什么還要討論Nativescript呢柜蜈?這是因?yàn)镽eactNative依然不能真正統(tǒng)一編程語言倦逐。ReactNative基于平臺抽象倘感,不可能暴露100%的原生API牲证,因此需要使用原生編程語言進(jìn)行擴(kuò)展军洼,提高了技術(shù)棧玫荣。所以甚淡,一個ReactNative的開發(fā)團(tuán)隊(duì)里面必須同時具備Javascript,Java還有ObjectiveC開發(fā)技術(shù)崇决。
相比之下材诽,Nativescript的技術(shù)棧則要簡單的多,開發(fā)者只需要使用Javascript就能進(jìn)行開發(fā)恒傻。這里列出了幾個Nativescript的核心功能:

  1. 使用Javascript直接訪問所有原生API
  2. 系統(tǒng)新功能0延時支持
  3. 第三方原生庫全部支持

準(zhǔn)備

首先需要搭建開發(fā)環(huán)境脸侥,請參考官方的文檔。你可以使用下面的命令來檢測Nativescript是否安轉(zhuǎn)完成:

tns doctor

Nativescript支持純Javascript盈厘,同時也支持Angular2睁枕。我們選擇Angular2Typescript進(jìn)行開發(fā),體會一下Angular2帶來的開發(fā)便利沸手。

創(chuàng)建我們的項(xiàng)目

tns create NSCalculator --ng

這個命令會在當(dāng)前目錄下新建NSCalculator文件夾外遇,同時安裝好所需的第三方依賴。其實(shí)這個命令還給你新建一個Demo契吉,運(yùn)行下面的命令跳仿,你就會看到你的第一個Nativescript應(yīng)用

tns platform add ios
tns run ios --emulator

拆分

使用Visual Studio Code打開文件,有如下的文件夾結(jié)構(gòu)

項(xiàng)目結(jié)構(gòu)

我們的代碼將會組織在app目錄下捐晶,所以只需考慮這個文件夾菲语。main.ts是整個應(yīng)用的啟動文件,我們現(xiàn)在不需要更改它惑灵。我們看到main.ts里面引入了app.component模塊山上,app.component將會被改造成我們的計算器組件。在改造app.component.ts前英支,我們先考慮一下如何將計算器拆分成一個個組件佩憾。
計算器拆分

首先從功能上對計算器進(jìn)行拆分。計算器由Displayer和Keyboard兩個部分,Keyboard由Button組成妄帘±慊疲基于此,我們在app目錄下新增三個文件夾:Displayer寄摆,Keyboard谅辣,NSButton。

布局

組件化開發(fā)有兩種常用方式婶恼,一種是由大到小開發(fā)桑阶,也就是Calculator -> Displayer -> Keyboard -> Button,一種是由小到大開發(fā)勾邦,也就是 Button -> Keyboard -> Displayer -> Calculator蚣录。當(dāng)然你也可以混合開發(fā)。本例采用由大到小的開發(fā)方式眷篇。
刪除app.component.ts里面的內(nèi)容萎河,用以下代替:

// app.component.ts

import {
    Component,
} from "@angular/core";

@Component({
    selector: "calculator",
    template: `
    <GridLayout rows="auto,*" columns="*">
     <StackLayout row="0" style="font-size:60;color:#fff;height:120;background-color:rgba(0,0,0,0.8);text-align:right;vertical-align:bottom;">
      <Label text="99" ></Label>
     </StackLayout>
     <GridLayout row="1" style="background-color:#fff;text-align:center;">
      <Label text="keyboards" ></Label>
      </GridLayout>
    </GridLayout>
`,
})
export class AppComponent {
    public counter: string = '';
}

運(yùn)行以下命令,你就能看到效果

tns livesync ios --emulator --watch

tns run ios命令不同蕉饼,這個命令會監(jiān)視你的文件變化并自動構(gòu)建部署新的應(yīng)用虐杯。

Nativescript布局

Nativescript的布局方式和安卓原生的布局方式非常類似。對于計算器昧港,我們的Displayer需要一個固定的高度擎椰,Keyboard需要占據(jù)全部剩余的空間。因此创肥,Calculator的第一級布局使用了GridLayout达舒。rows="auto,*" 表示Gridlayout為兩行,第一行高度由內(nèi)容(auto)決定叹侄,第二行高度占據(jù)全部剩余空間(*)巩搏。columns="*"表示Gridlayout分為一列布局,這一列的寬度占據(jù)全部空間趾代。
我們?yōu)镈isplayer選擇了StackLayout布局贯底,這是因?yàn)槲覀冃枰袻abel靠右下角對齊。我們?yōu)镵eyboard選擇了GridLayout布局撒强,這很好理解丈甸,因?yàn)槲覀冃枰粋€5x4的格子用來放置計算器的按鈕。
熟悉ReactNative的同學(xué)可能知道尿褪,ReactNative使用Flex布局,非常便于web開發(fā)者掌握得湘。Nativescript則使用和原生開發(fā)非常相似的布局方式杖玲,然而這種布局方式其實(shí)也很容易掌握。
注意我們還使用了行內(nèi)CSS來裝飾Nativescript的組件淘正。Nativescript支持的CSS屬性是web CSS屬性的一個子集摆马。你可以在這里看到Nativescript支持的CSS種類臼闻,總的來說,有限但是夠用囤采。

組件

目前為止我們的APP只有一個組件AppComponent述呐,這非常不利于項(xiàng)目的擴(kuò)展。幸運(yùn)的是Nativescript支持Angular2.0的全部功能蕉毯,我們可以使用Angular來實(shí)現(xiàn)Displayer和Keyboard組件乓搬。
在app目錄下新建Keyboard文件夾,在Keyboard文件里新增keyboard.component.ts代虾,keyboard.html进肯,以及keyboard.css文件。內(nèi)容如下:

//keyboard.component.ts
import {
  Component,
} from '@angular/core';

@Component({
  selector:'keyboard',
  templateUrl:'Keyboard/keyboard.html',
  styleUrls:['Keyboard/keyboard.css']
})

export class Keyboard{
}

<!--keyboard.html-->
<GridLayout row="1" columns="1*,1*,1*,1*"
   rows="1*,1*,1*,1*,1*">
  <!--第一行-->
  <StackLayout row="0" col="0"> 
    <Label class="keyboard-item gray" text="C"></Label>
  </StackLayout>
  <StackLayout row="0" col="1"> 
    <Label class="keyboard-item gray" text="+/-"></Label>
  </StackLayout>
  <StackLayout row="0" col="2"> 
    <Label class="keyboard-item gray" text="%"></Label>
  </StackLayout>
  <StackLayout row="0" col="3"> 
    <Label class="keyboard-item yellow" text="÷"></Label>
  </StackLayout>

  <!--第二行-->
  <StackLayout row="1" col="0"> 
    <Label class="keyboard-item gray" text="7"></Label>
  </StackLayout>
  <StackLayout row="1" col="1"> 
    <Label class="keyboard-item gray" text="8"></Label>
  </StackLayout>
  <StackLayout row="1" col="2"> 
    <Label class="keyboard-item gray" text="9"></Label>
  </StackLayout>
  <StackLayout row="1" col="3"> 
    <Label class="keyboard-item yellow" text="x"></Label>
  </StackLayout>

  <!--第三行-->
  <StackLayout row="2" col="0"> 
    <Label class="keyboard-item gray" text="4"></Label>
  </StackLayout>
  <StackLayout row="2" col="1"> 
    <Label class="keyboard-item gray" text="5"></Label>
  </StackLayout>
  <StackLayout row="2" col="2"> 
    <Label class="keyboard-item gray" text="6"></Label>
  </StackLayout>
  <StackLayout row="2" col="3"> 
    <Label class="keyboard-item yellow" text="-"></Label>
  </StackLayout>

  <!--第四行-->
  <StackLayout row="3" col="0"> 
    <Label class="keyboard-item gray" text="1"></Label>
  </StackLayout>
  <StackLayout row="3" col="1"> 
    <Label class="keyboard-item gray" text="2"></Label>
  </StackLayout>
  <StackLayout row="3" col="2"> 
    <Label class="keyboard-item gray" text="3"></Label>
  </StackLayout>
  <StackLayout row="3" col="3"> 
    <Label class="keyboard-item yellow" text="+"></Label>
  </StackLayout>

  <!--第五行-->
  <StackLayout row="4" col="0" colSpan="2"> 
    <Label class="keyboard-item gray" text="0"></Label>
  </StackLayout>
  <StackLayout row="4" col="2"> 
    <Label class="keyboard-item gray" text="."></Label>
  </StackLayout>
  <StackLayout row="4" col="3"> 
    <Label class="keyboard-item yellow" text="="></Label>
  </StackLayout>

</GridLayout>
// keyboard.css
.keyboard-item {
  border-width: 0.5;
  border-color: rgb(123,123,123);
  font-family: monospace;
  width:100%;
  height: 100%;
  text-align: center;
}

.gray {
  background-color: rgb(205,205,205);
  color:rgb(22,22,22);
  font-size: 25;
}

.yellow {
  background-color:rgb(242,127,38);
  color:#fff;
  font-size: 30;
}

在Keyboard組件里棉磨,我們把HTML模板和CSS都拆分到了獨(dú)立文件里面江掩,又回到了那個干干凈凈的web世界。而這兩者ReactNative都不能支持乘瓤!所以在組件復(fù)用性和易用性上环形,Nativescript其實(shí)技高一籌。
然而現(xiàn)在應(yīng)用界面并沒有任何變化衙傀,我們還需要在app.component.ts中引入Keyboard組件抬吟。修改后的app.component.ts文件如下

//app.component.ts
import {
    Component,
} from "@angular/core";
//引入外部組件
import {
    Keyboard
} from './Keyboard/keyboard.component';

@Component({
    selector: "calculator",
    template: `
    <GridLayout rows="auto,*" columns="*">
     <!--Dispalyer-->
     <StackLayout row="0" style="font-size:60;color:#fff;height:120;background-color:rgba(0,0,0,0.8);text-align:right;vertical-align:bottom;">
      <Label text="99" ></Label>
     </StackLayout>
     <!--引入Keyboard組件-->
     <keyboard row="1"></keyboard>
    </GridLayout>
`,
directives:[Keyboard] //聲明對Keyboard組件的依賴
})
export class AppComponent {
    public counter: string = '';
}

現(xiàn)在我們的計算器有點(diǎn)樣子了:

Keyboard組件

似乎有點(diǎn)簡單。但是請注意差油,這個界面是完全的原生界面拗军,完全由原生組件構(gòu)成。然而蓄喇,由于Nativescript的支持发侵,我們確可以像開發(fā)web應(yīng)用一般輕松的開發(fā)原生應(yīng)用了。
但是現(xiàn)在的Keyboard還不能提供任何功能妆偏,Keyboard不能響應(yīng)點(diǎn)擊事件刃鳄,也不能把數(shù)據(jù)傳遞給Displayer。接下來我們就要為Keyboard加上這些功能钱骂。

交互

Nativescript提供了原生的手勢事件叔锐,你可以在應(yīng)用中直接使用。由于touch事件會返回手指的狀態(tài):向下见秽,移動愉烙,向上等,滿足鍵盤交互的需求解取,因此我們監(jiān)聽touch事件步责。
要監(jiān)聽Keyboard的點(diǎn)擊事件,最直觀的答案就是為每個按鈕設(shè)置touch事件監(jiān)聽器,在這個計算器應(yīng)用中我們需要設(shè)置19次蔓肯!而且我們的監(jiān)聽邏輯不能復(fù)用遂鹊,雖然他們的功能很相似!這是不可接受的蔗包。所以秉扑,我們應(yīng)該把按鈕也做成一個Angular組件,因?yàn)榻M件是可以復(fù)用的调限。
那么這個按鈕組件需要哪些功能呢舟陆? 當(dāng)點(diǎn)擊按鈕時,按鈕的背景色需要改變旧噪,并且需要把這個點(diǎn)擊事件告知其他組件吨娜。
在app目錄下新建NSButton文件夾,同時在NSButton文件夾里新增一下文件: nsbutton.component.ts, nsbutton.css淘钟。

//nsbutton.component.ts
import {
  Component,
  ElementRef,
  ViewChild,
  AfterViewInit,
  Input,
  OnInit
} from '@angular/core';
import {
  Label
} from 'ui/label';
import {
  GestureTypes,
  TouchGestureEventData
} from 'ui/gestures';
import {
  Color
} from 'color';
@Component({
  selector: 'nsbutton',
  template: `<Label class="keyboard-item" #nsbutton [text]="text" (touch)="onTouch($event)"> </Label>`,
  styleUrls:['NSButton/nsbutton.css']
})

export class NSButton implements AfterViewInit{
  @ViewChild('nsbutton') nsBtnRef : ElementRef;
  @Input('text') text: string;
  @Input('normalBg') normalBg:string;
  @Input('activeBg') activeBg:string;
  private nsBtnView : Label;

  ngAfterViewInit() {
    this.nsBtnView = <Label> this.nsBtnRef.nativeElement;
    this.changeBg(this.nsBtnView,this.normalBg || '#D0D0D0');
  }

  changeBg(component:Label,bgColor:string) {
    component.backgroundColor = new Color(bgColor);
  }

  onTouch(event) {
    this.onTouchEvent(event.action);
  }

  onTouchEvent(type:string) {
    switch(type) {
      case 'down':
      case 'move':
        this.changeBg(this.nsBtnView,this.activeBg || '#A3A3A3');
      break;
      default:
        this.changeBg(this.nsBtnView,this.normalBg || '#D0D0D0');
      break;
    }
  }
}

請注意宦赠,這里我們沒有使用ngStyle的方式來改變按鈕的背景,而是用了更底層一級的API米母。主要是為了像你展示在Nativescript中使用原生API是多么輕松的一件事勾扭。

//nsbutton.css
.keyboard-item {
  border-width: 0.5;
  border-color: rgb(123,123,123);
  font-family: monospace;
  width:100%;
  height: 100%;
  text-align: center;
  font-size: 25;
}

然后,需要在Keyboard組件里引入NSButton铁瞒。修改keyboard.component.ts和keyboard.html文件如下:

//keyboard.component.ts
import {
  Component,
} from '@angular/core';
import {
  NSButton
} from '../NSButton/nsbutton.component';

@Component({
  selector:'keyboard',
  templateUrl:'Keyboard/keyboard.html',
  styleUrls:['Keyboard/keyboard.css'],
  directives:[NSButton],
})

export class Keyboard{
}
//keyboard.html
<GridLayout row="1" columns="1*,1*,1*,1*"
   rows="1*,1*,1*,1*,1*">
  <!--第一行-->
  <GridLayout row="0" col="0"> 
    <nsbutton text="C"></nsbutton>
  </GridLayout>
  <GridLayout row="0" col="1"> 
    <nsbutton text="+/-"></nsbutton>
  </GridLayout>
  <GridLayout row="0" col="2"> 
    <nsbutton text="%"></nsbutton>
  </GridLayout>
  <GridLayout row="0" col="3" style="color:#fff;"> 
    <nsbutton text="÷" normalBg="#F27F26" activeBg="#B65F1C"></nsbutton>
  </GridLayout>

  <!--第二行-->
  <GridLayout row="1" col="0"> 
    <nsbutton text="7"></nsbutton>
  </GridLayout>
  <GridLayout row="1" col="1"> 
    <nsbutton text="8"></nsbutton>
  </GridLayout>
  <GridLayout row="1" col="2"> 
    <nsbutton text="9"></nsbutton>
  </GridLayout>
  <GridLayout row="1" col="3" style="color:#fff;"> 
    <nsbutton text="x" normalBg="#F27F26" activeBg="#B65F1C"></nsbutton>
  </GridLayout>

  <!--第三行-->
  <GridLayout row="2" col="0"> 
    <nsbutton text="4"></nsbutton>
  </GridLayout>
  <GridLayout row="2" col="1"> 
    <nsbutton text="5"></nsbutton>
  </GridLayout>
  <GridLayout row="2" col="2"> 
    <nsbutton text="6"></nsbutton>
  </GridLayout>
  <GridLayout row="2" col="3" style="color:#fff;"> 
    <nsbutton text="-" normalBg="#F27F26" activeBg="#B65F1C"></nsbutton>
  </GridLayout>

  <!--第四行-->
  <GridLayout row="3" col="0"> 
    <nsbutton text="1"></nsbutton>
  </GridLayout>
  <GridLayout row="3" col="1"> 
    <nsbutton text="2"></nsbutton>
  </GridLayout>
  <GridLayout row="3" col="2"> 
    <nsbutton text="3"></nsbutton>
  </GridLayout>
  <GridLayout row="3" col="3" style="color:#fff;"> 
    <nsbutton text="+" normalBg="#F27F26" activeBg="#B65F1C"></nsbutton>
  </GridLayout>

  <!--第五行-->
  <GridLayout row="4" col="0" colSpan="2"> 
    <nsbutton text="0"></nsbutton>
  </GridLayout>
  <GridLayout row="4" col="2"> 
    <nsbutton text="."></nsbutton>
  </GridLayout>
  <GridLayout row="4" col="3" style="color:#fff;"> 
    <nsbutton text="=" normalBg="#F27F26" activeBg="#B65F1C"></nsbutton>
  </GridLayout>

</GridLayout>

現(xiàn)在妙色,我們的按鈕組件就有了一個漂亮的點(diǎn)擊動畫。


點(diǎn)擊動畫

不過Keyboard的點(diǎn)擊事件還不能通知給Displayer慧耍,我們接著來增加這個功能身辨,修改nsbuttom.component.ts, keyboard.component.ts, app.component.ts如下:

//nsbuttom.component.ts
import {
  Component,
  ElementRef,
  ViewChild,
  AfterViewInit,
  Input,
  OnInit
} from '@angular/core';
import {
  Label
} from 'ui/label';
import {
  GestureTypes,
  TouchGestureEventData
} from 'ui/gestures';
import {
  Color
} from 'color';
@Component({
  selector: 'nsbutton',
  template: `<Label class="keyboard-item" #nsbutton [text]="text" (touch)="onTouch($event)"> </Label>`,
  styleUrls:['NSButton/nsbutton.css']
})

export class NSButton implements AfterViewInit{
  @ViewChild('nsbutton') nsBtnRef : ElementRef;
  @Input('text') text: string;
  @Input('normalBg') normalBg:string;
  @Input('activeBg') activeBg:string;
  @Input('onBtnClicked') onBtnClicked: Function;
  private nsBtnView : Label;

  ngAfterViewInit() {
    this.nsBtnView = <Label> this.nsBtnRef.nativeElement;
    this.changeBg(this.nsBtnView,this.normalBg || '#D0D0D0');
  }

  changeBg(component:Label,bgColor:string) {
    component.backgroundColor = new Color(bgColor);
  }

  onTouch(event) {
    this.onTouchEvent(event.action);
  }

  onKeyUp() {
    if(this.onBtnClicked) {
      this.onBtnClicked && this.onBtnClicked(this.text);
    }
  }

  onTouchEvent(type:string) {
    switch(type) {
      case 'down':
      case 'move':
        this.changeBg(this.nsBtnView,this.activeBg || '#A3A3A3');
      break;
      case 'up':
        this.onKeyUp();
      default:
        this.changeBg(this.nsBtnView,this.normalBg || '#D0D0D0');
      break;
    }
  }
}
//keyboard.component.ts
import {
  Component,
  Input,
  OnInit
} from '@angular/core';
import {
  NSButton
} from '../NSButton/nsbutton.component';

@Component({
  selector:'keyboard',
  templateUrl:'Keyboard/keyboard.html',
  styleUrls:['Keyboard/keyboard.css'],
  directives:[NSButton],
})

export class Keyboard implements OnInit{

  @Input('onKeyBoardClicked') onKeyBoardClicked: Function;

  ngOnInit() {
    this.onBtnClicked = this.onBtnClicked.bind(this);
  }

  public onBtnClicked(text:string):void {
    this.onKeyBoardClicked && this.onKeyBoardClicked(text);
  }
}
//app.component.ts
import {
    Component,
    OnInit,
    ElementRef,
    ViewChild,
    AfterViewInit,
} from "@angular/core";
import {
    Label
} from 'ui/label';
import {
  Keyboard
} from './Keyboard/keyboard.component';
import {
  device,
  platformNames
} from 'platform';

@Component({
    selector: "calculator",
    template: `
            <GridLayout rows="auto,*" columns="*">
            <!--Dispalyer-->
            <StackLayout row="0" style="font-size:60;color:#fff;height:120;background-color:rgba(0,0,0,0.8);text-align:right;vertical-align:bottom;">
                <Label [text]="counter" #displayer></Label>
            </StackLayout>
            <!--Keyboard-->
            <keyboard row="1" [onKeyBoardClicked]="onKeyBoardClicked"></keyboard>
            </GridLayout>
    `,
    directives:[Keyboard]
})
export class AppComponent implements OnInit{
    public counter: string = '';
    @ViewChild('displayer') displayerRef: ElementRef;
    private displayerView : Label;

    ngOnInit() {
            this.onKeyBoardClicked = this.onKeyBoardClicked.bind(this);
    }

    public onKeyBoardClicked(text:string):void {
            this.counter += text;        
    }
}

這樣我們的Keyboard點(diǎn)擊就能實(shí)時顯示在Disapler上面了。
這個交互我們完全依賴于Angular2為我們提供的單向綁定芍碧。再強(qiáng)調(diào)一次煌珊,Nativesript支持所有的Angular2功能,這真的會簡化我們的開發(fā)泌豆。


鍵盤交互

原生API

對比我們的計算器和ios原生計算器定庵,我們發(fā)現(xiàn)原生計算器的Displayer會自動調(diào)整字體大小,以保證顯示的數(shù)字完全展示踪危。得益于Nativescript蔬浙,我們也能通過Javascript調(diào)用這套API,實(shí)現(xiàn)相同的效果贞远。修改app.comonent.ts如下:

//app.component.ts
import {
    Component,
    OnInit,
    ElementRef,
    ViewChild,
    AfterViewInit,
} from "@angular/core";
import {
    Label
} from 'ui/label';
import {
  Keyboard
} from './Keyboard/keyboard.component';
import {
  device,
  platformNames
} from 'platform';

@Component({
    selector: "calculator",
    template: `
            <GridLayout rows="auto,*" columns="*">
            <!--Dispalyer-->
            <StackLayout row="0" style="font-size:60;color:#fff;height:120;background-color:rgba(0,0,0,0.8);text-align:right;vertical-align:bottom;">
                <Label [text]="counter" #displayer></Label>
            </StackLayout>
            <!--Keyboard-->
            <keyboard row="1" [onKeyBoardClicked]="onKeyBoardClicked"></keyboard>
            </GridLayout>
    `,
    directives:[Keyboard]
})
export class AppComponent implements OnInit, AfterViewInit{
    public counter: string = '';
    @ViewChild('displayer') displayerRef: ElementRef;
    private displayerView : Label;

    ngAfterViewInit() {
        this.displayerView = <Label> this.displayerRef.nativeElement;
        this.setIOSLabelAutoFont(this.displayerView);
    }

    private setIOSLabelAutoFont(elem: Label) {
    if(device.os === platformNames.ios){
      elem.ios.numberOfLines = 1;
      elem.ios.minimumFontSize = 20;
      elem.ios.adjustsFontSizeToFitWidth = true;
    }
  }

    ngOnInit() {
            this.onKeyBoardClicked = this.onKeyBoardClicked.bind(this);
    }

    public onKeyBoardClicked(text:string):void {
            this.counter += text;        
    }
}

elem.ios.numberOfLines = 1, elem.ios.minimumFontSize = 20, elem.ios.adjustsFontSizeToFitWidth = true 是三個IOS的UILabel原生的api畴博。在Nativescript中,我們可以使用Javascript直接調(diào)用他們蓝仲,Nativescript會幫我們處理好Javascript到原生的映射绎晃,包括數(shù)據(jù)類型的轉(zhuǎn)換蜜唾,不需要寫任我的ObjectiveC代碼。
如此庶艾,我們就實(shí)現(xiàn)了在文章最開始展示的交互。** 這個交互擎勘,在ReactNative中咱揍,是無法直接實(shí)現(xiàn)的! **這也是Nativescript相比于ReactNative的強(qiáng)大之處

總結(jié)

得益于Nativescript可以訪問100%的原生API, 我們不需要寫任何原生代碼棚饵,就能獲得和原生代碼一樣的能力煤裙。這可以說是Nativescript相比于其他平臺,比如React Native, 最大的優(yōu)勢噪漾。在現(xiàn)階段硼砰,Nativescript應(yīng)該是最成熟的,性能最好的跨平臺APP構(gòu)建方案欣硼。
github代碼在這里:https://github.com/eeandrew/NSCalculator

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末题翰,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子诈胜,更是在濱河造成了極大的恐慌豹障,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,695評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件焦匈,死亡現(xiàn)場離奇詭異血公,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)缓熟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評論 3 399
  • 文/潘曉璐 我一進(jìn)店門累魔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人够滑,你說我怎么就攤上這事垦写。” “怎么了版述?”我有些...
    開封第一講書人閱讀 168,130評論 0 360
  • 文/不壞的土叔 我叫張陵梯澜,是天一觀的道長。 經(jīng)常有香客問我渴析,道長晚伙,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,648評論 1 297
  • 正文 為了忘掉前任俭茧,我火速辦了婚禮咆疗,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘母债。我一直安慰自己午磁,他們只是感情好尝抖,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,655評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著迅皇,像睡著了一般昧辽。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上登颓,一...
    開封第一講書人閱讀 52,268評論 1 309
  • 那天搅荞,我揣著相機(jī)與錄音,去河邊找鬼框咙。 笑死咕痛,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的喇嘱。 我是一名探鬼主播茉贡,決...
    沈念sama閱讀 40,835評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼者铜!你這毒婦竟也來了腔丧?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,740評論 0 276
  • 序言:老撾萬榮一對情侶失蹤王暗,失蹤者是張志新(化名)和其女友劉穎悔据,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體俗壹,經(jīng)...
    沈念sama閱讀 46,286評論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡科汗,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,375評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了绷雏。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片头滔。...
    茶點(diǎn)故事閱讀 40,505評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖涎显,靈堂內(nèi)的尸體忽然破棺而出坤检,到底是詐尸還是另有隱情,我是刑警寧澤期吓,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布早歇,位于F島的核電站,受9級特大地震影響讨勤,放射性物質(zhì)發(fā)生泄漏箭跳。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,873評論 3 333
  • 文/蒙蒙 一潭千、第九天 我趴在偏房一處隱蔽的房頂上張望谱姓。 院中可真熱鬧,春花似錦刨晴、人聲如沸屉来。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽茄靠。三九已至茂契,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間慨绳,已是汗流浹背账嚎。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留儡蔓,地道東北人。 一個月前我還...
    沈念sama閱讀 48,921評論 3 376
  • 正文 我出身青樓疼邀,卻偏偏與公主長得像喂江,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子旁振,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,515評論 2 359

推薦閱讀更多精彩內(nèi)容