はてなブックマークに追加

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
はてなブックマークに追加

iPhoneアプリ:画像ビュアを作る




サイトを移行しました。
iPhoneアプリと、そのプログラム



さて、これまで3回のiPhoneネットワークプログラミング
iPhone ネットワークプログラミング その1
iPhone ネットワークプログラミング その2
iPhone ネットワークプログラミング その3
を書いてきました。
ここいらで、総まとめとして一つアプリを作ってみたいと思います。


今回作成するアプリは画像ビュアです。
Downloadボタンをタップすると、
プログラム中にハードコーディングされたURLから画像をダウロードしてきて
iPhoneの画面上に表示するという、実用性0のアプリを作ってみたいと思います(笑)

完成図がこちら。
生意気にもプログレスバーなどもつけてみました。
(そのせいでややこしくなったけど・・・)

iphonenetworkprogramming2.jpg

さて、ではXcodeで開発を進めていきます。
毎度おなじみの手順ですが,

Xcodeの「新規作成」-> 「ファイル」->「新規プロジェクト」を選択。
プロジェクトの種類「Application」でテンプレート「View-based Application」を選択。
プロジェクト名は「PhotoViewer」にします。

エディタが起動したら、まずはIBでGUIを設計します。
左カラムから「グループとファイル」->「Resources」-> PhotoViewerViewController.xib
をダブルクリックするとIBが立ち上がりますので、
次の部品をライブラリからドラックしてきて並べてください。

iphonenetworkprogramming1.jpg


ここまでで、IB側での作業は終了です。
次はXcodeに戻ってプログラムをかいていきます。

PhotoViewerViewController.h
@interface PhotoViewerViewController : UIViewController {
NSFileHandle *file;
NSString *filePath;

IBOutlet UIImageView *imageView;
IBOutlet UIProgressView *progressBar;
double expectedContentLength;
}
-(IBAction) downloadButtonPressed:(id)sender;

@end



PhotoViewerViewController.m
- (void)connection:(NSURLConnection *)connection 
didReceiveResponse:(NSURLResponse *)response {
expectedContentLength = [response expectedContentLength];
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
UIImage *img = [[UIImage alloc] initWithContentsOfFile:filePath];
imageView.image = img;
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
if (file == nil) {
NSFileManager *fm = [NSFileManager defaultManager];
[fm createFileAtPath:filePath contents:[NSData data] attributes:nil];
file = [[NSFileHandle fileHandleForWritingAtPath:filePath] retain];
}
progressBar.progress = progressBar.progress +
((long double)[data length] / (long double)expectedContentLength);
[file writeData:data];
}

-(IBAction) downloadButtonPressed:(id)sender
{
NSString *url = [NSString stringWithString:
@"http://blog-imgs-45.fc2.com/i/i/p/iiphoneapp/sky.jpg"];
NSString *directoryPath = [[NSHomeDirectory()
stringByAppendingPathComponent:@"tmp"] retain];
NSString *fileName = [url lastPathComponent];
filePath = [[[directoryPath stringByAppendingPathComponent:fileName]
stringByStandardizingPath] retain];
NSLog(@"%@", filePath);

NSURLRequest *request = [ NSURLRequest requestWithURL:[NSURL URLWithString:url]];
[NSURLConnection connectionWithRequest: request delegate: self ];
}


大半が前3回で説明済みのコードなので理解しやすいと思います。
まず、ヘッダファイルではUIImageViewとUIProgressViewのアウトレットを宣言しています。
このアウトレットとIB側の部品を、次のように接続しておいてください。

iphonenetworkprogramming3.jpg

前回まではviewDidLoadにコアの処理を書いていましたが、
今回はDownloadボタンが押されたときに、ダウンロードを開始したいので
大半の処理はdownloadButtonPressedメソッドの中に移動しています。


プログレスバーの更新はconnection:didReceiveDataメソッドの中で行っています。
現在の進行具合 = 受信量 /ダウンロードサイズ
で求めています。これはプログレスバーの常套手段ですね。

全体のダウンロードサイズ(変数:expectedContentLength)は
connection:didReceiveResponseメソッドの中で求めています。
このメソッドは、iPhone側から送ったリクエストに対してのレスポンスとして呼び出されます。
そのレスポンスを利用して、これからダウンロードするファイルのサイズを取得します。


ダウンロードが終了すると
connectionDidFinishLoadingメソッドがトリガされるので
このメソッドの中で画面の更新を行っています。
Documentフォルダ以下に保存された画像の読み出しには
initWithContentsOfFileメソッドを使用します。


コンパイル&実行して、うまく動作するかを確かめてみてください。
はてなブックマークに追加

iPhone ネットワークプログラミング その3




サイトを移行しました。
iPhoneアプリと、そのプログラム



第3回:ファイルのダウンロード

前回にひきつづき、ネットワークプログラミングその3では、
Web上からファイルをダウンロードしてきて
iPhoneに保存するプログラムを紹介します。

CoCoaフレームワークにはNSURLDownload
というクラスがあり、非常に簡単にファイルをダウンロードできるのですが、
iPhoneではこのクラスが実装されていないため、
NSURLConnectionクラスを使って自作する必要があります。


といっても、前回のプログラムと大きくは違わないので
簡単に理解できるかと思います。

sampleViewController.h
@interface networkViewController : UIViewController {
NSFileHandle *file;
NSString *filePath;
}
@end

sampleViewController.m
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSLog(@"completed!");
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
if (file == nil) {
NSFileManager *fm = [NSFileManager defaultManager];
[fm createFileAtPath:filePath contents:[NSData data] attributes:nil];
file = [[NSFileHandle fileHandleForWritingAtPath:filePath] retain];
}
[file writeData:data];
}

- (void)viewDidLoad {
[super viewDidLoad];

NSString *url = [NSString stringWithString:
@"http://www.ritsumei.ac.jp/acd/mr/lib/images/calender/kin.pdf"];
NSString *directoryPath = [[NSHomeDirectory()
stringByAppendingPathComponent:@"tmp"] retain];
NSString *fileName = [url lastPathComponent];
filePath = [[[directoryPath stringByAppendingPathComponent:fileName]
stringByStandardizingPath] retain];
NSLog(@"%@", filePath);

NSURLRequest *request = [ NSURLRequest requestWithURL:[NSURL URLWithString:url]];
[ NSURLConnection connectionWithRequest: request delegate: self ];
}


これまでと同じく、ViewControllerのクラスに直接
プログラムを書いていきます。
理解しやすいよう、例外処理などは書いてないので
iPhoneに実装する際には追加が必要です。


viewDidLoadメソッドの中身から見ていきましょう。
NSURLConnectionを使って非同期でリクエストを送っているので
大半は前回と同様のプログラムになっています。
違いは、NSURLRequestを作る前に、
ダウンロードするURL、ダウンロードファイル名、ダウンロード先フォルダ
などのパスを設定している部分だけです。

2行目で、対象ファイルのあるURLの指定、
3行目で、保存するディレクトリパス(今回はtmpフォルダ)
4行目で、対象ファイルのファイル名を指定して
5行目で、保存するファイルパスを指定しています。

4行目で使用している、lastPathComponentというメソッドは
パスからファイル名だけを取り出せる便利なメソッドです。
例えばパスが
http://www.ritsumei.ac.jp/acd/mr/lib/images/calender/kin.pdf
であれば、lastPathComponentの戻り値はkin.pdfとなります。


あとは、デリゲートの説明です。
connectionDidFinishLoading:
connection:didReceiveData:
上の二つのメソッドがデリゲートとなっており、
前者はダウンロードが完了したときにトリガされます。
また、後者はサーバからデータが送られてくるごとに呼び出されます。
こちらのメソッドは数回に分けて呼び出されるため、
メソッド内のプログラムも、それに対応したものになっています。

connection:didReceiveData:
のメソッドでは最初に呼び出されたときにファイルを作成し、
次の呼び出しからはそのファイルに追記していく処理を行っています。
(データが数回に分けて送られてくるため、このような処理になります)


さて、実行してみてください。
うまくいけば、コンソールにファイルのパスとcompleted!と表示されます。
Finderから表示されたファイルパスを辿ってみてください。
実際にファイルが保存されていれば成功です。




はてなブックマークに追加

iPhone ネットワークプログラミング その2




サイトを移行しました。
iPhoneアプリと、そのプログラム



第2回:非同期通信によるデータの取得

さて、前回は同期通信でデータを取得しました。
今回は、非同期通信を使ってデータを取得してみましょう。

- ( void ) connection:( NSURLConnection *) connection didReceiveData:( NSData *) data
{
NSLog(@"%@", [[[NSString alloc] initWithData:data
encoding:NSASCIIStringEncoding] autorelease]);
}

- (void)viewDidLoad {
[super viewDidLoad];
NSString *url = [NSString stringWithString:@"http://google.co.jp"];
NSURLRequest *request = [ NSURLRequest requestWithURL:
[NSURL URLWithString:url] cachePolicy:
NSURLRequestReloadIgnoringLocalCacheData timeoutInterval: 60.0 ];
[ NSURLConnection connectionWithRequest: request delegate: self ];
}


前回と同様、実行するためにはview-based applicationでプロジェクトを作成し、
viewController.mの中身に上記プログラムを追加してください。


URLとタイムアウトを設定したNSURLRequestオブジェクトを作成し、
NSURLConnectionクラスのconnectionWithRequest:delegateメソッドを使って
コネクションを張ります。

今回のプログラムではデリゲートは自分自身(viewController)を登録しておきます。
デリゲートってなんぞや?という方はこちら
Objective-Cのデリゲート


データがサーバから送り返されてくると
connection:didReceiveData:メソッドがトリガされます。
データが大きい時には数回このメソッドが呼び出されることになります。


実際にコンパイル&実行してみて
HTMLの内容がコンソールに表示されることを確認してみましょう。

次回はファイルダウンロードについて紹介します
iPhoneネットワークプログラミング その3
はてなブックマークに追加

iPhone ネットワークプログラミング その1




サイトを移行しました。
iPhoneアプリと、そのプログラム



第1回:同期通信によるデータの取得

iPhoneのネットワークプログラミングに関して
あまり資料がないのはなぜだろう?

Macの開発とかなり似ているからだろうか?
しかし、Macのネットワークプログラミング自体
マイナだと思うんだけど(笑)

そんなこんななモチベーションで
iPhoneネットワークプログラミングについて書いてみようと思う。

まずはじめに、簡単なサンプルから。
GoogleのトップページのHTMLを取得するプログラムです。
今回は同期通信でデータを取得するバージョンです。

同期通信とはデータが送り返されてくるまで何もしない、
つまり待ち続ける通信方式です。
これに対して、非同期通信とはデータが送り返されてくるのを
待たずに次の処理を始める通信方式です。

実際のプログラムがこちら。
- (void)viewDidLoad {
[super viewDidLoad];

NSString *url = [NSString stringWithString:@"http://www.google.co.jp"];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
NSURLResponse *response = nil;
NSError *error = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:request
returningResponse:&response error:&error];

NSLog(@"%@", [[[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding] autorelease]);
}


上のプログラムを実行するためには
View-based application でプロジェクトをつくって
ViewdidLoad関数の中にプログラムを書くだけです。

NSURLRequestクラスのインスタンスにサーバのアドレスを登録し、
sendSynchronousRequestメソッドを使ってリクエストを送ります。
このメソッドの戻り値としてサーバのHTMLがNSData型で返されてくるので、
NSStringクラスのinitWithDataメソッドを使ってNSStringに変換して表示しています。

次回は非同期通信でのやりとりを説明します
iPhone ネットワークプログラミング その2

はてなブックマークに追加

回転のジェスチャを取得する


iOS 3.2以前にローテイト(回転)やスワイプなどの
ジェスチャを取得するためにはtouchesMoved:withEvent:
の中に、自前で取得のためのプログラムを実装する必要がありました。

iOS 3.2からはUIGestureRecognizerというクラスが追加され、
非常に簡単にユーザのジェスチャを取得できるようになりました。

回転のジェスチャを取得する例を下に示します
- (void)viewDidLoad {
[super viewDidLoad];

UIRotationGestureRecognizer* rotationGesture =
[[UIRotationGestureRecognizer alloc] initWithTarget:
self action:@selector(didRotationGesture:)];
[self.view addGestureRecognizer:rotationGesture];
[rotationGesture release];
}

-(void) didRotationGesture:(UIRotationGestureRecognizer*) sender {
UIRotationGestureRecognizer* rg =
(UIRotationGestureRecognizer*) sender;
NSLog(@"rotate:%f", rg.rotation);
}


viewDidLoad関数の中で、UIRotationGestureRecognizerクラスの
インスタンスを作成し、Viewにジェスチャとして登録します。
インスタンスには、回転のイベントが発生したときにトリガされる関数を
登録しておきます。

上のプログラムではトリガ関数としてdidRotationGestureを作成しました。
引数から回転角などを得ることが出来ます。


毎度おなじみの彼を回転させてみました。笑

UIGestureRecognizer1.jpg

このように、UIImageViewやUIViewを回転させる場合には
コールバック関数の中で次のように書けばよいでしょう。

-(void) didRotationGesture:(UIRotationGestureRecognizer*) sender {  
UIRotationGestureRecognizer* rg =
(UIRotationGestureRecognizer*) sender;
[imageView setTransform:
CGAffineTransformRotate(prevTransform, rg.rotation)];
}


prevTransformは前回の回転イベントが終了した時の姿勢です。
touchesEndedの中などで、保存しておけばよいでしょう。
また、デフォルトではマルチタッチイベントは取得されない設定になっているので
IBでマルチタッチを有効にしておく必要があります。

UIGestureRecognizer2.jpg


UIGestureRecognizerを用いれば、回転だけでなく
タップ・ピンチイン・ピンチアウト・パン・スワイプ
ローテイト・ロングプレス
などのイベントも取得することが出来ます。

これらのイベントも回転のイベントと同様の方法で
取得できるので、ぜひ実験してみてください。

はてなブックマークに追加

UIImaegViewにUIButtonを追加する


UIImaegViewUIButton1.jpg


図のようにUIImaegViewにUIButtonを追加することは
できません!

無理やり追加した場合、ボタンが反応しない不具合が起こります。


ごめんなさい、嘘を書いてました。
UIImaegViewにUIButtonを追加することは
できます!

そのプログラムを下に載せます
なお、画像のtest.png, button.pngなどの画像は
各自用意して、プロジェクトに追加しておいてください。


- (void)viewDidLoad {
[super viewDidLoad];

// imageViewをViewに追加
UIImageView *imageView = [[UIImageView alloc] initWithImage
:[UIImage imageNamed:@"test.png"]];
imageView.frame = CGRectMake(50, 100, 200,200);
imageView.userInteractionEnabled = YES;
[self.view addSubview:imageView];

// UIButtonをUIImageViewに追加
UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(160, 0, 40, 40)];
[button setBackgroundImage:[UIImage imageNamed:@"button.png"]
forState:UIControlStateNormal];
[button addTarget:self action:@selector(deleteButtonPressed:)
forControlEvents:UIControlEventTouchUpInside];
[imageView addSubview:button];
}

- (void) deleteButtonPressed:(id)sender
{
NSLog(@"pressed!");
}


ポイントは10行目付近の
imageView.userInteractionEnabled = YES;
と書かれた行です。
デフォルトではUIImageViewはユーザからのタッチイベントを
受け付けない設定になっているので、
この行で、タッチイベントの取得を許可しています。

下図のように、画像とボタンが表示されれば成功です。
ボタンを押せば、コンソールに"pressed!"と表示されます。

uiimageviewuibutton3.jpg

はてなブックマークに追加

UIImageViewを動かす

imageViewで表示した画像を、
指の動きにあわせて動かす方法を紹介します。

まずは動かすための画像をIBで設定します。

moveImageVIew1.jpg

IBのViewウインドウにライブラリからUIImageViewを
ドラック&ドロップします。

moveimageview1_5.jpg

次にAttributesウインドウでファイルを指定し、
画像を読み込みます。

ここまでできたら、Xcodeに戻りプログラムを作成します。
まずは、ヘッダファイルから見ていきましょう。

sampleViewController.h
@interface sampleViewController : UIViewController {
IBOutlet UIImageView *panda;
}

ヘッダファイルでは、先程IB側で設定したUIImageViewのアウトレットを
宣言しているだけです。

mファイルではUIImageViewの中心座標が
指を置いた座標になるようにタッチイベントのコールバック関数を設定します。

コールバック関数とはなんぞや?というかたはこちら
Objective-Cのコールバック

デフォルトで生成されたファイルに次の関数を追加してください。

sampleViewController.m
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint touchPos = [touch locationInView:self.view];
panda.center = touchPos;
}

この関数では、1行目で指座標の配列touchesから、
どれか一つの座標をとり出しています。
次に、2行目では、指の座標を指定したView(今回はオリジナルview)
における座標系に変換します。
最後の3行目で、変換後の座標を画像の中心座標に設定しています。


あとはIB側でpandaアウトレットとUIImageVIewを接続したら
コンパイル&実行してみてください。

画面上で指を動かすと、画像も追従して動けば成功です。

moveimageview2.jpg

はてなブックマークに追加

UIScrollViewの使い方 その4



サイトを移行しました。
iPhoneアプリと、そのプログラム



ここまでの3回の説明で、画像のスクロールと拡大縮小を
行うことが出来るようになりました。

UIScrollViewの使い方 その1
UIScrollViewの使い方 その2
UIScrollViewの使い方 その3

今回は、iPhoneの画面がタップされた時に
その座標を表示するプログラムを作ってみたいと思います。


こう書くと簡単そうなのですが、
意外や意外、これが結構めんどくさいのです。


もう一度UIScrollView その1で使った絵を
もう少し、正確に書いたものを書いてみます。
UIScrollView8.jpg


基本的には、ユーザのタッチイベントを取得するのは
一番下側のViewで行うのですが、この図からもわかるように
上側にScrollViewがのっかってしまっているために
タッチイベントがこれに邪魔されて一番下側のViewにまで降りてこないのです。
そこで、タッチイベントがScrollViewを透過してくるように設定します。

この設定は簡単で次の一行をviewDidLoad関数の中に記述するだけです。
scrollView.userInteractionEnabled = NO;	


IBでも同様の設定項目があるので、こちらで設定してもOKです。
UIScrollView9.jpg

ようは、scrollViewは画面がタッチされても無視しますよ~、と
宣言しているだけです。


さて、これで下側のViewがタッチイベントが取得できるようになりました。
タッチイベントを取得するにはtouchesBegan:withEventコールバックを使います。
この関数の中で、タッチされた座標の配列から1つを取り出し
scrollViewにおける座標系に変換して、touchPosに代入して表示ています。

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint touchPos = [touch locationInView:scrollView];
NSLog(@"%f, %f", touchPos.x, touchPos.y);
}


これで準備は整いました。早速コンパイル&実行してみましょう。
iPhoneの画面上をタップするごとに、コンソールに座標が表示されれば成功です。

と。ここまでは良かったのですが、問題発生です。
なんと!スクロールができなくなってしまったのです。。
ScrollViewのユーザインタラクションをOFFにしたのですから、
当たり前っちゃぁ、当たり前なんですけどねぇ。

ここまでのプロジェクトをココに置いておきます。
scroll3.zip


次回はこの問題を解決します。
UIScrollViewの使い方 その5
はてなブックマークに追加

UIScrollViewの使い方 その3



サイトを移行しました。
iPhoneアプリと、そのプログラム



前回のプログラム
UIScrollViewの使い方 その2
までで、UIScrollViewを使って画像をスクロールするところまで出来るようになりました。

次は、画像の拡大縮小機能を実装してみます。
まずはヘッダファイル内でUIScrollViewDelegateプロトコルに準拠します。
三角カッコで囲まれたところが、その部分です。
プロトコルに準拠って何?ってかたはこちら
Objective-Cのプロトコル


SampleViewController.h

@interface ScrollViewController : UIViewController
<UIScrollViewDelegate>
{
IBOutlet UIScrollView *scrollView;
UIImageView *imageView;
}


SampleViewController.h

- (void)viewDidLoad {
[super viewDidLoad];

imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"test.jpg"]];
[scrollView addSubview:imageView];
[imageView release];

scrollView.contentSize = imageView.frame.size;
scrollView.delegate = self;
scrollView.minimumZoomScale = 0.5;
scrollView.maximumZoomScale = 4.0;
}

- (UIView *)viewForZoomingInScrollView:(UIScrollView *)_scrollView
{
return imageView;
}



viewDidLoad関数内でscrollViewのデリゲートを
自分のクラス(sampleViewController)に設定しておきます。
また、minimumZoomScaleとmaximumZoomScaleで、拡大縮小のリミット値を設定しています。

あとは、デリゲート関数viewForZoomingInScrollViewで、
拡大縮小したいViewを返せば完成です。

さっきからデリゲート、デリゲートって言っとるけど
デリゲートって何やねん!ぉらぉらって人はこちら
Objective-Cのデリゲート


ここまで記述できたら、コンパイル&実行してみましょう。

UIScrollView7.jpg

画面上でピンチイン、ピンチアウトするとそれにしたがって画像が拡大縮小します。
うまくいかなかった場合にはデリゲートが適切に設定されているか、
もう一度確かめてみてください。

ここまでのプロジェクトをココに置いておきます。
参考にしてみてください。
scroll2.zip


次回は拡大縮小と座標の対応について説明します
UIScrollViewの使い方 その4


はてなブックマークに追加

UIScrollViewの使い方 その2



サイトを移行しました。
iPhoneアプリと、そのプログラム



さて、前回
UIScrollViewの使い方 その1
のコードの内容を見ていきましょう。

メインのプログラムはviewDidLoadの中身になります。

imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"test.jpg"]];

imageNamed関数を使って、画像を読み込みUIImageファイルを生成しています。
そして、生成したUIImageファイルを画像としてもつUIImageVIewを作成しています。
ここまではこんな感じ。

UIScrollView5_.jpg


[scrollView addSubview:imageView];
[imageView release];

つぎに上の2行で、scrollViewに今作ったimageViewを追加しています。
ViewにaddSubviewでボタンやimageViewを追加するのは常套手段なので
覚えておいて損はないかと思います。

ここまでで、こんな感じ。

UIScrollView6_.jpg



見るからにUIScrollViewのサイズがUIImageVIewと異なっており、
画面と同サイズなので、スクロールするマージンがなくなってしまっています。

そこで、スクロールを行えるようにするため、
scrollView.contentSize = imageView.frame.size;

でscrollViewのサイズをimageVIewのサイズと同じにしています。


次はいよいよピンチイン・ピンチアウトで
画像の拡大縮小が出来るようにコードを追加していきましょう。


UIScrollViewの使い方 その3
開発アプリ

iDOF 色影 ラテアート ぱすてる

プロフィール

hokuson

Author:hokuson
京都在住。iPhoneアプリ「色影」や「iDOF」の開発者。アプリのレビューとかもしてみる。博士後期課程@R大学。ついに就職活動なるものをしなければいけないらしい。誰か雇ってください。笑。

カレンダー
06 | 2017/07 | 08
- - - - - - 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 - - - - -
カテゴリ
最新コメント
RSSリンクの表示
リンク
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。