Goalist Developers Blog

はじめてのAngular TODOアプリをつくる① リスト表示編

はじめてAngular2を触ってみた初心者のメモ書きです。

今回からは、公式チュートリアルをチラ見しながらTODOアプリを作っていきたいと思います。

https://angular.io/docs/ts/latest/tutorial/angular.io

今回もAngular CLIの恩恵にあずかってまいります。
Windowsでの環境構築編はこちら

developers.goalist.co.jp

目次

準備

プロジェクトを生成

ng new todo-app

開発用サーバを起動

ng s

これで保存の度に自動ビルドしてくれます。

http://localhost:4200/をブラウザ上で確認
f:id:y-iio:20170410163753p:plain

ちゃんと動いてますね。これで準備完了です。

タスクを一つ表示する

公式チュートリアルのHero Editorを見ながらやっていきます。
内容としては

Angular Docs

のところです。

Taskクラスの作成

ng g class task

これでapp下にtask.tsが作成されました。
とりあえずIDとタスク名を持たせます。

task.ts

export class Task {
  id: number;
  name: string;
}

Taskクラスをインポート

appコンポーネントにimport { Task } from './Task';を追加して、Taskクラスを使えるようにします。
適当に初期表示も決め打ちします。

app.component.ts

import { Component } from '@angular/core';

import { Task } from './Task';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'todo app';
  task: Task = {
    id: 1,
    name: '田中さんにメール'
  };
}

チュートリアルのHero Editorほぼそのままのhtmlです。

app.component.html

<h1>{{title}}</h1>
<h2>{{task.name}} の詳細</h2>
<div><label>id: </label>{{task.id}}</div>
<div><label>name: </label>{{task.name}}</div>
<div>
  <label>name: </label>
  <input [(ngModel)]="task.name" placeholder="name">
</div>

表示ドン

f:id:y-iio:20170410164136p:plain

双方向バインディング[(ngModel)]もオッケーです。

f:id:y-iio:20170410164145p:plain

タスクリストを表示する

内容としては

Angular Docs

のところです。

リスト表示(ngFor)

とりあえずリスト内容を宣言
このあたりで良いのかな

app.component.ts

export class AppComponent {
  title = 'todo app';
  task: Task = {
    id: 1,
    name: '田中さんにメール'
  };
  tasks = TASKS;
}
const TASKS: Task[] = [
  { id: 11, name: '企画ロードマップ作成' },
  { id: 12, name: '山田さんにメール返信' },
  { id: 13, name: 'Angular2キャッチアップ' },
  { id: 14, name: 'ブログ更新' },
  { id: 15, name: '新卒技術研修' }
];

ngForを使ってリスト表示します。
テンプレート構文の使い方は前回のブログで!

app.component.html

<ul class="tasks">
  <li *ngFor="let task of tasks">
    <span class="badge">{{task.id}}</span> {{task.name}}
  </li>
</ul>

こんな感じでリスト表示できました。

f:id:y-iio:20170410164420p:plain

CSSを追加

チュートリアルにあるCSSの「heroes」を「tasks」に変えて使いたいので、Sassでいきます。
app.component.scssを作って呼び出します。コンパイルもしてくれるっぽい(すごい!)

app.component.ts

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})

一気にそれっぽくなりました!

f:id:y-iio:20170410164440p:plain

タスクを選択できるようにする

クリックイベントを追加

前回さらった(click)を使ってイベントを呼び出します。

app.component.html

<li *ngFor="let task of tasks" (click)="onSelect(task)">

スクリプト側にハンドラを追加します。

app.component.ts

selectedTask: Task;

onSelect(task: Task): void {
  this.selectedTask = task;
}

選ばれしタスクを表示(ngIf)

前回やったngIfを使います。
selectedTaskに値を入ったらば*ngIf="selectedTask"がtrueになるので、以下の要素が表示されるようになります。

app.component.html

<div *ngIf="selectedTask">
  <h2>{{selectedTask.name}} details!</h2>
  <div><label>id: </label>{{selectedTask.id}}</div>
  <div>
    <label>name: </label>
    <input [(ngModel)]="selectedTask.name" placeholder="name"/>
  </div>
</div>

タスクをクリックしたら…

f:id:y-iio:20170410164620p:plain

詳細が表示されるようになりました。

f:id:y-iio:20170410164629p:plain

選択中のタスクに色を付ける([class.クラス名])

これは前回はしょってやらなかったのですが、
[class.クラス名]="式"でCSSクラスの追加/削除ができるようです。

app.component.html

<li *ngFor="let task of tasks" [class.selected]="task === selectedTask" (click)="onSelect(task)">

選択されている("task === selectedTask"がtrue)ときはselectedクラスをaddしてくれます。 "task === selectedTask"がfalseならremoveしてくれます。(便利!)

f:id:y-iio:20170410164651p:plain

ソースコードまとめ

感想

ngFor, ngnIf, CSSクラスの追加/削除を学びました。
今後もチュートリアルに沿ってどんどん進めていく所存です。

ちんたらやってるうちに業務で本格的に使うことになってしまいました…頑張ります…

HRogチャートの開発フロー(バックエンド編)

f:id:suzutt:20170217000629p:plain

こんにちは2ヶ月ぶりの執筆になります。鈴木です。

新卒メンバーが入社し、CTO入倉と2年目エンジニアの飯尾が技術研修をしていまして、 毎日めきめきスキルアップしているようです。

のちのち自分も開発フロー研修をする予定です。 Qiitaをみても意外とIDEのプラグインを含めて使用方法がまとまっていなかったのでブログに書いてみました。

検証済みバージョン

以下のバージョンで検証済みです。

  • OS
    • OS X El Capitan(10.11.5)
  • Eclipse
    • Luna (4.4.2)
  • Java
    • 1.8.0_25
  • Gradle
    • 3.3
  • git
    • 2.4.2

Eclipse プラグインのバージョンです。

  • EGit
    • 3.4.2
  • Buildship: Eclipse Plug-ins for Gradle
    • 1.0.20

開発ツールのインストール

事前に以下のツールをインストールしてください。

  • Eclipse
  • 上記のEclipseプラグイン
  • git
  • Gradle

Gradleは主にプロジェクトの依存ライブラリの解決に使います。

プロジェクトの設定

Github上のリモートリポジトリのクローン

コマンドラインより、Eclipseのワークスペースに設定したディレクトリ上で以下のコマンドを実行します。

git clone https://github.com/xxxxxx/yyyyyy

Eclipseプロジェクト化

IDEの設定はEclipseの設定ファイル(.project, .classpath, .settings/)はコミットしたくないので、 clone後にはプロジェクト直下でコマンドを実行することで、これらのファイルを作成します。

gradle eclipse

賛否両論ありますが、特にクラスパスの設定がGradleの設定ファイル(build.gradle)とEclipseの設定ファイル(.classpath)でダブルメンテになってしまうのが嫌なのでこのようにしています。

Eclipseへのインポート

Eclipseを起動し、

File > Import > General > Exsiting Projects into Workspace

より、該当のプロジェクトをワークスペースにインポートしてください。

もしプロジェクトが認識されないのであれば、Eclipseプロジェクト化されていないので、 「Eclipseプロジェクト化」の手順が実施されているか再度見直してください。

Gradle Natureを追加

EclipseにGradleプロジェクトだと認識させるために以下の手順を実行します。

プロジェクトを右クリック > Configure > Add Gradle Nature

Gradleプロジェクトと認識されないと、build.gradleを元に外部ライブラリをダンロードしたり、それをクラスパスに追加したりしてくれません。

なぜ、そもそもGradleプラグインを使ってプロジェクトを作成しないのかと思ってる人がいましたら、以下のQiita記事がとてもわかりやすかったのでそちらを。。

qiita.com

Gradleプラグインを使ってプロジェクトを作成すると、コンパイルバージョンが1.5になってしまうようです。

Gradle プロジェクトをリフレッシュ

プロジェクトを右クリック > Gradle > Refresh Gradle Project

により、build.gradleの設定にしたがって、外部ライブラリがダウンロードされ、 クラスパスに追加されます。

コンパイルが通ることを確認する

この時点でコンパイルが通るはずです。もしエラーが出ているようであれば手順実施ミスか、そもそものプロジェクトがイケてないので、迷わずプロジェクトメンバーに相談を。

Githubフローに沿った開発

無事コンパイルが通れば、プロジェクトの設定は完了です。 ここからGithubフローに沿って、開発していきます。

流れとしては開発対象の機能をきめて、専用のトピックブランチを作ります。 開発のきりのいいタイミングで add, commit を繰り返し、こまめにGithub上のリモートリポジトリに push します。 フィードバックが欲しい場合や、変更が完了した場合には push 後にブラウザ上からプルリクエストをします。

以下のGithubフローについては以下の日本語訳が参考になります。

GitHub Flow (Japanese translation) · GitHub

トピックブランチの作成

機能ごとにトピックブランチを作成します。

右クリック > Team > Switch to > New branch

名前は開発内容がわかるような名前をつけます

(例)delete-freeplan-message

開発しながら、変更をgitで管理します。

コミット対象のファイルを指定

コミット対象のファイルを指定します。

プロジェクトを右クリック > Team > Add to Index

コミットする

プロジェクトを右クリック > Team > Commit

必ずコメントを入力します。チケット管理している場合はチケット番号もコメントに含めます。後で他の人が変更を追いやすくすることが目的です。

Github上のリモートリポジトリに反映する

プロジェクトを右クリック > Team > Push Branch

変更が完了したら、Github上のリモートリポジトリに変更を反映します。

プルリクエストする

開発が完了した場合や、フィードバックが欲しい場合に、プルリクエストを行います。 ブラウザ上から以下の記事を参考に実行します。

qiita.com

Eclipse上から出来るといいんですけど、そういうプラグインはないみたいですね。

ソースコードレビューを経て、マージ

プルクエストをされた内容をソースコードレビューし、問題がなければマージされます。 指摘があれば修正後、再度プルリクエストを行います。

そして、次の機能開発へ…

無事マージされたら、次の開発へ。
新しくトピックブランチを作成し、繰り返し開発していきます。

まとめ

本当はユニットテストについても作りたかったのですが、書けるほど詳しくないので断念しました。多分勝手に追記するか、次の記事で書きます。 次回投稿時はユニットテストの話か「HRogチャートの開発フロー(フロントエンド編) 」を書こうかなと思っています。

それでは。

はじめてのAngular やさしいテンプレートシンタックス編

はじめてAngularを触ってみた初心者のメモ書きです。

前回のブログではAngular CLIを使って環境構築を行いました。

developers.goalist.co.jp

今回はAngularのテンプレート構文を使ったデータバインドを試していきます。

目次

準備

前回の復習もかねてコンポーネントを追加してみます。 template-testという名前で作ってみました。

$ng g component template-test
installing component
  create src\app\template-test\template-test.component.css
  create src\app\template-test\template-test.component.html
  create src\app\template-test\template-test.component.spec.ts
  create src\app\template-test\template-test.component.ts
  update src\app\app.module.ts

前回同様app.component.htmlに作ったコンポーネントを追加します。

<h1>{{title}}</h1>
<hr>
<app-template-test></app-template-test>

これで準備完了です。 使いそうなテンプレート構文を一通りさらっていきたいと思います。

片方向データバインド

コンポーネントクラスで宣言した文字列を画面側に挿入します。
app.component.htmlの{{title}}部分と同様です。

template-test.component.tsのTemplateTestComponentクラスで式を宣言して、
template-test.component.htmlの{{式}}で出力します。

template-test.component.ts

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

@Component({
  selector: 'app-template-test',
  templateUrl: './template-test.component.html',
  styleUrls: ['./template-test.component.css']
})

export class TemplateTestComponent implements OnInit {
  value = 'goalist';
}

template-test.component.html

<p>
  {{value}}
</p>

ビルドすると画面はこんな感じに

f:id:y-iio:20170327174809p:plain

{{}}の中ではJavaScript式が使えます。
template-test.component.html

export class TemplateTestComponent implements OnInit {
  number = 10;
  ok = true;
  str = 'abcdefg';
}

template-test.component.html

<p>
  {{number * 5}}<br>
  {{ok ? 'YES' : 'NO'}}<br>
  {{str.split('').reverse().join('')}}<br>
</p>

結果はこんな感じ

f:id:y-iio:20170327174831p:plain

関数を呼び出したりもできます。
TemplateTestComponentクラスで関数を宣言して

export class TemplateTestComponent implements OnInit {
  getHoge(): string {
    return 'hoge';
  }
}

HTML側から呼び出し

<p>
  {{getHoge()}}
</p>

結果はこんな感じ

f:id:y-iio:20170327174859p:plain

双方向データバインド

画面側で入力した値と、コンポーネントクラスの変数の値が同期します。

export class TemplateTestComponent implements OnInit {
  inputText = "初期値";
}
<input [(ngModel)]="inputText">
<p>
  {{inputText}}
</p>

コンポーネントクラスで変数宣言するときに初期値を指定しておくことができるようです。
ちなみに変数宣言しなくてもエラーになりませんでした。なぜかしらん。

f:id:y-iio:20170327174918p:plain

リスト表示(ngFor)

for文風に使えます。
配列から要素を取り出して、ngForを書いたHTML要素を繰り返し出力します。
Vue.jsでいうところのv-forとほぼ同じです。

ary = ['りんご', 'ごりら', 'らっぱ']のとき

<div *ngFor="let item of ary">
  {{item}}
</div>

ビルド後はこうなります。

<div>りんご</div>
<div>ごりら</div>
<div>らっぱ</div>

let i=indexのようにインデックス変数を宣言して使うこともできます。

<div *ngFor="let item of ary; let i=index">
  {{i+1}}: {{item}}
</div>

f:id:y-iio:20170327184824p:plain

HTML要素の表示/非表示(ngIf)

if文っぽく使えます。
式の値がtrueのときにngIfを書いたHTML要素を出力します。

isVisible = trueのとき

<div *ngIf="isVisible">このdivは出力される</div>
<div *ngIf="!isVisible">このdivは出力されない</div>

Vue.jsのv-ifと同じで要素自体が無くなります。
v-showみたいにstyle:block/noneみたいなやつはないんでしょうか。

HTML要素の表示切り替え(ngSwitch)

switch文っぽく使えます。
ngSwitchを書いたHTML要素の子要素から、条件に一致するもののみを出力します。

<div [ngSwitch]="condition">
  <div *ngSwitchCase="'case1'">condition = 'case1'のとき出力される</div>
  <div *ngSwitchCase="'case2'">condition = 'case2'のとき出力される</div>
  <div *ngSwitchDefault>どの条件にも一致しないとき出力される</div>
</div>

HTML要素のプロパティ指定

[プロパティ名]="式"で指定したプロパティに値を代入できます。

isDisabled = trueのとき

<button [disabled]="isDisabled">このボタン要素にdisabledが効く</button>

こんな風に使えそうです。

<input id="agreement" type="checkbox" [(ngModel)]="isAgreed">
<label for ="agreement">同意する</label>
<button [disabled]="!isAgreed">送信</button>
isAgreed = false;

f:id:y-iio:20170327184229p:plain

イベント処理

(イベント名)="式"で式を呼び出します。

<button (click)="alert()">アラート表示</button>
alert(): void {
  window.alert('you clicked');
}

f:id:y-iio:20170327185056p:plain

ソースコードまとめ

今回使ったソースはこんな感じになりました。

感想

このブログを書いている間にアップデートがあってAngular2が4になってしまいました。
めげずに頑張ります。

はじめてのAngular Windowsで環境構築~とりあえず触ってみよう編

Windowsで環境構築~とりあえず触ってみよう編

このブログを書いた人

  • プログラミングを始めて1年弱
  • TypeScriptはこれから勉強します
  • JSフレームワークだとVue.jsなら触ったことある
    くらいの初心者

今のところ環境

  • node: 6.3.0
  • os: win32 x64

Angular CLIを入れてみる

開発環境構築にはAngular CLIというツールが便利らしいのでインストール

npm install -g @angular/cli

バージョンは1.0.0-beta.28.3 でした

ヌッ…黄色い字の警告文…

As a forewarning, we are moving the CLI npm package to "@angular/cli" with the next release,
which will only support Node 6.9 and greater. This package will be officially deprecated
shortly after.

node公式を見たら最新安定板はv6.10.0だったのでバージョンを変える

インストール済みのやつを確認

nodist
   (x64)
   4.4.7
 > 6.3.0  (global: 6.3.0)

使いたいバージョンをインストールする

nodist + v6.10.0

バージョンを切り替える

nodist 6.10.0

これでよし

nodist
   (x64)
   4.4.7
   6.3.0
 > 6.10.0  (global: 6.10.0)

プロジェクトを生成してみよう

適当なディレクトリ下で

ng new my-new-app

ちょっと待ちましたが Project 'my-new-app' successfully created. ですって

さっそくサーバー起動

cd my-new-app
ng serve

webpack: Compiled successfully.が出たらhttp://localhost:4200/をブラウザで見てみる

f:id:y-iio:20170316193815p:plain
動いてる~オッホホ!

エディタで中身を見てみよう

Angular CLIが自動でこんなかんじのディレクトリ構成を作ってくれたので f:id:y-iio:20170316193849p:plain

src以下を見ていきます。

index.html

<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <title>MyNewApp</title>
  <base href="/">

  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
  <app-root>Loading...</app-root>
</body>
</html>

<app-root></app-root>のところにたぶんこの部分が入るのか?
f:id:y-iio:20170316193923p:plain

中身をチェックだ

app.component.html

<h1>
  {{title}}
</h1>

app.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'app works!';
}

app.component.tsのここの部分でコンポーネント定義されてて

@Component({
  selector: 'app-root', // このセレクタで呼び出す
  templateUrl: './app.component.html', // コンポーネントの中身のhtml参照先のパス
  styleUrls: ['./app.component.css'] // コンポーネントの中身のcss参照先のパス
})

ここがデータバインド部分かしら

export class AppComponent {
  title = 'app works!';
}

titleを変えてみよう

title = 'hello world!';

保存したらng serveのビルド処理が走る!
LiveReloadでブラウザが自動更新される!
f:id:y-iio:20170316194239p:plain
変わってる~!

新しいコンポーネントを作ってみよう

greetingという名前のコンポーネントを作ってみます。

ng generate component greeting
 installing component
  create src\app\greeting\greeting.component.css
  create src\app\greeting\greeting.component.html
  create src\app\greeting\greeting.component.spec.ts
  create src\app\greeting\greeting.component.ts
  update src\app\app.module.ts

(なんかいろいろ作ってくれた…)

app/greetingに中身の一式を
f:id:y-iio:20170316194534p:plain

app.module.tsはこのあたりを書き加えてくれたようです。
f:id:y-iio:20170316194546p:plain

これでimportと宣言されるんで呼び出せるようになるということかしら。

greeting.component.tsを見たところ、
greetingコンポーネントのセレクタ名はapp-greetingになるらしい。
f:id:y-iio:20170316194642p:plain

というわけでapp.component.htmlに以下のように書き加えます。

<h1>
  {{title}}
</h1>
<app-greeting></app-greeting>

greeting.component.htmlを好きに変更して…

<p>
  welcome to my app
</p>

ドン
f:id:y-iio:20170316194707p:plain
コンポーネント足せた~!

まとめ

というわけではじめてのAngular2、とりあえず触ってみることができました。
Angular CLIのおかげで何やら難しげなimportなんかの整理やビルドも楽々です。
最終的には公式チュートリアルを参考にしつつ、TODOアプリ的なものを作ってみたいと思っています。
次回はやさしいテンプレート構文編です。
乞うご期待!

Angular2とJavaでPay.jpの定期課金をやってみる

こんにちわ!
ゴーリスト開発のモリツグです。

Angular2で何かすることを隠れ蓑にFlexを懐かしんできた1回目2回目でしたが、残念ながら今回はFlexを懐かしむ要素がありません。

今回は以下のような方に向けた内容になります。
・Angular2とJavaでクレジットカード課金したい
・Pay.jpを使ってみようと考えている方

Pay.jpとは

クレジットカードの決済周りのAPIを提供してくれているサービス。
サイトの説明やAPIドキュメントがものすごく分かりやすくて良い。
APIで出来ることは大体全部サイト上のGUIでも提供されており、売上などのダッシュボードが綺麗。
定期課金にも対応。

カード情報のトークン化

詳しくはこちらになるのですが、Angular2ではコンポーネントにscriptタグを埋め込んでもコンパイラが削除するので「<script> タグ一行で実装可能」的なものは利用できません。
ngAfterViewInitとかで頑張って突っ込んでみても正常に動作しなかったので皆さんは無駄な努力をしないように願っています。
したがって今回はpay.jsを利用してトークンを作成しました。

// コンパイラに怒られるので定義しておく
declare var Payjp: any;

@Component({
 .....
})
export class CreditCardDialog{
  .....
  // パブリックキーをセット
  Payjp.setPublicKey(PAY_JP_PUBLIC_KEY); 

  // カードオブジェクトを作成
  let card: Object = {
    number: "4242424242424242",
    cvc: "123",
    exp_month: "12",
    exp_year: "2020"
  };
  
  // tokenを取得 エラーかどうかはstatusで判定
  Payjp.createToken(card, (status, response) => {
    let token:string = response.id;
  });
  .....
}

PAY_JP_PUBLIC_KEYはPay.jpからアカウントごとに発行されるパブリックキーです。
以降のトークンを利用したサーバ側でのPay.jpへのリクエストではシークレットキーを利用します。
サーバ側でのCustomerの作成と事前に作成しておいた定期課金プラン(Subscription)をユーザに紐づける処理は以下になります。
定期課金プランはAPIでも作成できますが、Pay.jpのサイト上でGUIで作成したほうが楽です。
コード中のPAY_JP_PLAN_IDは定期課金プランのIDです。

// トークンを用いてユーザを作成
Map<String, Object> customerParams = new HashMap<String, Object>();
customerParams.put("id", "cus_01");
customerParams.put("email", email);
customerParams.put("card", tokenId); // 先ほど作成したトークンをセット
Customer customer = Customer.create(customerParams);

// 作成したCustomerに定期課金プランを登録する
// 今回のプランではフリー期間なしですぐに初回の課金が行われる
Map<String, Object> subscriptionParams = new HashMap<String, Object>();
subscriptionParams.put("plan", PAY_JP_PLAN_ID);
subscriptionParams.put("customer", customer.getId());
Subscription.create(subscriptionParams);

まとめ

Angular2でscriptタグをComponent中に埋め込めないので少し面倒かなという印象です。
Pay.jpは登録すると本番環境とテスト環境の2つのキーを発行してくれるのでテストも簡単です。
メジャーバージョンアップしてAngular4になりましたが、進化の速さに負けずにユーザが増えてくれるといいなぁと思います。

中途エンジニア、ブログを書く

はじめまして、JPです。
名付け親は新卒エンジニアのイイオさんです。
自己紹介します。

f:id:j-itoh:20170321180331j:plain
真ん中が自分、右がセールスのすぎやんさんです。いい天気です。

経歴

プロフィール

社会人4年目、26歳、男、メガネ

好きなこと

ゴルフ、麻雀、漫画

学業

4年制大学、経済学部卒業

就職活動
  1. ERPパッケージベンダーのインターンシップに申し込む(給料が高かったから)
  2. インターンシップでプログラミングに出会う(はまる)
  3. そこに入社する
仕事内容
  1. 半年研修(長い)
  2. 会社の労務である社員の健康診断管理に関するシステムで以下を経験
     - 不具合修正、機能追加、テスト、導入、webアプリケーションへの置き換え
      (人間1人分の仕事量じゃない)
  3. 新製品のインフラチームに異動
     - Linux, Vagrant, Docker, Jenkins等に軽く触れる(すぐ忘れる)
  4. ゴーリストにジョイン
  5. webアプリケーションの新機能開発で以下を経験
     - 仕様検討、DB設計、チームメンバーのタスク管理 (開発もちょっと)
  6. 現在、プロジェクトメンバーとしてパートナー会社の大規模システム開発に参加
    (周りは強者だらけ)
まとめ

プログラミング未経験の自分にとっては激動の4年間でした。
担当機能の前任者もおらず、仕様に関する資料等もないところからスタートし、分からないことが当たり前の状況の中、様々な業務を経験することができました。

ゴーリストでは今までに経験のないチームでの仕事を担当させてもらいました。
自分があまり開発していないのに製品ができあがるのは不思議な感覚です。

これから

最近はゴーリストのミッションの1つである「チームで結果を出すこと」の意義を日々感じています。
また、チームメンバーに外国人がいたりして難しい部分もありますが、これを乗り越えればビジネスパーソンとして一皮剥けそうです。
ブログでは自分が工夫して効率化したことについて取り上げていく予定です。

UITextFieldのキーボード操作で使えるTips

こんにちは。
最近タイピング時に小指が痛い渡部です。

f:id:watabe1028:20170316174757j:plain

今日はアプリ開発時によく使うUITextFieldのキーボード操作に便利なTipsについて書きます。

結構面倒な実装だし、ググると色々なパターンがあって悩んでしまう人もいると思うので
個人的に一番簡単だと思う実装方法を紹介しようと思います。

多分最も使うであろう機能
1.ボタン押下でキーボードを閉じる
2.ボタン押下で次のUITextFieldに移動する
3.画面タップでキーボードを閉じる
4.入力欄にかぶらないように画面をひょいっと動かす
を順に書いて行きます。

1.ボタン押下でキーボードを閉じる

まずはSingle Applicationでプロジェクトを作成し、UITextFieldを設置します。

まずここでビルドするとUITextFieldをタップするだけでキーボードが表示されます。
(背景をlightgrayにしてます)

f:id:watabe1028:20170316173204p:plain

しかし、その後閉じることができません。

「return」ボタンを「Done」ボタンに変更し、閉じれるように変更します。

手順1

StoryboardでUITextFieldを選択し、「Return Key」を「Default」から「Done」に変更します。

f:id:watabe1028:20170316173232p:plain

手順2

UITextFieldをOutletでソースと紐づけます。
そのままDelegateの設定をし、必要なデリゲートメソッドを記述して行きます。

import UIKit

class ViewController: UIViewController, UITextFieldDelegate {

    @IBOutlet weak var textField: UITextField!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        textField.delegate = self
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}

デリゲートメソッドを追加

    // このメソッドを追加
    // Doneボタン押下でキーボードを閉じる
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        
        textField.resignFirstResponder()
        return true
    }

これでキーボードを閉じる設定ができました。

2.ボタン押下で次のTextFieldに移動する

次は入力フォームのような複数のUITextFieldがある場合、
「Next」ボタンを押して次のUITextFieldに移動するように設定します。
今回はタグを使ってやってみます。

手順1

UITextFieldを一つ追加してOutletで繋ぎます。

最初のUITextFieldにはタグに「0(デフォルト)」を
追加したUITextFieldには「1」を設定します。

f:id:watabe1028:20170316173302p:plain f:id:watabe1028:20170316173324p:plain

手順2

最初のUITextFieldの「Return Key」を「Done」から「Next」に変更します。
追加したUITextFieldの「Return Key」を「Default」から「Done」に変更します。

手順3

先ほど追加したデリゲートメソッドの中身を変更します。
内容はボタンが押されたUITextFieldのタグによって次に進むか
キーボードを閉じるかを判断します。

    // このメソッドを修正
    // Doneボタン押下でキーボードを閉じる
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        
        switch textField.tag {
        case 0:
            // タグが0ならsecondTextFieldにフォーカスを当てる
            secondTextField.becomeFirstResponder()
            break
        case 1:
            // タグが1ならキーボードを閉じる
            textField.resignFirstResponder()
            break
        default:
            break
        }
        return true
    }

コード的にはスマートではないですが、とってもシンプルですね。

これでフォーカスの移動とキーボードの閉じるが実装されました。

3.画面タップでキーボードを閉じる

実はUITextFieldのキーボードはキーボードをしまうインターフェースがありません。
なので大体のアプリでは画面の他の部分をタップするとキーボードが閉じるように設定されています。

手順1

タップジェスチャーを追加します。
Storyboardで「Tap Gesture Recognizer」をviewに追加します。

f:id:watabe1028:20170316173345p:plain

手順2

追加するとViewController上部に表示されるので
そこからソースと紐づけます。
今回はOutletではなくActionにします。

f:id:watabe1028:20170316173405p:plain

手順3

追加したメソッドに1行追加します。
たった1行です。

    // 画面タップ時に呼ばれる
    @IBAction func tapScreen(_ sender: Any) {
        self.view.endEditing(true)
    }

これで完了です。
実行すると画面タップでキーボードが閉じます。

4.入力欄にかぶらないように画面をひょいっと動かす

これはちょいと面倒です。
色々なやり方がありますが、個人的に最も簡単な方法は
入力時に画面自体を動かしてしまうことです。
ボタンを追加してキーボードに隠れてしまうように設置します。
仮にログインボタンとします。

f:id:watabe1028:20170316173427p:plain

手順1

NotificationCenterという通知をviewDidLoadに追加します。
キーボードを開く際に通知で画面を動かす処理を呼び出します。

通知の設定

        // キーボードを開く際に呼び出す通知
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
        
        // キーボードを閉じる際に呼び出す通知
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
手順2

同様に閉じる処理を呼び出す処理も追加。

    // キーボード表示時
    func keyboardShow() {
        // キーボードを開く際に画面を上に50ずらす
        self.view.bounds = CGRectMake(0, 50, self.view.frame.size.width, self.view.frame.size.height)
    }
    
    // キーボード非表示時
    func keyboardHide() {
        // キーボードを閉じる際に画面を元に戻す
        self.view.bounds = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)
    }

ついでにSwift3ではCGRectMakeはそのままでは使えないので
自分でラップさせます。
筋肉で解決です。

    // CGRectMakeをwrap
    func CGRectMake(_ x: CGFloat, _ y: CGFloat, _ width: CGFloat, _ height: CGFloat) -> CGRect {
        return CGRect(x: x, y: y, width: width, height: height)
    }

以上の追加でキーボードの表示、非表示で画面がいい感じに動きます。

f:id:watabe1028:20170316173446p:plain

まとめ

いかがだったでしょうか?
以外に面倒なキーボード操作もこれくらいなら
コピペで10分で実装できます。
いちいち実装が面倒な時はこのブログをコピペで使って頂けたらと思います。