Posted at
IonicDay 18

Ionicのカスタムコンポーネントでペルソナ5のUIを再現してみた

この記事はIonic Advent Calendar 2018 18日目の記事になります。

今年になってIonicを触り始め、技術書典5にもIonicの本を出させてもらいました。

この記事では、カスタムコンポーネントで神ゲーであるペルソナ5のフレームUIを再現します。


開発環境



  • Ionic


    • Ionic CLI : 4.1.0

    • Ionic Framework : ionic-angular 3.9.2

    • @ionic/app-scripts : 3.2.1




  • System


    • NodeJS : v10.9.0

    • npm : 6.2.0

    • OS : macOS High Sierra




Ionicでペルソナ5みたいな枠を使いたいッッッ!

こんなの↓

window_S_LW.png


想定

想定としては、枠の中はion-cardと同様の使い方をしたいです。

ページのsassファイルを汚してしまうのは嫌なのでカスタムコンポーネント化します。

不規則なデザインかつ、大きさ(幅と高さ)も可変式にする必要があるのでsvgを使ってデザインを行います。


カスタムコンポーネント作成

$ ionic generate component p5-card


htmlテンプレート編集

<ion-card id="p5-card" (tap)="p5TapEvent()" no-margin>

<!-- 外側の黒い枠 -->
<svg class="p5-card-frame" viewBox="0,0,100,100" width=100 height=100 preserveAspectRatio="none" fill="black">
<polygon points="0,95 90,100 100,0 5,10"></polygon>
</svg>
        <!-- 内側の白い枠 -->
<svg class="p5-card-frame" viewBox="0,0,100,100" width=100 height=100 preserveAspectRatio="none" fill="white">
<polygon points="5,90 89,95 95,5 7,15"></polygon>
</svg>
<!-- <p5-card>ここがng-contentとして挿入される</p5-card> -->
<ng-content></ng-content>
</ion-card>

やっていることは、<ion-card>の幅と高さを100として計算し、svgで枠の形のボックスを挿入しているだけです。

こうすれば、ion-cardの恩恵を受けつつ枠を作ることができます。


.scss編集

p5-card {

.p5-card-frame {
position: absolute;
top: 0;
left: 0;
width: 100%;
height:100%;
z-index: -1;
}
#p5-card {
position: relative;
background-color: rgba(0,0,0,0);
border: none !important;
box-shadow:none;
padding: 15px 30px 15px 20px;
text-align: center;
width: 100%;
}
}


.ts編集

import { Component, Output, EventEmitter } from '@angular/core';

@Component({
selector: 'p5-card',
templateUrl: 'p5-card.html'
})
export class P5CardComponent {
@Output() p5Tap = new EventEmitter();
constructor() {
}
p5TapEvent() {
this.p5Tap.emit();
}
}

アウトプットイベントにp5Tapというイベントを作成しました。

このように、Outputデコレータを使えばカスタムコンポーネント独自のイベントを作ることができます。


問題発生

このままionic serveしてもエラーが出ます。

標準では、カスタムコンポーネント内ではion-*といったIonicのコンポーネントを使うことができません。

では、使える使えるようにしましょう。

components.module.tsを編集します。


components.module.ts編集

import { NgModule, CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';

import { CommonModule } from '@angular/common';
import { IonicModule } from 'ionic-angular';
import { P5CardComponent } from './p5-card/p5-card';
@NgModule({
declarations: [P5CardComponent,
],
imports: [CommonModule,
IonicModule],
exports: [P5CardComponent,
],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class ComponentsModule {}

ここで新たにimportしたのは


  • P5CardComponent

  • CUSTOM_ELEMENTS_SCHEMA

  • CommonModule

  • IonicModule

P5CardComponentは言うまでもなく、先ほど作成したカスタムコンポーネントです。


CUSTOM_ELEMENTS_SCHEMA

まずschemasと言うのは、


Angularのコンポーネントやディレクティブではない、Angular外で定義された要素とプロパティをHTMLパーサがどのように取り扱うか指定するもの


CUSTOM_ELEMENTS_SCHEMAは、


Angularの標準コンポーネント以外をカスタムコンポーネント内で使っても認識するようにするもの


こうすることで、カスタムコンポーネント内でion-*系のコンポーネントや自分で定義したコンポーネントを使えるようになります。


CommonModule

CommonModule


カスタムコンポーネント内で、Angular標準のDirectiveやPipeを使えるようにするもの


つまり、


  • ngIf

  • ngFor

  • ngSwitch

などの構造Directiveや


  • AsyncPipe

  • DecimalPipe

などのPipeをカスタムコンポーネントで使えるようになります。


IonicModule

app.module.tsで以下のように定義したデザインの条件をカスタムコンポーネントでも使えるようにします。

@NgModule({

declarations: [ MyApp ],
imports: [
BrowserModule,
IonicModule.forRoot(MyApp, {
backButtonText: 'Go Back',
iconMode: 'ios',
modalEnter: 'modal-slide-in',
modalLeave: 'modal-slide-out',
tabsPlacement: 'bottom',
pageTransition: 'ios-transition'
}, {}
)],
bootstrap: [IonicApp],
entryComponents: [ MyApp ],
providers: []
})

IonicModuleをimportしていないと、アイコンやモーダルなど影響を受けるコンポーネントは正常に動作しなくなります。


完成

localhost_8100_(iPhone X).png


課題

paddingの値を適当に決めてしまっているので、検証してベストな値を見つけたい。


おまけ

この記事の要領でトグルとスライダーも作ってみた。

Untitled.gif