2012年10月アーカイブ

Perfect listener -Voice player-|1秒単位で再生位置を調整可能な音声プレイヤー。デザインと機能性を高いレベルで融合させた良アプリがここに誕生!!


AppLife様サイトにて弊社Perfect listener -Voice player-を紹介して頂きました!
かなり詳細に解説して頂いているので、是非一度ご覧下さい。
レビュワーのOrange様、どうも有り難うございます。

5分までの再生という制限付きではありますが、現在無料版のPerfect listener Liteを申請中です。
もう暫くでリリースされると思いますので、もう暫くお待ち下さい。
こんにちは。開発担当のICTFです。

以前「iAdが表示されない間自社広告を表示する」方法についてご紹介しましたが、今回はnend広告についても自社広告を表示できるようにしてみようと思います。
※nendSDKの使い方について解説はしません。

仕様は前回と同じく、通常のNADViewクラスと同様の使い方ができるものを目指します。
NADView独特の特徴ですが、iAdの時のように広告ビューのサブクラス内で自社広告画像をaddSubViewすると言った方法を取った場合、nand広告が切り替わるタイミングで自社広告がremoveされてしまいます。
一度広告が表示されても電波状況などで受信失敗→自社広告を表示したいというケースが考えられますので、前回の方法は取れません。
解決策としてUIViewをNADViewと自社広告Viewのコンテナとして用意し、その上で両者の表示を切換えようと思います。

以下実装です。
【NADViewEx】
#import "NADView.h"


@interface NADViewEx : UIView

<NADViewDelegate>

{

NADView* _nadView;

UIImageView* _ictfAdView;

}


-(id)initWithFrame:(CGRect)frame rootViewController:(UIViewController*)rootViewController;


@end


【NADViewEx.m】

@interface NADViewEx ()


// 自社広告のタップイベント

-(void) adIctfAdTapHandle:(UITapGestureRecognizer*)sender;


@end


@implementation NADViewEx


- (id)initWithFrame:(CGRect)frame rootViewController:(UIViewController*)rootViewController

{

    self = [super initWithFrame:frame];

    if (self) {

// NADView

_nadView = [[NADView alloc] initWithFrame:frame];

[_nadView setNendID:NAD_KEY spotID:NAD_ID];

[_nadView setBackgroundColor:[UIColor clearColor]];

[_nadView setRootViewController:rootViewController];

[_nadView setDelegate:self];

[_nadView load:nil];

[self addSubview:_nadView];

// 自社広告を追加

_ictfAdView = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:@"ICTF_Ad320.png"]] autorelease];

[self addSubview:_ictfAdView];

_ictfAdView.center = CGPointMake(self.bounds.size.width * 0.5, self.bounds.size.height * 0.5);

_ictfAdView.userInteractionEnabled = YES;

// 自社広告のタップイベント

UITapGestureRecognizer* tapGesture =  [[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(adIctfAdTapHandle:)] autorelease];

tapGesture.numberOfTapsRequired = 1;

[_ictfAdView addGestureRecognizer:tapGesture];

    }

    return self;

}


-(void) dealloc

{

_nadView.delegate = nil;

[_nadView release];

[super dealloc];

}


// Adの初回読み込み完了

-(void) nadViewDidFinishLoad:(NADView *)adView

{

NSLog(@"Ad初回読み込み成功");

}


// Adの読み込み完了通知

-(void) nadViewDidReceiveAd:(NADView *)adView

{

NSLog(@"Ad読み込み成功");

_ictfAdView.hidden = YES;

_nadView.hidden = NO;

}


// Adの読み込み失敗通知

-(void) nadViewDidFailToReceiveAd:(NADView *)adView

{

NSLog(@"Ad読み込み失敗");

_ictfAdView.hidden = NO;

_nadView.hidden = YES;

}


// 自社広告のタップイベント

-(void) adIctfAdTapHandle:(UITapGestureRecognizer*)sender

{

// AppStoreを開く

NSURL* url = [NSURL URLWithString:@"https://itunes.apple.com/jp/app/perfect-listener-voice-player/id570553082?mt=8"];

UIApplication* application = [UIApplication sharedApplication];

if ([application canOpenURL:url]) {

[application openURL:url];

}

}


@end


使い方は普通のNADViewと同じです。

adView = [[[NADViewEx alloc] initWithFrame:CGRectMake(0, 0, NAD_ADVIEW_SIZE_320x50.width, NAD_ADVIEW_SIZE_320x50.height) rootViewController:rootViewController] autorelease];


聞き取りに特化したボイスプレイヤーアプリ
「Perfect listener」が発売開始しました!

mzl.qidcuzxy.png
・長いシークバーで再生位置の調整が容易に行なえます。
・さらに細かく再生位置を調整したい場合、画面したのギアを回転させる事でコンマ秒単位での調整が可能です。
・再生開始時に自動的に0秒〜10秒巻き戻す「自動巻き戻し」機能付き。
・再生速度を0.5倍〜1.5倍に変更できます。
・Dropboxからリソースデータを読み込むため、iTunes同期などの面倒な操作が必要ありません。

議事録の文章化やテープ起こし業務、あるいは外国語の聞き取りなどに如何でしょうか。
私は今までiTunesを使って議事録の文章化を行なっていたのですが、このアプリに切換えてからは時間効率が1.5倍ほどになっております。
是非お試し下さい!



170円
(2012.10.23時点)
posted with ポチレバ
こんにちは。開発担当のICTFです。

iAdのガイドラインに「広告が表示中でない間、広告ビューを隠す事」とありますが、隠している間その領域に何を表示しようか悩んだ事は無いでしょうか。
広告が表示されるまでの間、作業領域を大きくとるというのが理想的なのかもしれませんが、その為(広告が表示されない間)だけの実装と考えるとかなり面倒です。

一案として、iAd非表示中は自社広告を変わりに表示するのは如何でしょうか。
常に広告枠に何かしら表示されている状態にしておけば、iAdの表示状態を気にする必要はありません。今回はそんなiAdビュークラスを実装します。

実装するiAdビューの仕様は次の通りです。
  • iAdビューを貼付けるだけ(通常のADBannerViewクラスと同じ扱い)で自社広告の表示を行なう。
  • iAd非表示中は自社広告を表示し、iAd表示中は自社広告を表示しない。
  • 自社広告をタップすることで、対象のAppStoreリンクに遷移する。
まずiAdと同じ大きさのバナーを作ります。
iPhoneは320x50、iPadは768x66となります。Retina対応する場合はそれぞれ2倍のサイズも用意して下さい。
ICTF_Ad320.png
自社広告ビュークラス(ICTF_AdView)を作ります。
サンプルでは単に画像を表示するだけのクラスですので、必要なければUIImageViewに画像を設定するだけで構いません。
【ICTF_AdView.h】

// 自社広告クラス

@interface ICTF_AdView : UIImageView

{

}


@end


【ICTF_AdView.m】

@implementation ICTF_AdView


-(id) init

{

CGRect frame;

if ([CommonFunctions isiPad]) {

frame = CGRectMake(0, 0, 768, 66);

}

else {

frame = CGRectMake(0, 0, 320, 50);

}

if (self = [super initWithFrame:frame]) {

if ([CommonFunctions isiPad]) {

self.image = [UIImage imageNamed:@"ICTF_Ad768.png"];

}

else {

self.image = [UIImage imageNamed:@"ICTF_Ad320.png"];

}

}

return self;

}


@end


[CommonFunctions isiPad]はデバイスがiPadであるかを調べる為の自作メソッドです。
iPadであればYESを返します。

ADBannerViewを継承したADBannerViewExクラスを作ります。
【ADBannerViewEx.h】

#import <iAd/iAd.h>

#import "ICTF_AdView.h"


// 自社広告表示機能を追加したiAdビュー

@interface ADBannerViewEx : ADBannerView

<ADBannerViewDelegate>

{

ICTF_AdView* _ictfAdView;

UITapGestureRecognizer* _ictfAdTapGesture;

}


@end


【ADBannerViewEx.m】

@interface ADBannerViewEx ()


// 自社広告のタップイベント

-(void) adIctfAdTapHandle:(UITapGestureRecognizer*)sender;


// 自社広告のタップイベント追加

-(void) addIctfAdTapGesture;


// 自社広告のタップイベント削除

-(void) removeIctfAdTapGesture;


@end


@implementation ADBannerViewEx


-(id) initWithAdType:(ADAdType)type

{

if (self = [super initWithAdType:type]) {

self.delegate = self;

_ictfAdTapGesture = nil;

// 自社広告を追加

_ictfAdView = [[ICTF_AdView alloc] init];

[self addSubview:_ictfAdView];

_ictfAdView.center = CGPointMake(self.bounds.size.width * 0.5, self.bounds.size.height * 0.5);

[self addIctfAdTapGesture];

}

return self;

}


-(void) dealloc

{

[_ictfAdView release];

[super dealloc];

}


// iAdの読み込み完了通知

- (void)bannerViewDidLoadAd:(ADBannerView *)banner

{

NSLog(@"iAd読み込み完了");

_ictfAdView.hidden = YES;

[self removeIctfAdTapGesture];

}


// iAdの読み込み失敗通知

-(void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error

{

NSLog(@"iAd読み込み失敗: %@",error);

_ictfAdView.hidden = NO;

[self addIctfAdTapGesture];

}


// 自社広告のタップイベント

-(void) adIctfAdTapHandle:(UITapGestureRecognizer*)sender

{

// AppStoreを開く

NSURL* url = [NSURL URLWithString:@"http://itunes.apple.com/jp/app/mono-calculator/id517496688?mt=8"];

UIApplication* application = [UIApplication sharedApplication];

if ([application canOpenURL:url]) {

[application openURL:url];

}

}


// 自社広告のタップイベント追加

-(void) addIctfAdTapGesture

{

if (_ictfAdTapGesture == nil) {

_ictfAdTapGesture = [[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(adIctfAdTapHandle:)] autorelease];

_ictfAdTapGesture.numberOfTapsRequired = 1;

[self addGestureRecognizer:_ictfAdTapGesture];

}

}


// 自社広告のタップイベント削除

-(void) removeIctfAdTapGesture

{

[self removeGestureRecognizer:_ictfAdTapGesture];

_ictfAdTapGesture = nil;

}


@end


自社広告をiAdビューの上に被せるように配置しています。
iAdの読み込み通知を受けたタイミングで、自社広告の表示・非表示を切換えます。
UITapGestureRecognizerをADBannerViewに追加する事で、iAdのタップイベントを乗っ取っています。
iAd表示後もタップイベントを乗っ取ったままだとまずいので、iAdの表示通知を受けてUITapRecognizerを解放しています。

ADBannerViewのDelegateをselfに設定していますので、広告表示側のViewControllerなどに特別な処理を実装したい場合、別に通知処理を用意する必要があります。

最後に実装の注意事項となりますが、最初UITapGestureRecognizerを自社広告ビュー(ICTF_AdView)に設定していました。
しかしその方法で実装した場合、ADBannerViewに自社広告ビューをaddSubViewしていてもタッチイベントが受け取れませんでした。
ADBannerViewのタッチイベントが優先されるようです。

ADBannerViewExの使い方はADBannerViewとまったく同じです。

adView = [[ADBannerViewEx alloc] initWithAdType:ADAdTypeBanner];


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

[UIView animateWithDuration:0.2 animations:^(void) {}];

を使って360°の回転アニメーションを作る場合、素直に書くと次のようになります。

[UIView animateWithDuration:0.2 animations:^(void) {

    CGAffineTransform positiveRotate = CGAffineTransformMakeRotation(360 * (M_PI / 180.0));

    view.transformpositiveRotate;

}];


ですがこのコードを動かすと、実際はまったく動かないのをご存知でしょうか。
360°はつまり0°と同じですので、最初から目的の度数であると判断される為です。
この現象を回避するため、また回転の方向を制御する為に90°の回転アニメーションを4回に分けて行なうなど面倒な処理が必要になります。

animateWithDuration: animations:で実装に苦労する360°回転処理ですが、実はCABasicAnimationを使う事で比較的簡単に実装ができます。

CABasicAnimation* rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];

rotationAnimation.toValue = [NSNumber numberWithFloat:(M_PI / 180) * 360];

rotationAnimation.duration = 30.0f;

rotationAnimation.repeatCount = HUGE_VALF;

[view.layer addAnimation:rotationAnimation forKey:@"rotateAnimation"];


toValueに回転する度数を、durationにアニメーションが完了するまでの時間を、repeatCountに繰り返す回数を設定します。
HUGE_VALFを設定する事で無制限の繰り返しにする事も可能です。
上記コードでは時計回りに回転しますが、反時計回りにしたい場合はtoValueにマイナスの値を設定して下さい。

CABasicAnimationを使う際の注意点ですが、画面の切り替わりやアプリの切り替わりでアニメーションがクリアされます。
画面を戻した時に継続してアニメーションを行ないたい場合、viewWillAppear:やapplicationWillEnterForeground:がコールされるタイミングで再度アニメーションの設定を行なう必要があります。
こんにちは。開発担当のICTFです。

滑らかに値を操作できる事がUISliderの魅力ですが、逆に「ぴったりある値に設定する」事は苦手です。
例えば、音声の再生速度をUISliderで滑らかに変動させたい。しかし、ぴったり1倍の再生速度に戻せるようにもしたい。といった機能の実装にそのままUISliderを用いると少々不満が出てしまいます。

今回は滑らかに値を変更させつつも、ある値にぴったりと設定が可能なUISliderの実装方法をご紹介します。
次の仕様でサンプルの実装を行ないます。
  • 再生速度の調整を行なうスライダー
  • スライダーの値は0.5〜1.5
  • デフォルトの値は1.0とする
  • 基本的に滑らかに再生速度の変更を行うが、ぴったり1.0倍に合わせる事が出来るようにする

まずIBでUISliderを配置し、Outletsで_rateSliderと関連づけます。
次に以下のメソッドを宣言し、UISliderのイベントとして関連づけます。

-(IBAction) rateSlider_changeValue:(id)sender;

 →Value Changed

-(IBAction) rateSlider_touchUp:(id)sender;

 →Touch Up Inside と Touch Up Outside

各メソッドの実装に入ります。

// 再生速度スライダーの値変更

-(IBAction) rateSlider_changeValue:(id)sender

{

NSLog(@"rateValue: %f", _rateSlider.value);

if (_player) {

_player.rate = _rateSlider.value;

}

}


// 再生速度スライダーから指が離れたとき

-(IBAction) rateSlider_touchUp:(id)sender

{

// 一定範囲内の値であれば、1.0へ吸着させる

if (_rateSlider.value < 1.2 && _rateSlider.value > 0.8) {

_rateSlider.value = 1.0;

if (_player) {

_player.rate = 1.0;

}

}

}


_playerは、音声の再生を管理する為のインスタンスを保持しています。
_player.rateに_rateSlider.valueを設定する事で、再生速度を変更します。
スライダーから指が離れるとrateSlider_touchUpメソッドがコールされますが、その時に値が0.8より多く、1.2未満であれば1.0に設定するようにしています。
このマージンを多く取る程ストレス無く1.0に吸着できるようになりますが、逆にその範囲内の値に設定する事ができなくなりますので、目的に合わせて適切な値を設定して下さい。
こんにちは。開発担当のICTFです。

UITableViewへの表示結果に対して検索をかける場合、一般的にはUISearchDisplayControllを用います。
UISearchDisplayControllは簡単に使えて便利なクラスですが、tableViewをカスタマイズしている場合、少々厄介な現象が発生します。
UISearchDisplayControlの検索結果はtableViewの上に専用のtableView(self.searchDisplayController.searchResultsTableView)として重ねて配置されるのですが、その際self.tableViewに施していたデザインが壊れてしまうのです。

2012-10-07 21.48.40.png
このようなデザインのtableViewに対して検索結果を表示すると・・・
2012-10-07 21.49.00.png
こんな風にデザインが壊れてしまいます。

通常のtableViewと検索結果のtableViewは別のインスタンスである為、検索結果のtableViewにも通常と同等のデザインを施す必要があるのですが、その処理を記述するタイミングに注意が必要です。
検索結果のtableViewは検索が行なわれるまで存在せず、且つ検索を行なう度にインスタンスが作り直されるようです。
ですのでviewDidLoad内で1度だけデザインすれば良いという訳にはいきません。

正しく表示させるには、検索結果のtableViewが作られた直後(例えば- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath内)に記述します。

if (tableView == self.searchDisplayController.searchResultsTableView) {

// 検索結果

file = [_searchResults objectAtIndex: [indexPath row]];

// 検索結果tableViewの設定(検索されるごとに生成される様なので、viewDidLoadでは実装不可

if (tableView.backgroundView == nil) {

tableView.backgroundView = [[[UIView alloc] initWithFrame:self.tableView.bounds] autorelease];

tableView.backgroundView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"SCR_PTT001.png"]];

tableView.separatorStyle = UITableViewCellSeparatorStyleNone;

}

}

else {

// 非検索

file = [_dataList objectAtIndex: [indexPath row]];

}


本日RelationalVoiceRecorderが4.0にバージョンアップしました!
iPhone5の縦長画面対応、iOS6対応、安定性が向上しております。
さらに新機能としてEvernoteとの連携機能を追加しました。

Evernote連携機能の使い方は非常に簡単です。

送信したいファイルのメニューの2ページ目を表示して
2012-10-05 14.02.33.png
Evernoteボタンをタップします。
2012-10-05 14.02.37.png
たったこれだけで完了です。
録音データ、録音地点、メモ情報が1つのメモとしてEvernoteにアップロードされます。
勿論Dropboxのアップロード機能と同じく、Everoteへのアップロードはバックグラウンドで行なわれます。
Evernoteへのアップロード中でも新しく録音を開始したり、メモの編集が可能です。

Evernoteへのアップロード状況は、専用の画面で確認が可能です。
2012-10-05 14.02.55.png
さらに便利になったRelationalVoiceRecorderを是非お試し下さい!

RelationalVoiceRecorder App
カテゴリ: 仕事効率化
価格: ¥350


無料版もございます。まずはこちらをお試し下さい。
無料版は下記の公式サイトから入手できます。

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

  • UITextAlignmentCenter
  • UITextAlignmentRight
  • UITextAlignmentLeft
がiOS6で廃止予定になりました。
上記3つの定数を使っている箇所でワーニングが発生するようになっています。
ワーニングを解除するには、それぞれ下記の定数に置き換えて下さい。
  • NSTextAlignmentCenter
  • NSTextAlignmentRight
  • NSTextAlignmentLeft
Twitterボタン
Twitterブログパーツ