- 投稿日:2020-01-20T21:40:13+09:00
UITableViewでセルを選択不可にする方法
- 投稿日:2020-01-20T19:15:54+09:00
signin with apple 実装するときの注意点まとめ
対応バージョン
iOS13以上、iOS13以下は対応しないため、別々のデザイン準備する必要があります。
取得できるユーザーデータ
- ユーザーの選択でランダム生成されたメール渡せる可能性があります
- full name
- ユーザーの編集可能で、apple id登録された名前とは限らない
sign in 初回と2回目の違い
sign in 初回はメールと名前のユーザーデータ取れますが、その以後sign inする場合は取得できなくなります。
初回取得成功後key chainなどに保存し、登録成功後削除したほうが一番無難。let request = ASAuthorizationAppleIDProvider().createRequest() request.requestedScopes = [.fullName, .email] let controller = ASAuthorizationController(authorizationRequests: [request]) controller.delegate = self controller.presentationContextProvider = self controller.performRequests()extension AppleSigninService: ASAuthorizationControllerDelegate { func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) { guard let credentials = authorization.credential as? ASAuthorizationAppleIDCredential else { let error = NSError(domain: "jp.huiping192.signInWithApple", code: -1000, userInfo: nil) signInSubject?.onError(error) return } // アプリ起動時ログイン状態チェックのためcredentials.user keychainに保持する saveUserId(credentials.user) // mailとnameある場合一時保持、登録成功後に削除 saveUserInfo(nickname: credentials.fullName?.nickname, email: credentials.email) } func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) { // error handing } }AppleID使用停止検知
「設定」 -> 「{Apple ID}」->「パスワードとセキュリティ」-> 「Apple IDを使用中のApp」 -> 「{app name}」-> 「Apple IDの使用を停止する」
ユーザーは上の手順でSign in with Apple使用停止することが可能なので、アプリ側にチェックする必要があります。
- アプリ起動時
ASAuthorizationAppleIDProvider().getCredentialState(forUserID: appleUserID) { credentialState, _ in if credentialState != .authorized { // logout User.current.logout() } }
- アプリ起動中
NotificationCenter.default.rx.notification(ASAuthorizationAppleIDProvider.credentialRevokedNotification).subscribe(onNext: { _ in // logoutしとく User.current.logout() }).disposed(by: disposeBag)AppleID使用停止後再度登録
新しいユーザーを扱い、token、ユーザー情報新しく取得できる。
- 投稿日:2020-01-20T16:29:15+09:00
iOS Clean Architecture勉強会のまとめ
この文章は2020年1月21日に行われた「iOS Clean Architecture勉強会 sponsored by Sansan」という勉強会のまとめです。
発表内容
yimajo: 「クリーンアーキテクチャとiOSアプリ開発のためのVIPERと」
- 依存関係逆転の原則(DIP)について
- VIPER
- VIPERの種類色々ある
- VIPERはDIPを使ってない
- DIPを使ってない場合の依存を取り除くには
- Interactorごと取り替える
- DBに依存したデータを表示するためのstructなどに置き換える
スライド
https://speakerdeck.com/yimajo/kurinakitekutiyatoiosahurikai-fa-falsetamefalseviperto
dotrikun: 「ゼロイチフェーズからのClean Architecture」
- DeNAテックカンファレンスあります
- 新規アプリでクリーンアーキテクチャは食い合わせ悪いのか
- これまで3本は非CA
- 4本目はCAを採用
- AppRootViewController使ってる
- 起動時
- RouterにHUDいれてる
- 悩んでる
- Embedded Framework
- UIではないEntity, UseCaseをEmbedded Frameworkで分けている
- どこになにがあるかは慣れた
- あとでWatchようにしたりするよりさきに分けておくと楽だった
- ドメインロジックで切り出す
- 他のアプリでも使える
- クリーンアーキテクチャで先に作る「技術的投資」
- 大きな会社のプロダクトなのでリターンが見込めそう
- スタートアップだと厳しそう
スライド
https://speakerdeck.com/dotrikun/ios-ca
ChaaaaaaaaaaanU: 「VIPRE + MicroViewController を組み合わせて大きな機能を実装した話」
- Sansan株式会社でSansanアプリを作ってる
- 人物詳細
- かなりリッチな画面(機能が多い)
- 1つのVIPERモジュールではきつい
- なのでMicroViewController使う
- 各ViewControllerの中にVIPERの構成
- Routerがなかったりする
- MicroViewControllerのInstantiatableプロトコルはVIPERのRouterと役割がかぶる
- 中途半端に両方を使わない
スライド
LT5分 kageroupro44: 「クリーンアーキテクチャ導入が、 どのような作業に影響を及ぼすのか考察」
- インターンでfancというアプリ作ってる大学三年生
- クリーンアーキテクチャ導入後
- レイヤーやクラスが責務によって分かれた
- 担当ワケできたので作業の短縮できた
- 開発者感共通認識
- 共通認識があるので全体的にスピードが上がった
- 実装に統一感が生まれた
- ファイルが増えた
スライド
hirothings:「VIPER with アーキテクチャ選定 実践入門」
- VIPER以前の課題
- ViewControllerで個別に遷移してた
- プレゼンテーションロジックとデータ用のロジックが混在
- 選定(VIPERに至る)
- データバインディングは必要なし(インタラクティブいらない)
- DBもなし
- サンプルを作ったりして選定した
- VIPERにしてよかったこと
- ユニバーサルリンクからでもRouter使って画面表示が楽
- iOSアプリ設計パターン(Routerの記述がいい)
- テストしやすい実装を後押ししてくれる
- 単体テストのはじめというスライドが良い
- VIPER良い点
- 層が分かれているので担当が分かれている
- Embedded Framework
- UIに関連する/しないでフレームワーク分割
- 正しさよりも影響範囲で分けた
- CM
- 個人で作ってます
- 作りはMVC
- アプリの成長によってアーキテクチャを選定するのでクリーンアーキテクチャじゃない
スライド
https://speakerdeck.com/hirothings/viper-architecture
takasek: 「モバイルアプリにおける『中心』とは何か」
- 中心とは?
- 創界山!!
- クライアントアプリはハブ
- JSONの色付けは難しい
- クライアントアプリの「ドメインロジック」は「エンティティ=中心」にあるとは限らない
- CA本19章
- 方針はさらに小さな方針に分離される
スライド
https://speakerdeck.com/takasek/20200121-the-center-of-the-client-number-ios-ca
座談会での質問
参加者の皆さんに頂いたアンケートから、発表者に質問に答えてもらいました
質問: Routerの呼び出しはenumだけだと他のパラメータどうしてるんだろ
- ChaaaaaaaaaaanU
- 情報はenumに入れている
- コールバックもある
- ボイラープレートはenumに吸収させたい
質問: 個人アプリでCA導入しようと思うきっかけがあれば教えてほしいです。
- hirothings
- アプリの複雑性よりも上位の問題が気になるのでCAでやってない
- サーバサイドを気にしている
- サーバサイドはテスト書いている
- Firebaseだから?
- そう
- お金がかかわるから
- NoSQLでセキュリティ・ルールが必要
質問: CA初学者にCAの概念と、実際の実務での差分のうまいフィッティングがあれば教えてほしいです。
- 役割を考えるとシンプル
- アプリに関係ない部分が外側にある
- 外の世界をつなげるとこ
- それで4つの世界
- アプリに関係ある/ない/糊/外側
- 投稿日:2020-01-20T16:00:04+09:00
ダークモードとは何か?各OSの設定方法からiOS/Androidアプリの対応方法まで
はじめに
勉強会をご覧の皆さま
元々のテーマは「10分でわかるダークモード対応」でしたが、あちこち調べているうちにページ数が30を超えてしまい、「10分ではわからないダークモード対応」になりました?♂️
20分には収めます
ダークモードとは?
OSシステムレベルで設定可能な、画面表示色の設定です。
Light Modeが従来通りの白基調な画面、Dark Modeは黒基調な画面です。
何が明るく/暗くなるの?
特定の何に適用すべきという法則は無いようですが、閲覧者に見せたいコンテンツ以外のウィンドウ枠、背景などに対して適用されることが多いようです。
もちろん、メインコンテンツ(テキスト色など)も背景色に応じて調整する必要があります。
ダークモードにすると何がいいの?
- 目へのダメージを抑える
- 眩しい画面を見ることによるドライアイ、頭痛、メラトニン抑制による不眠など
- バッテリーの持ちが長くなる
- OLEDスクリーンで輝度が100%の場合、DarkはLightと比較して約60%のエネルギーを節約。輝度が50%の場合、約15%節約(YouTubeアプリで計測)
- 背景は明るいより暗いほうが、メインのコンテンツを目立たせ、作業に集中しやすくする
ダークモードにする場合のデメリットや注意点
- 直射日光の下などの明るい場所で読みづらい
- ナイトモード(ブルーライトカットの)と同じように、日没〜日の出までダークモードとする設定が用意されている
- テキスト色と背景色の逆転にOCRが追いついていない
- ダークモードで撮ったスクショをGoogle翻訳にかけても(現時点では)翻訳してくれない?
ダークモード対応OS
- Windows 10 version 1903〜
- Mac OS Mojave(10.14)〜
- Android 10〜
- iOS 13〜
ダークモード設定方法
- Windows
- スタート -> 設定 -> 個人用設定 -> 色
- macOS
- -> システム環境設定 -> 一般 -> 外観モード
- Android
- 設定 -> ディスプレイ -> テーマ
- Zenfoneの場合は 設定 -> ディスプレイ -> システムカラースキーム
- クイック設定パネルに追加したい場合は 画面上端を下にスワイプ -> ?
- iOS
- 設定 -> 画面表示と明るさ -> 外観モード
- コントロールセンターに追加したい場合は 設定 -> コントロールセンター -> コントロールをカスタマイズ
iOS/Androidアプリでのダークモード対応方法(アプリエンジニア向け)
iOS
準備
- Xcode 11以上のビルド環境
- iOS 13以上の実機orシミュレーター
iOSダークモード対応は急務!!
- iOSアプリが2020年4月以降、iOS 13 SDKビルドでの審査提出が必須となる
- iOS 13 SDKビルドはデフォルトでダークモードがONになる
UIUserInterfaceStyle
を使えば一時しのぎ出来るが、公式は移行を強く推している
- 将来効かなくなる可能性が高い
まずダークモードの見え方を確認しよう!
StoryboardやXibのInterface Builder上でLight/Darkを切り替える
デバッグ実行中にLight/Darkを切り替える
Darkにして、どうなったか。弊社案件の場合
- テキストが自動で白くなったが背景も白い。文字が読めない!
- 背景が自動で黒くなったがテキストも黒(
- 濃緑基調のグラフィックが黒い背景では見えづらい
- QRコードが真っ黒黒助
何故そうなるのか
- 場所によってiOS System Colorsを使ったり使わなかったりするため
- 大人数のプロジェクトでありがちな統一感の甘さ
- とはいえiOSのStoryboardを完璧な統一感で作った人は見たことありませんが…?
対応作業
カラーセットを使う場合
- ハードコードしている色をAssets CatalogのColor Setに移行する
- Color SetのAppearancesにてDarkを追加する
- Dark Appearanceにフォーカスを合わせ色設定する
- 色は従来のsRGB方式以外に、iOS System Colorsも選択可能
darkTextColor
やsystemBackgroundColor
など- 使うとOS側が色の濃さを自動調整してくれる。便利!
- 詳しくは参考記事の実践 iOS13ダークモード対応に、わかりやすく書かれています
カラーセットを使わない場合
- アプリ起動中にLight/Darkを切り替えられても即反映させたいので、次のいずれかの方法で実装
- dynamicColor方式
extension UIColor { private class func dynamicColor(light: UIColor, dark: UIColor) -> UIColor { if #available(iOS 13, *) { return UIColor { (traitCollection) -> UIColor in if traitCollection.userInterfaceStyle == .dark { return dark } else { return light } } } return light } public static var textColor: UIColor { return dynamicColor( light: UIColor(displayP3Red: 0, green: 9, blue: 11, alpha: 1), dark: UIColor(displayP3Red: 255, green: 246, blue: 244, alpha: 1) ) } }
- dynamicProvider方式
extension UIColor { @available(iOS 13.0, *) convenience init(light: UIColor, dark: UIColor) { self.init { if $0.userInterfaceStyle == .dark { return dark } else { return light } } } @available(iOS 13.0, *) public static let textColor = UIColor( light: UIColor(displayP3Red: 0, green: 9, blue: 11, alpha: 1), dark: UIColor(displayP3Red: 255, green: 246, blue: 244, alpha: 1) ) }こちらはSDKバージョンの制限を受けますが、initとして処理を書けて、定数をimmutableにできます。
Android
準備
- Android Studio 3.3以上のビルド環境
- Android 10(Q)以上の実機orシミュレーター
まずダークモードの見え方を確認しよう!
Design View上でLight/Darkを切り替える
開発者向けオプションを使う
- システム -> 詳細設定 -> 開発者向けオプション -> フォースダークのオーバーライド
- アプリの実装を変えずダークモードをシミュレートできる
Darkにして、どうなったか。弊社案件の場合
- Design View上では何も変わらなかった…
- Android版は
?android:attr/textColorPrimary
などのシステムカラーを使っていなかったから- Androidチームはデザイン指示書に厳密に従ったので、システムカラーを使わなかった
- でも、開発者向けオプションだといい感じのダークモードになった
- iOSで起きてた問題は一切起きなかった(細かい部分を見ると直したい色はあったが)
- Android10の強制ダークモードは割としっかりダークしてくれるの例と同じような結果だった
対応作業
styles.xml
やcolors.xml
を別々に用意する
- Light:
res/values/*
- Dark:
res/values-night/*
- 共通のものはLight側にまとめよう
- Darkの方には、夜間モードかフォースダークを適用する(後述)
- 2つの重ね掛けはできないらしい
- もしくは、iOSのSystem Colorsに相当するテーマの属性やマテリアルデザイン コンポーネントを利用することもできる。厳密にカラー指定しない場合はこちらがオススメ
- 色のハードコードは厳禁らしい
夜間モード機能を使う
- アプリを新規作成すると自動で
Theme.AppCompat.Light
系のテーマが適用されているが、Dark側のスタイルにはTheme.AppCompat.DayNight
を適用するres/values-night/themes.xml<style name="AppTheme" parent="Theme.AppCompat.DayNight.NoActionBar" />
フォースダーク機能を使う
- 各ビューを分析して自動でダークカラーに変えてくれる機能
- 先述の開発者向けオプションを使った確認では、こちらがシミュレートされる
res/values-night/themes.xml<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"> <item name="android:forceDarkAllowed">true</item> </style>
- 自動で変えたくないビューには、AppTheme以外のstyleを用意して適用すればよい
Androidのダークモードサポートは色々手厚い!
- より詳しく知りたい場合、こちらを参照
WebViewの場合は?
- Web側CSSで対応するらしい(StackOverflowより)
まとめ
- ダークモードは目とバッテリーに優しく、集中できる!
- iOSは2020/04まで(03末?)にダークモードを対応するか、一時しのぎでLightに固定しなければならない
- まずは動かしてみないと修正規模がわからない
- Androidはフォースダークで対応するのが手っ取り早そう
最後に大事なこと
- ダークモード対応はエンジニアファーストで提案しよう!
- 顧客やPMは、iOS SDKの事情でダークモード対応が必要なんて知る由もない
- 工数削減のために、自動調整してくれるシステムカラーは最大限活用しよう!
- 活用すれば、20画面あっても半日で終わるから怖くない(ヤバいAppは知りません)
- デザイナーにも必要な情報を公開しよう!
- 一言「ダークモード版の素材と指示書お願いします」で受けてくれるデザイナーは奇跡の存在です(個人の所感)
やっぱり言わせてください
参考
- Use Dark Mode on your iPhone, iPad, or iPod touch
- How to use Dark Mode on your Mac
- The Benefits of Dark Mode: Why should you turn off the lights?
- ダークテーマ | Android デベロッパー | Android Developers
- Dark Mode - How to support Dark Mode for iOS 13 using Xcode
- 実践 iOS13ダークモード対応
- Android10の強制ダークモードは割としっかりダークしてくれる
- 投稿日:2020-01-20T12:54:57+09:00
Swift で 画像 (UIImage ) の リサイズ と トリミング (切り抜き) を一度の処理で行う。
0.はじめに
Swift で画像の切り抜きとリサイズを一度の処理で行いたかったので、やってみました。
以下の記事を参考にさせて頂きました。
- UIImageのリサイズ方法と注意点 - Qiita
- 【Swift4】UIImageで画像のサイズ変更、指定した倍率で拡大/縮小 - Qiita
- Swift3.0で画像の切り抜き - Qiita
- [Swift] 画像のサムネイル生成(縮小&切り抜き) - Qiita
感謝 ♪♪♪
?♂️?♂️?♂️
1.コード
今回は、画像を 0.5 倍にリサイズしつつ、中心部分を正方形に切り抜いてみました。
var _image: UIImage = image var compress: CGFloat = 0.5 var oneside: CGFloat = _image.size.width < _image.size.height ? _image.size.width : _image.size.height let origin: CGPoint = _image.size.width < _image.size.height ? CGPoint(x: 0.0, y: (_image.size.width - _image.size.height) * 0.5 * compress) : CGPoint(x: (_image.size.height - _image.size.width) * 0.5 * compress, y: 0.0) UIGraphicsBeginImageContextWithOptions(CGSize(width: oneside * compress, height: oneside * compress), false, 0.0) _image.draw(in: CGRect(origin: origin, size: CGSize(width: _image.size.width * compress, height: _image.size.height * compress))) _image = UIGraphicsGetImageFromCurrentImageContext()! UIGraphicsEndImageContext()■ リサイズ
まず、以下の処理で、出力先のサイズを指定します。
var oneside: CGFloat = _image.size.width < _image.size.height ? _image.size.width : _image.size.height UIGraphicsBeginImageContextWithOptions(CGSize(width: oneside * compress, height: oneside * compress), false, 0.0)■ トリミング (切り抜き)
そして、以下の処理で、画像をトリミング (切り抜き) します。
let origin: CGPoint = _image.size.width < _image.size.height ? CGPoint(x: 0.0, y: (_image.size.width - _image.size.height) * 0.5 * compress) : CGPoint(x: (_image.size.height - _image.size.width) * 0.5 * compress, y: 0.0) _image.draw(in: CGRect(origin: origin, size: CGSize(width: _image.size.width * compress, height: _image.size.height * compress)))重要なポイントは、
draw 関数の引数に指定する CGRect の値 (origin も、size も) を出力後の値で設定する
こと。
99.ハマりポイント
- 上述しましたが、draw 関数の引数に指定に結構手間取りました…。
???
XX.まとめ
以上、ご参考になれば ♪♪♪
???
- 投稿日:2020-01-20T12:17:35+09:00
CustomCellに置いたButtonの選択状態によってTableViewの処理を変える
タップしたButtonが乗ってるCellの情報をFirestoreに保存したい。
その想いから、こんなややこしい(?)記述方法になってしまいました。ご了承下さい。
Firestoreの部分は他記事にDelegate!開発環境
・Xcode 11.3
・Swift 5.0UIButtonのextensionを作る
CustomCell.swiftextension FaveButton { func switchAction(onAction: @escaping ()->Void, offAction: @escaping ()->Void) { switch self.isSelected { case true: //ONにする時に走らせたい処理 onAction() case false: //OFFにする時に走らせたい処理 offAction() } } }ButtonActionにDelegateを設定する
CustomCell.swiftimport UIKit protocol CellDelegate: AnyObject { func didTapButton(cell: CustomCell) //ON func didUnTapButton(cell: CustomCell) //OFF } class CustomCell: UITableViewCell { weak var delegate: CellDelegate? @IBAction func didButtonTapped(_ sender: UIButton) { sender.switchAction(onAction: { //TableViewController.swiftのdidTapButton()に委任 self.delegate?.didTapButton(cell: self) },offAction: { //TableViewController.swiftのdidUnTapButton()に委任 self.delegate?.didUnTapButton(cell: self) }) } }TableViewController.swiftimport UIKit class TableViewController: UITableViewController, CellDelegate /*追記*/ { func didTapButton(cell: CustomCell) { print("ON") } func didUnTapButton(cell: CustomCell) { print("OFF") } }参考
- 投稿日:2020-01-20T09:54:06+09:00
[Swift] IntやDoubleなどの数字オブジェクトを2倍にする関数でジェネリクスを使ってみた
概要
業務でInt型やDouble型を単純に2倍する関数を作りたい時に戸惑いましたのでググってみました。
/// これを型ごとに作ると、関数が増えてしまって冗長なので書きたくない func multipleValue(_ value: Int) -> Int { return value * 2 } func multipleValue(_ value: Double) -> Double { return value * 2 } func multipleValue(_ value: CGFloat) -> CGFloat { return value * 2 } multipleValue(2) // 4 multipleValue(3.14) // 6.28 }これをクールに一つの関数にまとめたいと思いました。
さてどうすればいいのかを考えるのが今回のテーマです。ジェネリクスを使う
すぐに思いつくやり方は、ジェネリスクでパラメータを一つにまとめる方法です。
ジェネリスクはSwift のドキュメントでこう記されています。
ジェネリクスの用法としては
[Swift]ジェネリクスについてが参考になります。
それはいいとして、ジェネリクスを使ってこんな風に書きたいです。
/// Tがジェネリックパラメータ func multipleValue<T>(_ value: T) -> T { return value * 2 } multipleValue(2) // 4 multipleValue(3.14) // 6.28 }これでいけるかと思ったのですがビルドエラーになってしまいました。
エラーの内容は
Binary operator '*' cannot be applied to operands of type 'T' and 'Int'どうやらジェネリクスに二項演算子「*」などのoperatorが使えないみたいなエラーでした。
そのため、てっきりジェネリクスで数値を2倍にできないのかと諦めかけましたが、
エラーの文章からググってみましたら解決策が見つかりました。Binary operator '+' cannot be applied to two 'T' operands
ということで Numeric protocol に準拠させたら使えるそうです。
/// Tがジェネリックパラメータ func multipleValue<T: Numeric>(_ value: T) -> T { return value * 2 } multipleValue(2) // 4 multipleValue(3.14) // 6.28 }これで目標のあらゆる数値を単純に2倍にする関数が作れました。
Numeric とは何なのか
乗算をサポートする値を持つ型だそうです。
Numericプロトコルを汎用制約として使用すれば、標準ライブラリ内の任意の数値型を操作する関数が作れるようになるとの事でした。
これで数値を操作する汎用メソッドが作れます。
と調べた後にこれについて詳しい資料がありましたので最後に貼って終わります。
- 投稿日:2020-01-20T02:07:13+09:00
React Native体験入学【環境構築】【標準コンポーネントの使い方】【リリースまで】
最近までNext.jsの入門してブログシステム作ってたけど、どうもwebpack周りで詰んでしまったのでもう少し実戦練習できることをやってみようと思ってReact Nativeを始めることに。あまりNext.jsに向いてないブログシステム作るより、ガッツリReact使いまくるアプリ制作でコーディングしまくりたい。
とりあえずReact Nativeの基本情報と、環境構築、ドキュメントやリファレンスの流し読み、そして簡単なアプリを作ってみようと思う。予定は簡単な「ダイス」アプリ。できればリリースするところまで経験しておきたい。
目次(暫定)
- 環境構築
- React Nativeとは(クロスプラットフォーム開発環境)
- Reactとは(UI構築のためのJSライブラリ)
- Expoとは(OSに依存しないビルド環境)
- 統合開発環境
- Xcode
- Android Studio
- 開発ツールのインストール
- Homebrew
- Node.js
- Watchman
- react-native-cli
- 動作テスト
- 仕様
- 標準コンポーンネント
- 標準API
- StyleSheet
- HTTP通信
- アニメーション
- データの保持
- 画面遷移(navigation・pagenation)
- 標準UI(React Native Elements)
- ビルド・リリース
- Google Play
- AppStore
- デバッグとアップデート
React Nativeとは
- Facebookが開発したクロスプラットフォーム開発フレームワーク
- FlutterみたいなやつのReact版
- 同じコードでWeb・iOS・Androidアプリが作れる
- OSのAPIの仕様の差をフレームワークレベルで抽象化することで共通化
- JavaScriptとReactの知識があればモバイルアプリを作れる
Reactとは
UI構築のためのJSライブラリ。コンポーネントは状態を持ったviewの単位。Reactではコンポーネントを組み合わせてUIを構築する。その辺はReact.jsの方の公式ドキュメントなどで勉強すべし。
コンポーネントライフサイクル
これはいずれ理解しないといけないややこしい部分。数が多いのでまた今度気合入れて勉強しとく。
ReactDOM.render
constructor()
getInitialState()
非推奨。constructor()推奨。componentDidMount()
componentWillUnmount()
shouldComponentUpdate()
getSnapshotBeforeUpdate()
componentDidUpdate()
componentDidCatch()
Expoとは
- OSに依存しないビルド環境
- スマホ用の開発環境アプリがある
- 同じネットワークなら無線接続でテスト可能
- 利用には会員登録が必要
Expo Snack
ブラウザ上でコードの動作をリアルタイムで確認できるツール。ReactのCodePenやCodeSandboxのようなもの。
アプリの実行方法は2つ
実機で動かすのと、シミュレータで動かすもの。
実機で動かすときは、Expo.ioからプロジェクトを開始したら表示されるQRコードを、スマホのExpoアプリで読み取れば起動する。
シミュレータで動かすときは、
expo-cli
というコマンドラインツールをPCにnpmインストールして、expo init
コマンドを実行することでExpoプロジェクトに接続可能。ただしreact-native init
コマンドとは異なることに注意。コマンドラインからでも
expo start
コマンドでQRコードから実機接続できる。また、このときにi
を入力すればシミュレータが起動する。統合開発環境
実機を持ってなくとも新旧機種を問わず動作テストできる環境を構築する。それにはXcodeとAndroid Studioといった統合開発環境をインストールすればいい。ただしiOSアプリの開発はMacOSでしかできない。以下、必要なツールをリストアップしておく。
Xcode
Android Studio
- Java(開発言語)
- JDK(Java開発キット)
- SDK(ソフトウェア開発キット)
- AVD(Android仮想デバイス)
その他
- Homebrew(パッケージマネージャ)
- Node.js(非同期のJSライブラリ)
- Watchman(ファイルシステムの監視ツール)
- react-native-cli(コマンドラインツール)
- Expo
動作テスト
公式ドキュメントを参考に一通りやってみる。
各種インストール
環境はMacOS & iOSを選択。そしてXcodeをインストールすることでHomebrewが使えるようになる。
$ brew install node $ brew install watchman $ sudo gem install cocoapods$ npx react-native init MyTestApp
このとき、
react-native-cli
をグローバルインストールしなくともnpx
コマンドを使えばreact-native init
コマンドが使える。下記コマンドはnpx
を使わない例。$ npm install -g react-native-cli $ react-native init MyTestAppシミュレータ起動して試運転
アプリをシミュレータで起動するコマンド。
$ cd MyTestApp $ npx react-native run-ios
App.js
を編集して保存したらホットリロードされる。次に公式ドキュメントのHello Worldコードを
App.js
にコピペして保存してみる。ここからは普通のReactのコーディングだと思えばわかりやすい。App.jsimport React, { Component } from 'react'; import { Text, View } from 'react-native'; // react-native標準コンポーネントのインポート export default class HelloWorldApp extends Component { render() { return ( <View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}> <Text>Hello, world!</Text> </View> ); } }ちょっとだけ自由に編集してみた。まずrootディレクトリに
public/
を作成し、profile.png
を配置。そしてApp.js
でImage
コンポーネントをインポートのところに追加し、render()
の中にpropsやstyleを与えた<Image />
を記述。ついでに<Text>
のフォントサイズのstyle追加とテキストを変更してみた。レイアウトは<View>
コンポーネントのstyleでセンタリングされて表示される。import React, { Component } from 'react'; import { Text, View, Image } from 'react-native'; export default class HelloWorldApp extends Component { render() { return ( <View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}> <Text style={{fontSize:30}}>お絵描きホーホー論</Text> <Image style={{width: 100, height: 100}} source={require('./public/profile.png')} /> </View> ); } }標準コンポーネント
React Nativeのコンポーネントの構造についてサッと頭に入れておくと知識を蓄積しやすくなるかも。下図は公式サイトのトップページにある図解。React Nativeではいくつかの標準コンポーネントを提供しており、それをツリー構造で配置することでUIを構築し、そのReactコンポーネントはネイティブなコードをラップしているため、ネイティブコードを一切触らずにJavaScriptでのアプリ開発ができる、という触れ込みが書かれている。
標準コンポーネントの種類については、公式ドキュメントのコンポーネントとAPIのリファレンスを参考。基本的な説明と、渡せるpropsの一覧が見れる。名称から用途が想像できるものもあるが、各プラットフォーム専用のコンポーネントもあるので要勉強(下記が全てではない)。
- 基本コンポーネント
- View
- Text
- Image
- TextInput
- ScrollView
- StyleSheet
- UI
- Button
- Picker
- Slider
- Switch
- List Views
- iOS Components and APIs
- Android Components and APIs
- Others
- Activity Indicator
- Alert
Viewコンポーネント
HTMLでいう
<div>
のような役割。要素を入れるコンテナとして、レイアウトを作るのに使える。return( <View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}> (中略) </View> );Textコンポーネント
テキスト表示用で、HTMLと違ってReact Nativeではこのコンポーネントを使わないとテキスト表示ができない。
return( <Text>Hello World</Text> );Imageコンポーネント
画像を表示する。画像ファイルパスは
require
でpublic/
などの静的ファイル用のディレクトリを参照するようになる。Imageコンポーネントはstyle
でサイズ指定しなけれな表示されない。基本的には位置調整のため<View>
コンポーネントに入れて配置する。return( <Image style={{width: 100, height: 100}} source={require('./assets/sample.png')} /> <Image style={{width: 100, height: 100}} source={{uri: 'https://facebook.github.io/reactnative/img/favicon.png'}} /> );