




Card interfaces can be used for a lot more than simply making cool dating apps. Let’s learn how to build them by creating a food matchmaker. Imagine if a child could pre-order his or her lunch from Mom and Dad in the morning by swiping left on the broccoli, and swiping right on the PBJ. Or, in this case, by selecting exactly which desserts you want after dinner, always a critical moment of choice.
To begin with, I scaffolded a basic app using Angular and NativeScript. Since this is a dessert-matchmaking app, in my service, I created a basic array of emoji. Each emoji is placed on a colored card.import { Injectable } from "@angular/core";
import { Emoji } from "./emoji";
@Injectable()
export class CardService {
private emoji = new Array<Emoji>(
{ code: '🍮', color: 'b1' },
{ code: '🍡', color: 'b2' },
{ code: '🍨', color: 'b3' },
{ code: '🍩', color: 'b4' },
{ code: '🍪', color: 'b5' },
{ code: '🍰', color: 'b5' },
{ code: '🍬', color: 'b1' },
{ code: '🍭', color: 'b2' },
{ code: '🎂', color: 'b3' },
{ code: '🍧', color: 'b4' },
{ code: '🍫', color: 'b5' },
{ code: '🍦', color: 'b6' }
);
getEmoji(): Emoji[] {
return this.emoji;
}
}
.b1 {
background-color: #FFCCDA;
}
.b2 {
background-color: #FAEEC3;
}
.b3 {
background-color: #F67982;
}
.b4 {
background-color: #FFA1A1;
}
.b5 {
background-color: #FACBAA;
}
.b6 {
background-color: #F67982;
}
<StackLayout>
<AbsoluteLayout horizontalAlignment="center" paddingTop="30" #absolutelayout>
<GridLayout width="100%" style="z-index:1" columns="*,*" horizontalAlignment="center">
<Label #no col="0" verticalAlignment="center" text="no, thanks!" class="no"></Label>
<Label #yes col="1" text="yes, please!" class="yes"></Label>
</GridLayout>
</AbsoluteLayout>
</StackLayout>
@ViewChild("absolutelayout") al: ElementRef;
@ViewChild("yes") yes: ElementRef;
@ViewChild("no") no: ElementRef;
...
ngOnInit() {
this.emoji = this.cardService.getEmoji();
//initial card
this.code = this.emoji[this.i].code;
//get ready for the swiping!
for (var key in this.emoji) {
this.handleSwipe(key);
}
}
handleSwipe(key: any) {
this.i--;
let grid = new GridLayout();
let emoji = new Label();
let yes = <Label>this.yes.nativeElement;
let no = <Label>this.no.nativeElement;
let absolutelayout = <AbsoluteLayout>this.al.nativeElement;
let swipeleft = <Button>this.swipeleft.nativeElement;
let swiperight = <Button>this.swiperight.nativeElement;
//set the emoji on the card
emoji.text = this.emoji[key].code;
//build the grid which is the card
grid.cssClass = 'card ' + this.emoji[key].color;
grid.id = 'card' + Number(key);
grid.marginTop = this.i;
//add the emoji to the grid, and the grid to the absolutelayout
grid.addChild(emoji);
absolutelayout.addChild(grid)
...
}
grid.on(GestureTypes.swipe, function (args: SwipeGestureEventData) {
if (args.direction == 1) {
//right
yes.animate({ opacity: 0, duration: 100 })
.then(() => yes.animate({ opacity: 1, duration: 100 }))
.then(() => yes.animate({ opacity: 0, duration: 100 }))
.then(() =>
grid.animate({ translate: { x: 1000, y: 100 } })
.then(function () { return grid.animate({ translate: { x: 0, y: -2000 } }); })
.catch(function (e) {
console.log(e.message);
})
)
.catch((e) => {
console.log(e.message);
});
}
else {
//left
no.animate({ opacity: 0, duration: 100 })
.then(() => no.animate({ opacity: 1, duration: 100 }))
.then(() => no.animate({ opacity: 0, duration: 100 }))
.then(() =>
grid.animate({ translate: { x: -1000, y: 100 } })
.then(function () { return grid.animate({ translate: { x: 0, y: -2000 } }); })
.catch(function (e) {
console.log(e.message);
})
)
.catch((e) => {
console.log(e.message);
});
}
});
