2012年2月アーカイブ

こんにちは。 開発担当のICTFです。

iPhone用多機能ボイスレコーダーアプリ「Relational VoiceRecorder」バージョン2.0相当の機能すべてを無料で利用できる
「Relational VoiceRecorder Lite」が登場しました!

録音時間に制限がついていますが一口メモ程度であれば十分利用可能であると思います。
まずはLite版でRelational VoiceRecorderの便利さをご体験ください!

AppleStore:
http://itunes.apple.com/jp/app/relationalvoicerecorder-lite/id504165683?mt=8

公式サイト:
http://ict-fractal.com/ICTF0008/index.html
こんにちは。開発担当のICTFです。

coco2dでゲーム画面を作成しています。
ゲーム機能の1つとして写真を撮影する必要があり、RootViewControllerを親としてUIImagePickerControllerをModal表示していたのですが、困った現象が起こりました。
撮影画面を表示中に画面を回転させると、撮影画面自体は正常に動作するのですが、裏のcocos2dレイヤーが縦横比が狂った状態で固まってしまうのです。
ログビューにもOpenGLの描画失敗関連のエラーが大量に発生します。
画面全体が1枚の絵のようになってしまい、もちろん貼付けているボタンなども反応しません。
UIImagePickerControllerをModalではなく、AddSubviewした場合はcocos2dレイヤーに問題が発生しませんので、予想ですが恐らく撮影画面をModal表示する事でcocos2d側に画面回転の通知が届かなくなり、結果として「画面横のつもりで描画してみた⇒実は画面縦だった⇒エラー」という流れになっているのではないでしょうか。

上でAddSubviewだと問題無しという表現をしましたが、実はAddSubviewした場合撮影画面の動作がおかしくなってしまいます。
撮影画面を開いた状態で画面を回転させると、iPhoneに表示されている風景画像までもが回転してしまうのです。ですので、やはり撮影画面はModal表示する事が前提に作られているようです。

最終的に撮影画面を表示中は、cocos2d側の画面回転を禁止すれば良いという結論に至り、RootViewControllerに画面回転を抑制する為の機能を盛り込みました。
ついでに単純に画面回転を禁止するだけではなく、動的に「縦のみ」「横のみ」「全方向
」を切換えられるようにもしました。
どちらかというと画面回転抑制機能の実装が今回の主題に近いかもしれません。

RootViewController.hに画面の方向を指す以下の定数を列挙します。

typedef enum {

eOrientationMode_INVALID,

eOrientationMode_Full,

eOrientationMode_Portrait,

eOrientationMode_Landscape,

eOrientationMode_COUNT

} eOrientationMode;


INVALIDとCOUNTは単に私の癖ですので、無くても構いません。
次に、クラスの定義を以下のようにします。

@interface RootViewController : UIViewController

<

UIImagePickerControllerDelegate

, UINavigationControllerDelegate

>

{

BOOL m_isOrientationLock;

eOrientationMode m_OrientationMode;

}


@property (nonatomic, readwrite) BOOL isOrientationLock;

@property (nonatomic, readwrite) eOrientationMode OrientationMode;


isOrientationLockは画面方向のロック状態を表します。
このフラグがYESの場合、どのような状況でも画面回転を許可しません。
OrientationModeは上で定義した列挙子を用います。
Fullは、どの画面方向も許可します。
Landscapeは、画面が横の場合のみ許可します。
Portraitは、画面が縦の場合のみ許可します。

最後にRootViewController.mに画面回転制御の実処理を組み込みます。

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {

//

// There are 2 ways to support auto-rotation:

//  - The OpenGL / cocos2d way

//     - Faster, but doesn't rotate the UIKit objects

//  - The ViewController way

//    - A bit slower, but the UiKit objects are placed in the right place

//

#if GAME_AUTOROTATION==kGameAutorotationNone

//

// EAGLView won't be autorotated.

// Since this method should return YES in at least 1 orientation, 

// we return YES only in the Portrait orientation

//

return ( interfaceOrientation == UIInterfaceOrientationPortrait );

#elif GAME_AUTOROTATION==kGameAutorotationCCDirector

//

// EAGLView will be rotated by cocos2d

//

// Sample: Autorotate only in landscape mode

//

if( interfaceOrientation == UIInterfaceOrientationLandscapeLeft ) {

[[CCDirector sharedDirector] setDeviceOrientation: kCCDeviceOrientationLandscapeRight];

} else if( interfaceOrientation == UIInterfaceOrientationLandscapeRight) {

[[CCDirector sharedDirector] setDeviceOrientation: kCCDeviceOrientationLandscapeLeft];

}

// Since this method should return YES in at least 1 orientation, 

// we return YES only in the Portrait orientation

return ( interfaceOrientation == UIInterfaceOrientationPortrait );

#elif GAME_AUTOROTATION == kGameAutorotationUIViewController

//

// EAGLView will be rotated by the UIViewController

//

// Sample: Autorotate only in landscpe mode

//

// return YES for the supported orientations

if (m_isOrientationLock) {

return NO;

}

switch (m_OrientationMode) {

case eOrientationMode_INVALID:

return NO;

break;

case eOrientationMode_Full:

return YES;

break;

case eOrientationMode_Portrait:

return ( UIInterfaceOrientationIsPortrait(interfaceOrientation) );

break;

case eOrientationMode_Landscape:

return ( UIInterfaceOrientationIsLandscape( interfaceOrientation ) );

break;

default:

return NO;

break;

}

#else

#error Unknown value in GAME_AUTOROTATION

#endif // GAME_AUTOROTATION

// Shold not happen

return NO;

}


使い方は、UIImagePickerCoontrollerをModal表示する前にRootViewController.isOrientationLockにYESを設定し、撮影画面が消え次第NOに戻すだけです。
こんにちは。開発担当のICTFです。

iPhone用ボイスレコーダーアプリ
 「Relational VoiceRecorder」
をリリースしました!

AppStore:
http://itunes.apple.com/jp/app/relationalvoicerecorder/id500641907?mt=8

公式サイト:
http://ict-fractal.com/ICTF0008/index.html

録音した場所を音声と一緒に記録するので、記憶をたどるのに役立ちます!
他のボイスレコーダーには無い様々な機能が盛り込んでありますので、是非一度公式サイトをご覧下さい。

写真 12-02-09 9 13 58.png

こんにちは。開発担当のICTFです。

今回はカスタマイズしたUITableViewCell(サンプルとしてUISwitchを加えたもの)をUITableViewに追加した場合の、セル上にあるスイッチが切り替わった事をTableView側で感知する方法をご紹介しようと思います。

まずこのようなカスタマイズUITableViewCellを作ります。
0001.png
カスタマイズしたUITableViewクラスの名称は、「SwitchCell」とします。
SwitchCellクラスのヘッダファイルは次のようになります。

@protocol SwitchCellDelegate


// スイッチの切換えを通知する

-(void) tableView:(UITableView*)tableView changeSwitchValue:(BOOL)on indexPath:(NSIndexPath*)indexPath;


@end


@interface SwitchCell : UITableViewCell

{

id _delegate;

}


@property (nonatomic, assign) id<SwitchCellDelegate> Delegate;


@property (nonatomic, retain) IBOutlet UISwitch* ValueSwitch;

@property (nonatomic, retain) IBOutlet UILabel* Title;


// スイッチの値が変更されたときのコールバック

-(IBAction) changeSwithValue:(id)sender;


@end


InterfaceBuilderでセルの設計を行なった場合、セル上に配置した各オブジェクトをプロパティに関連づけてください。
例ではUISwitchをValueSwitchに関連づけました。

次に、スイッチを切換えた時にコールするデリゲートメソッドをプロトコルとして実装します。
プロトコル名は「SwitchCellDelegate」、デリゲートメソッドは「-(void) tableView: changeSwitchValue: IndexPath」としました。
デリゲートとしてコールする事になりますので、SwitchCellクラスにデリゲートを保持する為の変数を追加する必要があります。
メンバ変数に_delegate、_delegateに関連づけるプロパティを追加しています。

実際にスイッチが切換えられた時にコールされるメソッドが「-(IBAction) changeSwitchValue:」です。
changeSwitchValueの実装は次のようになります。

// スイッチの値が変更されたときのコールバック

-(IBAction) changeSwithValue:(id)sender

{

// スーパークラスをたどり、このセルを保持するテーブルビューを探す

id tableView = [sender superview];

while ([tableView isKindOfClass:[UITableView class]] == NO) {

tableView = [tableView superview];

}

// NSIndexPathを得る

NSIndexPath* indexPath = [((UITableView*)tableView) indexPathForCell:self];

// デリゲートメソッドをコールする

[_delegate tableView:tableView changeSwitchValue:self.ValueSwitch.on indexPath:indexPath];

}


引数に自身が配置されているUITableViewと、自身を指すNSIndexPathを設定する必要があります。
UITableViewは自身の親となるビュークラスを辿ってゆき、UITableViewを見つけています。
見つけたUITableViewのindexPathForCellメソッドを用い、自身のNSIndexPathを取得します。
後はデリゲートメソッドをコールすれば、SwitchCellとしての役割は終了です。

次にSwitchCellを表示するUITableViewを保持するクラスに対し、修正を加えます。
例ではUITableViewControllerを継承した「SCR_MNU_005_SettingIndex」というクラスで紹介します。
先ほど作成したSwitchCellDelegateを採用します。

@interface SCR_MNU_005_SettingIndex : UITableViewController

<SwitchCellDelegate>

{

...

}


デリゲートとしてSCR_MNU_005_SettingIndexを登録する必要がありますので、SwitchCellを生成する箇所(恐らく- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath内になると思います)に以下の処理を追加します。

cell.Delegate = self;


最後に実際に受け取るデリゲートメソッドの実装を行ないます。

-(void) tableView:(UITableView *)tableView changeSwitchValue:(BOOL)on indexPath:(NSIndexPath *)indexPath

{

CategoryInfo* category = [_categoryList objectAtIndex:indexPath.section];

CellInfo* cellInfo = [category.CellList objectAtIndex:indexPath.row];

NSLog(@"ログ表示: [%@]", on?@"ON":@"OFF");

}


CategoryInfoとCellInfoクラスについて詳しい紹介は省きますが、データソースを管理するクラスです。
indexPathから該当するデータソースを抽出し、通常のコールバックメソッド同様、様々な処理を行なう事が可能です。

同じ作り方でUIButtonやUISliderのイベントを感知する事ができますので、応用してみて下さい。