忍者ブログ
  • 2024.04
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 2024.06
[PR]
×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。

【2024/05/06 21:57 】 |
appCCloudでPUSH通知
そろそろちゃんとまとめよう。
appCCloudを使ってPUSH通知を実装する方法。

appCCloudじゃなくても共通で必要な手順もある。


◯証明書を揃える
PUSH通知用の証明書を作る(開発用、本番用両方)

1. Apple Developerに行き、Certificatesを新規作成


2. 証明書の種類を「Apple Push Notification service SSL」を選択。
開発用の場合は Sandbox , 本番用の場合は Productionにする


3. そのままContinueを押す
この画面には、証明書要求(Certificate Signing Request)の作り方が書いてある。それを作るのは次の手順で。


4. 証明書要求を作る。
Macの「キーチェーン」アプリを起動する。
上部メニューから、キーチェーンアクセス→証明書アシスタント→認証局に証明書を要求 を選択


次の画面で「ディスクに保存」を選択し、「続ける」を押す。(メールアドレスや通称は何でも良い)


すると、
CertificateSigningRequest.certSigningRequest
という名前のファイルが生成される。(次の手順で使ったらもう必要ないので、適当なところに置いておけばよい)

5. 証明書要求を送信する
Apple Developerに戻る。
この画面で、 Choose File から先ほど作ったばかりの CertificateSigningRequest を選択する。
選択したらGenerateをクリック。


6. すると、すぐに証明書が作成されるので、ダウンロードしてどこか分かりやすいところに保存しておく。
開発用なら aps_development.cer, 本番用なら aps_production.cer という名前になっている。

7. キーチェーンに登録
今ダウンロードした aps_development, aps_production.cer をダブルクリックする。
すると自動的にキーチェーンに登録される。
開発用なら「Apple Development IOS Push Service: (バンドル名)」
本番用なら「Apple Production IOS Push Service: (バンドル名)」
という名前で登録されているはず。

8. 秘密鍵を書き出す
この証明書から、秘密鍵情報を書き出す。
キーチェーンの証明書の三角をクリックすると、下に秘密鍵情報の行が表示される。
ここを右クリックして、「◯◯◯を書き出す」を選択。
分かりやすいファイル名をつけ、ファイル形式を「p12」にして書き出す。
これがPUSH通知用の秘密鍵になる。
PUSH通知サービスを使う場合、この秘密鍵の登録が必ず必要になる。


9. pemファイルに変換する
秘密鍵は作れたのでいいのだが、appCCloudを使う場合、ファイル形式をpemにする必要があるので変換する。
ターミナルを開き、以下のコマンドを実行する。
$ openssl pkcs12 -in XXX.p12 -out XXX.pem -nodes -clcerts
これで出力されたXXX.pemを使用することになる。


◯appCCloud管理画面

1.アプリ情報の登録
アプリの登録を行う。
画面はしょっちゅう変わるので、スクリーンショットは割愛。見れば分かる。
バンドルIDその他を登録。正確に。当たり前だがバンドルIDが合っていないとPUSH通知は届かない。
最下部にPUSH通知用の設定箇所がある。ここに先ほど作ったpemファイルを登録する。

また、アプリ情報を登録すると、メディアキーが作成される。これが必要になるのでコピーしておく。

2. 最新SDKダウンロード
当然のことだが、SDKを最新にしておくことは重要。
ダウンロードしておく。
ちなみにcocos2d-x用や、Unity用のSDKもあるので、そちらを使うこと。

3. PUSH通知情報登録
PUSH通知設定画面から、PUSH通知の文面、配信日時、開発用か本番用かなどを登録する。
配信は5分間隔で行われる。(即時でないのが惜しい)
ただしまだ実装の方が済んでないので、そちらが終わってからにしよう。


◯実装
1. 先ほどダウンロードしたSDKを解凍

2.プロジェクトに追加
中に入っているREADME.mdファイルを読めば書いてあるのだが、
AppCCloudPlugin.h
AppCCloudPlugin.cpp
AppCCloudPlugin.mm
libappCCloud.a
includeディレクトリ
をプロジェクトに追加する。

3. ライブラリ追加
CoreTelephony.framework
StoreKit.framework
確かこれらが必要だった気がする

4. ARC対応
前の手順で追加した AppCCloudPlugin.mm が
実はARC非対応で書かれているので、もしプロジェクト全体をARCで作っている場合は対応が必要。そうでないなら(コンパイルが通っていれば)この手順は飛ばしてよい。
プロジェクトビューからプロジェクトを選択→TARGETSからiOSのものを選択→ Build Phases を選択→AppCCloudPlugin.mmをダブルクリック→ -fno-objc-arc を追加
これで、AppCCloudPlugin.mmは非ARCとしてコンパイルされるようになる。


5. コーディング
AppController.mに必要なコードを追記する。
以下はサンプルから抜粋したもの。
APPCCLOUD_MEDIA_KEYには、appCCloudの管理画面で手に入れたメディアキーを入れておくこと。


#define APPCCLOUD_MEDIA_KEY @""

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// プッシュ通知経由の起動数を取得する場合は、引数にlaunchOptionsをセットしてください
[appCCloud setupAppCWithMediaKey:APPCCLOUD_MEDIA_KEY
option:APPC_CLOUD_AD | APPC_CLOUD_PUSH
launchOptions:launchOptions];

return YES;
}

- (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *) devToken
{
NSLog(@"success token:%@", devToken);
[appCCloud pushNotificationDidRegisterWithDeviceToken:devToken];
}

- (void)application:(UIApplication *)app didFailToRegisterForRemoteNotificationsWithError:(NSError *) err
{
NSLog(@"failure %@", err);
[appCCloud pushNotificationDidFailWithError:err];
}

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
[appCCloud pushNotificationDidReceive:userInfo appStat:application.applicationState];
}




6. 実機で起動する
実機で起動する。シミュレータではできない。
うまく行けば、「(アプリ名)はPUSH通知を使用します。よろしいですか?」というアラートビューが出る。


ここまでできれば、再度appCCloud管理画面に戻り、PUSH通知設定を行う。
5分待って通知がくれば成功!


◯本番については
本番用については、本番用のアプリを起動した端末があればいい。
PUSH通知設定で本番向けに設定すれば、PUSH通知は飛んでくる。AppStoreに置かれるのを待つことは無い。
appCCloudに登録した証明書の間違いが無いかの確認のため、AppStoreに置かれる前に一度確認しておこう。(もし間違っていても、別にappleへ再サブミットするとかではないので、慌てることは無い。「◯証明書を揃える」の手順を見直せばいいだけだ)

PR
【2015/04/15 23:31 】 | iPhone | 有り難いご意見(0)
[iOS]システム音を鳴らす
シャッター音とか、着信音とかを鳴らす方法。

AudioToolBoxライブラリを追加。


#import <AudioToolbox/AudioServices.h>

AudioServicesPlaySystemSound(1108); //シャッター音





プログラムの参考
鳴らせる音の一覧

ちなみにバイブも鳴らせる

AudioServicesPlayAlertSound(kSystemSoundID_Vibrate);



【2015/04/10 15:05 】 | iPhone | 有り難いご意見(0)
画像の切り取り(iOS)
iOSで、画像(UIImage)を切り取る方法。


参考

そのまま持ってきたもの

UIImage* clipImage(UIImage* image, CGRect rect) {

// イメージの解像度に従いrectも換算
float scale = image.scale;
CGRect cliprect = CGRectMake(rect.origin.x * scale, rect.origin.y * scale,
rect.size.width * scale, rect.size.height * scale);

// ソース画像からCGImageRefを取り出す
CGImageRef srcImgRef = [image CGImage];

// 指定された範囲を切り抜いたCGImageRefを生成しUIImageとする
CGImageRef imgRef = CGImageCreateWithImageInRect(srcImgRef, cliprect);
UIImage* resultImage = [UIImage imageWithCGImage:imgRef scale:scale orientation:image.imageOrientation];

// 後片付け
CGImageRelease(imgRef);

return resultImage;
}




実に簡単。
画像の解像度も考慮してくれているので、
元の(scaleしない)イメージサイズを基準にして、切り取りたい範囲のRectを第2引数に渡せば良い。
Rectは左上が原点。

【2015/04/05 10:56 】 | iPhone | 有り難いご意見(0)
iOSの新testflightを使う
testflightが使えなくなり、iTunesConnectから使用するように変わった。

使い方のイメージとしては、「サブミット前の確認」。


まず、iTunesConnectに行き、最新のAppleの条件をAgreeする必要がある。
これをしなくても先のページに進めるが、アプリを登録するボタン(ヘッダの「+」ボタン)を押しても何も出ない、という妙なところで止められてしまう(不具合に見える。こんなところでも分からないと詰まってしまうようなところ)


Agreeしたら、iTunesConnectにアプリを登録する。


DeveloperCenterでDistribution用のProvisioning Profileを作っておく。
このとき、AdHoc用ではなく、Distribution用を作ることに注意。
AdHoc用でもこの先の手順でサブミットできるし、testflightで配布もできるのだが、testflightからインストールできるのが、Provisioning Profileに登録されているデバイスだけに限定されてしまうので不便なだけ。


で、Distribution用のProvisioning ProfileでアプリをXcodeでアーカイブする。
できたらSubmit。


少し待つと、iTunesConnectにアプリが載る。


ここで「プレリリース」をクリック。
内部テスターの欄に、testflightで配布したいメンバーのappleIDを登録する。
(開発メンバーは基本的に内部テスター。外部テスターというのもあるが、これは実際の顧客など外部の人に使ってもらうことを想定しており、外部テスターに配布するためにはAppleの審査を通した後配布するという手順を踏むことになるようだ)


で、「TestFlightベータ版テスト」のスイッチをONにし、
招待メールを送信。


これで、内部テスターのappleIDのアドレスにメールが届く。
iPhone、iPadなどでそのメールのリンクを踏むと、testflightのアプリに飛び、件のアプリがインストールできるページになる。
晴れてインストールできるというわけ。


たまにメールが飛ばないことがあるので、「TestFlightベータ版テスト」をOFF→ONにしたらメールが行ったということがあった。


また、上げ直す際は必ずビルド番号を上げておくこと。
あくまでサブミットへの手順の一部なので、ビルド番号をあげておかないと、XcodeからiTunesConnectへのアップロードができない。
再度アーカイブし直しという面倒なことになるので注意。

バージョンはあげなくていい。
というか、上げるとストアの情報など再設定が必要になったりtestflight的にも新しいもの扱いに鳴って再度招待メールを飛ばす必要があったりと面倒。

本当にアプリとしてバージョンをあげるときだけにとどめよう。

【2015/03/25 17:17 】 | iPhone | 有り難いご意見(0)
iOSでYouTube動画再生
iOSでYouTubeの動画を再生するときの方法。

画面でボタンをクリック→全画面で動画再生→完了ボタンを押したら元の画面に戻る
という流れにしたい。


WebViewを使うのが早い、という記事が多いが、WebViewだと完了ボタンを押したときに画面を閉じるということができない。
WebViewはhtmlを表示しているだけなので、動画コンテンツを再生しているかどうかは感知できない。だから完了ボタンを押したときに、明示的にWebViewを閉じる命令を出す必要があるが、そもそも完了ボタンを押したことを知ることができない。


そこで、MPMoviePlayerViewControllerを使う。
モーダルビューコントローラを表示し、そこで動画(URLで指定)を再生できる。完了したらモーダルは閉じる。これだ!

ただし注意。YouTubeのURLそのままだとiOSで再生できない。
再生可能な形式のURLを取得してくる非公式ライブラリがあるのでそれを使う
HCYoutubeParser

以下のようになる。


NSDictionary *dict = [HCYoutubeParser h264videosWithYoutubeID:@"youtubeID"];
NSURL *url = [NSURL URLWithString:dict[@"medium"]];

MPMoviePlayerViewController *vc = [[MPMoviePlayerViewController alloc] initWithContentURL:url];
[self presentViewController:vc animated:YES completion:nil];




その他、WebViewでいい場合は
参考

【2015/03/03 16:28 】 | iPhone | 有り難いご意見(0)
ローカル通知が多重に来る
applicationDidEnterBackgroundの中とかでローカル通知のスケジューリングを行う。
アプリを起動したときにスケジュール済みの通知を全削除したりするが、そのタイミングは
applicationWillEnterForeground
ではいけない。

必ず通るとは限らないからである。

起動
→バックグラウンドへ(ここで通知スケジューリング)
→他のアプリを起動するなどしているうちに、アプリが自然にシャットダウンする
→アプリを起動
→バックグラウンドへ(ここで通知が2重にスケジューリングされる!)

というわけで、通知を全削除する( [[UIApplication sharedApplication] cancelAllLocalNotifications];
)箇所は、

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions;
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation;
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url;
- (void)applicationWillEnterForeground:(UIApplication *)application;
の4つ…とかはめんどいので、

applicationDidEnterBackground
でスケジューリング登録する直前に全削除、が一番楽であろう。
【2015/02/26 18:14 】 | iPhone | 有り難いご意見(0)
adcrops導入
adcropsを導入したときの話。
かなり変な癖があって行儀が悪いSDKだったので、今後のために書いておく。

公式

今回実装した広告は、全部ウォール型。正しい名前は確認していないが
・リストウォール
・バナーウォール
・スロットウォール


◯広告設定
ID的なものは2つ。
サイトIDとサイトキー。
1つのアプリに複数種類の広告を置いても、このIDは増えない。
どの種類の広告もこの2つのIDを用いて表示する。

ここが他の広告媒体と違うので注意。
1つで何でも表示できるので便利…といえないこともない。
でも表示箇所ごとに広告を管理(フィルタリングなど)することができないのでどうなんだ。


◯SDKインストール
まずはSDKをインストールする。
header,resourceをまるっとプロジェクトに追加


リンカオプションに
-ObjC
を追加する。


なぜこのオプションが必要か。

このSDKは、categoryファイルを含んでいる。

そもそもUNIXでC/C++をビルドしたとき、
オブジェクトファイル(ソースファイルから作られるバイナリファイル)内に見つからないシンボルがあるとき、リンカがそれを解決する。つまり、そのシンボル(メソッド)を含む別のオブジェクトファイルをインクルードする。

だが、ObjCのstatic library の categoryはそうならない。
未定義シンボルは未定義のままで、実行時に"selector not recognized"例外が発生してしまう。

そこで-ObjCオプションを付けると、すべてのcategoryのメソッドが実行可能ファイルに含まれるようになる。
ただし、不要なメソッドも含んでしまうので、実行可能ファイルが膨大になることがある。(だからデフォルトオプションになっていない)
また、コード中にC/C++で書かれている部分がコンパイルエラーになることがある。

特にcocos2dのライブラリ内でよく起きるのだが、
その場合は、そのファイル全体をコメントアウトしてしまうのが早い。
(大抵ムービーとかゲームコントローラとかあんまり使わないところでしか起きないからだ)


公式のQ&A


◯サンプル
さて、この状態ではまだ広告は出ない。
adcropsのSDKはかなり基本的なところしか対応していなくて、
ウォールを表示しようとしたら自分でテーブルビューとか作らないといけない。

これを自分でやるとなると不親切極まりないと憤慨するところだが、
サンプルコードがいろいろ付いている。


サンプルコードをみると、SDKの他に
Chk***.h/m/mm
というファイルがたくさん入っている。
これらがテーブルビューとかを用意している。いわばヘルパークラスで、アプリ側とSDKを繋ぐ位置にいる。


これらのヘルパーファイルをコピーして、自分のプロジェクトに追加する。

で、アプリ側からはこれらのヘルパーを呼び出す形にする。
複数の広告種類を出すなら、それぞれのサンプルからヘルパーをコピーしてくる。


これで動くようになる。
初めからこのヘルパーもSDKに入れておけ、というところだ。


【2015/01/07 16:48 】 | iPhone | 有り難いご意見(0)
Xcodeでメモリ周りのデバッグ
Xcodeでデバッグする便利機能いくつか

【メモリのアクセス違反を検知】
Guard Malloc という機能を使う。
これはXcodeにデフォルトで入っている。
使い方は以下のとおり。スキームの設定をする。



参考

その他の機能の説明
Enable Scribble. Fill allocated memory with 0xAA and deallocated memory with 0x55.
Enable Guard Edges. Add guard pages before and after large allocations.
Enable Guard Malloc. Use libgmalloc to catch common memory problems such as buffer overruns and use-after-free.
引用元

zombie objectとは、解放されたメモリをNSZombieObjectにリプレースする機能。
解放済みメモリにアクセス違反したとき、どこにアクセスしたのかなどの情報が分かりやすくなる。
NSZombieObjectの説明


さらにいろんな便利機能
参考
うう〜ん、べんり!


なお、注意点として、Guard Mallocを有効にした状態で実機実行はできない。
以下のエラーが出る。

dyld: could not load inserted library '/usr/lib/libgmalloc.dylib' because image not found


面倒だが、シミュレータのときと実機のときで、スキームから設定を変更しよう。
参考
【2014/12/08 10:45 】 | iPhone | 有り難いご意見(0)
iOS通知のカスタムアクション実装
公式ドキュメント

を参照。
26ページから(特に28ページ冒頭)を要チェック。

引用----------

リスト 2-7 通知アクションを定義するコード例
UIMutableUserNotificationAction *acceptAction =
[[UIMutableUserNotificationAction alloc] init];
// Define an ID string to be passed back to your app when you handle the action
acceptAction.identifier = @"ACCEPT_IDENTIFIER";
// Localized string displayed in the action button
acceptAction.title = @"Accept";
// If you need to show UI, choose foreground
acceptAction.activationMode = UIUserNotificationActivationModeBackground;
// Destructive actions display in red
acceptAction.destructive = NO;
// Set whether the action requires the user to authenticate
acceptAction.authenticationRequired = NO;



リスト 2-8 アクションをカテゴリにまとめるコード例

// First create the category
UIMutableUserNotificationCategory *inviteCategory = [[UIMutableUserNotificationCategory alloc] init];
// Identifier to include in your push payload and local notification
inviteCategory.identifier = @"INVITE_CATEGORY";
// Add the actions to the category and set the action context
[inviteCategory setActions:@[acceptAction, maybeAction, declineAction] forContext:UIUserNotificationActionContextDefault];
// Set the actions to present in a minimal context
[inviteCategory setActions:@[acceptAction, declineAction]
forContext:UIUserNotificationActionContextMinimal];




リスト 2-9 通知カテゴリを登録するコード例

NSSet *categories = [NSSet setWithObjects:inviteCategory, alarmCategory, ...
UIUserNotificationSettings *settings =
[UIUserNotificationSettings settingsForTypes:types categories:categories];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];



リスト 2-11 ローカル通知に用いるアクションのカテゴリを定義するコード例

UILocalNotification *notification = [[UILocalNotification alloc] init];
...
notification.category = @"INVITE_CATEGORY";
[[UIApplication sharedApplication] scheduleLocalNotification:notification];




引用ここまで-------------


つまり

まずアクションを作成する。
UIUserNotificationActionクラス

identifier
title
activationMode
authenticationRequired
destructive

などの設定をする。
通知において、ひとつのボタンの操作に対応。


次に、アクションをまとめてカテゴリーを作る。
UIMutableUserNotificationCategory

カテゴリーはアクションの配列を格納し、識別子を持つ。
ひとつの通知におけるビューがこれで作られる。
カテゴリーは別に1アプリ1つではない。通知の種類によっていくらでもカテゴリーは作れる。
ただし、コンテキストによって2種類の配列を登録する必要がある。
UIUserNotificationActionContextDefault …これはモーダルビューで見た時
UIUserNotificationActionContextMinimal …これはロック画面で見た時。こちらは最大2つしかアクションを持てない



さらに、カテゴリーをセッティングにまとめる。
UIUserNotificationSettings
セッティングは、通知種別(アラート、バッジ、サウンドなど)を持つ


そして、このセッティングをアプリケーションに登録する。
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];

これにて通知が仕えるようになる。



実際に使うためには、通知をスケジューリング登録する。

UILocalNotification *notification = [[UILocalNotification alloc] init];
...
notification.category = @"INVITE_CATEGORY";
[[UIApplication sharedApplication] scheduleLocalNotification:notification];


【2014/12/05 18:25 】 | iPhone | 有り難いご意見(0)
コードから制約を生成する
今やiOSでは当たり前となったAutoLayout。
制約(NSLayoutConstraint)を適切に指定することで、レイアウトを指定することができ、画面サイズの違う端末でも意図通りに表示できるようになる。


AutoLayoutによる位置・サイズの決定は、viewWillAppearとviewDidAppearの間で行われる。



【画面初期化の流れ】

viewDidLoad実行
   ↓
viewWillAppear実行
   ↓
AutoLayout実行(内部)
   ↓
ビューのlayoutSubviews実行
   ↓
viewDidLayoutSubviews実行(もう一度呼ばれる)
   ↓
画面が構成される(内部)
   ↓
画面遷移開始(ここからユーザの眼に触れる)
   ↓
画面遷移終了
   ↓
viewDidAppear実行



間違って(あるいは面倒くさがって)ビューコントローラ上のコードで画面レイアウトを作ろうとして、画面表示前(viewDidLoadなど)でビューのframeを直接いじっても、
その後にAutoLayout制約が適用されて上書きされてしまう。
(じゃあviewDidAppearの後にframeをいじろう、と考えたくなるところだが、それだとちょっと間に合わない。画面遷移をしながら表示するビューの場合、frameをいじる前のビューが画面に映ってしまう(=手遅れ)なのだ。


だから、レイアウトを処理・変更する必要があるビューは、必ずカスタム定義をして
layoutSubviews
メソッドを実装しておく必要がある。
このメソッドは、viewWillAppearの後に呼ばれる。
また、画面を再構成する必要があると自動的に判断されたときにも呼ばれるし、明示的に呼びたい場合は、ビューコントローラで
[view setNeedsLayout];
を実行すればよい。




じゃあどうするか。
制約適用直後に画面が映ってしまうのはさけられない。
ということはつまり、制約適用時に求める画面が構成されるようにしておけばいい。


だから、、、

【制約を動的に作成する】

ということになる。


つまり、AutoLayoutを使うようになった時点で、画面構成はすべて制約で作るようにするべきなのだ。
frameとかboundsとかを直接いじることはなくなってくるはずだ(少なくとも、定数値を代入するようなことはないはずだ。せっかくAutoLayoutを指定していても台無しになる)。


さて、そうすると、どうやってコード上で制約を記述するのか、ということを覚えなければならない。ストーリーボードではいつも作ってるけど、コーディングはどうやって…?


公式のAutoLayoutマニュアル


制約クラスは
NSLayoutConstraint

制約のインスタンスを作るメソッドは2種類ある

1.constraintsWithVisualFormat: options: metrics: views:



VisualFormat
VisualFormatとは、制約を人間に見やすく記述できるDSL。
これを使用して、ビューのサイズや位置を指定する。storyboardとほぼ同じことができる

公式のVisual Format Language仕様

いくつか例示する。
なお、view1,view2などは、制約を作りたいビューのメンバ変数名(詳細は後述)

view1の横幅を10にする
H:[view1(==10)]

view1の高さを20以上にする
V:[view1(>=20)]

view1の高さを20以上100以下にする
V:[view1(>=20,<=100)]

view1とview2の幅を同じにする
H:[view1(==view2)]

※比較演算子は、==,>=,<= の3つしか使えない
※カッコで囲わないと、パーサーがビュー名の区切りを判断できない。
※HもVも書かないときはH(水平方向)になる

view1とview2を12px空けて横に並べる
H:[view1]-12-[view2]

view1とview2をデフォルトの間隔を空けて縦に並べる
V:[view1]-[view2]

view1とview2を間隔無しで並べる
H:[view1][view2]

superviewとの間隔を指定する。パイプ(|)がsuperviewを表す
H:|-50-[view1]-50-|


options
指定できる内容は以下
NSLayoutFormatAlignAllLeft
NSLayoutFormatAlignAllRight
NSLayoutFormatAlignAllTop
NSLayoutFormatAlignAllBottom
NSLayoutFormatAlignAllLeading
NSLayoutFormatAlignAllTrailing
NSLayoutFormatAlignAllCenterX
NSLayoutFormatAlignAllCenterY
NSLayoutFormatAlignAllBaseline
NSLayoutFormatAlignAllLastBaseline
NSLayoutFormatAlignAllFirstBaseline

NSLayoutFormatDirectionLeadingToTrailing
NSLayoutFormatDirectionLeftToRight
NSLayoutFormatDirectionRightToLeft

何もいらなければ0を指定。


metrics
調べてない

views
VisualFormat内に登場したビュー名と、ビューへの参照を格納したNSDictionary。
上記の例だと、
NSDictionary viewsDictionary = [[NSDictionary alloc]initWithObjects:@[view1,view2] forKeys:@[@"view1",@"view2"]];
のような感じ。
ちなみにこれと同じことが
NSDictionaryOfVariableBindings(view1, view2);
と書くことができる。


戻り値
記述した制約をすべて満たせるNSLayoutConstraintの配列が返ってくる。


最終的なコード例
view1の横幅を40にし、view2を水平に12px空けて並べ、それぞれsuperviewと左右端を合わせる。(制約が4つ作られる)

NSDictionary viewsDictionary = NSDictionaryOfVariableBindings(view1, view2);
[self.view addConstraints: [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[view1(==40)]-12-[view2]|" options:0 metrics:nil views:viewsDictionary]];






例外を捕まえる
VisualFormatは実行時にパースされるので、書き間違えていると例外が飛んでくる。
ちゃんとキャッチしてチェックしよう。


@try{
NSDictionary viewsDictionary = NSDictionaryOfVariableBindings(view1);
[self.view addConstraints: [NSLayoutConstraint constraintsWithVisualFormat:@"V:[view1==%d)]" options:0 metrics:nil views:viewsDictionary]];
}@catch(id exception) {
NSLog(@"%@", [exception description]);
}

Unable to parse constraint format:
Expected a ']' here. That is how you give the end of a view.
V:|[view1==123)]|
^
こんな感じで出力される







2.constraintWithItem:attribute:relatedBy:toItem:attribute:multiplier:constant:

item
制約を付けるビュー。

attribute
以下のものがある。
実態は前のメソッドのoptionに指定するNSLayoutFormat***と同じ。
NSLayoutAttributeLeft = 1,
NSLayoutAttributeRight,
NSLayoutAttributeTop,
NSLayoutAttributeBottom,
NSLayoutAttributeLeading,
NSLayoutAttributeTrailing,
NSLayoutAttributeWidth,
NSLayoutAttributeHeight,
NSLayoutAttributeCenterX,
NSLayoutAttributeCenterY,
NSLayoutAttributeBaseline,
NSLayoutAttributeLastBaseline = NSLayoutAttributeBaseline,
NSLayoutAttributeFirstBaseline NS_ENUM_AVAILABLE_IOS(8_0),

NSLayoutAttributeLeftMargin NS_ENUM_AVAILABLE_IOS(8_0),
NSLayoutAttributeRightMargin NS_ENUM_AVAILABLE_IOS(8_0),
NSLayoutAttributeTopMargin NS_ENUM_AVAILABLE_IOS(8_0),
NSLayoutAttributeBottomMargin NS_ENUM_AVAILABLE_IOS(8_0),
NSLayoutAttributeLeadingMargin NS_ENUM_AVAILABLE_IOS(8_0),
NSLayoutAttributeTrailingMargin NS_ENUM_AVAILABLE_IOS(8_0),
NSLayoutAttributeCenterXWithinMargins NS_ENUM_AVAILABLE_IOS(8_0),
NSLayoutAttributeCenterYWithinMargins NS_ENUM_AVAILABLE_IOS(8_0),

relatedBy
比較演算子。以下の3つ
NSLayoutRelationLessThanOrEqual = -1,
NSLayoutRelationEqual = 0,
NSLayoutRelationGreaterThanOrEqual = 1,


toItem
対象となるビューを指定する。
align系なら、どのビューからの距離か、を指定するときに使う。
size系なら、あのビューのサイズの○倍、というような指定の時に使う。
不要ならnilを指定。

attribute
toItem側のattribute。
itemのtopとtoItemのtopが○○px離れてる、というような制約のときに使用。
なければ0。

multiplier
係数。計算式に使う。後述

constant
定数。計算式に使う。後述


コード例
view1の高さを123にする場合。

[self.view addConstraint:
[NSLayoutConstraint constraintWithItem:self.view1 attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil attribute:0
multiplier:1.f constant:123]
];



view1の上端をview2の上端から25px以上空ける制約

[self.view addConstraint:
[NSLayoutConstraint constraintWithItem:self.view1 attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationGreaterThanOrEqual
toItem:self.view2 attribute:NSLayoutAttributeTop
multiplier:1.f constant:25]
];



view1の幅をview2の高さの2倍より10大きいサイズにする制約

[self.view addConstraint:
[NSLayoutConstraint constraintWithItem:self.view1 attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:self.view2 attribute:NSLayoutAttributeHeight
multiplier:2.f constant:10]
];




【2014/12/05 14:01 】 | iPhone | 有り難いご意見(0)
<<前ページ | ホーム | 次ページ>>