[iOS]ユーザに選択させる(UIActionSheet)
前回のアラートは、ユーザに情報を伝える為のもの。今回のアクション・シートはユーザに選択させる為のものだ。
ビューコントローラにUIActionSheetDelegateプロトコルを設定する。
@interface ViewController : UIViewController <UIActionSheetDelegate>
@end
アクションシートを表示させる。
@implementation ViewController
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:@"My Action Sheet"
delegate:self
cancelButtonTitle:@"Cancel"
destructiveButtonTitle:@"destructive button"
otherButtonTitles:@"Button 1",
@"Button 2",
nil];
[actionSheet showInView:self.view];
}
@end
アラートと同様にアクション・シートもデリゲートのメソッドでボタン押下に対応する。
@implementation ViewController
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
NSLog(@"%s index(%d)", __func__, (int)buttonIndex);
}
- (void)actionSheetCancel:(UIActionSheet *)actionSheet
{
NSLog(@"%s", __func__);
}
@end
実行。
アクション・シートでは、追加するボタンの個数は可変だ。画面に収まりきれなく個数を指定した場合は、どうなるのだろうか?
@implementation ViewController
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:@"My Action Sheet"
delegate:self
cancelButtonTitle:@"Cancel"
destructiveButtonTitle:@"destructive button"
otherButtonTitles:@"Button 1",
@"Button 2",
@"Button 3",
@"Button 4",
@"Button 5",
@"Button 6",
nil];
[actionSheet showInView:self.view];
}
@end
なんと、ボタンの部分がピッカーになっている!
第50回関東Cocoa勉強会で@saeki24hさんが、自身が発見されたアクション・シートのバグを発表されていましたが、その時はボタンの個数が増えてピッカーになった際に、cancelボタンとdestructiveボタンの順番が変わって、その際、インデックスがおかしくなっていたが、iOS 5.1で修正されたのか、ボタンの順番が変わらず、その為か、インデックスは正しい値のようだ。
関連情報
UIActionSheet Class Reference
UIActionSheetDelegate Protocol Reference
[iOS]アラートを表示する
ビーコントローラでタッチ操作を検出するようにして、タッチされたら、OKボタンのみのアラートを表示する例だ。
ビューコントローラにプロトコルを使って、UIAlertViewDelegateへ対応させる。
@interface ViewController : UIViewController <uialertviewdelegate>
@end
タッチされたらOKボタンのみのシンプルなアラートを表示させる。
@implementation ViewController
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Demo Alert"
message:@"demo appl"
delegate:self
cancelButtonTitle:nil
otherButtonTitles:@"OK", nil];
[alert show];
}
@end
OKボタンが押下されたら呼び出される、デリゲートのメソッドを追加する。
@implementation ViewController
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
NSLog(@"- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex(%d)", (int)buttonIndex);
}
@end
実行。
関連情報
UIAlertView Class Reference
UIAlertViewDelegate Protocol Reference
[iOS]CoreAnimation(animating transitions)
画像に続いて文字列に対しても、何らかの画面上の効果を発生させたいと考えている。今、考えているのは、UILabeに対してだ。
前回までのUIViewに対してのアニメーションだと、対象のプロパティがアニメーションになるのだが、今回は効果に対応するプロパティを変更する必要が無い。変更したら、完了後に戻す処理が必要になる。
今、考えている事に合う手段はないか?と、探していて見つけたのだ、レイヤへの効果の適用だ。
まず、Quartz Coreフレームワークをプロジェクトに追加する。そして、QuartzCore/QuartzCore.hをインポートする。
サンプルではラベルの内容の変化が分かるように日付を設定している。
ラベルに現在日時を初期値として設定する。
- (void)awakeFromNib
{
NSDate *date = [NSDate date];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateStyle:NSDateFormatterMediumStyle];
[formatter setTimeStyle:NSDateFormatterMediumStyle];
self.label.text = [formatter stringFromDate:date];
}
画面がタッチされたら、ラベルの内容を現在日時に変更して、アニメーションを実行する。
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
CATransition *animation = [CATransition animation];
[animation setDelegate:self];
[animation setDuration:1.0f];
[animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
[animation setType:kCATransitionPush];
[animation setSubtype:kCATransitionFromLeft];
NSDate *date = [NSDate date];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateStyle:NSDateFormatterMediumStyle];
[formatter setTimeStyle:NSDateFormatterMediumStyle];
self.label.text = [formatter stringFromDate:date];
[[self.label layer] addAnimation:animation forKey:@"animation transition"];
}
文字が左から右に流れた後に、内容が変わる事が確認できるはずだ。
ソースコード
GitHubからどうぞ。
https://github.com/murakami/workbook/tree/master/ios/CoreAnimation - GitHub
関連情報
Core Animation for Mac OS X and the iPhone
Creating Compelling Dynamic User Interfaces
Core Animationプログラミングガイド
アニメーションのタイプとタイミング
iOS Developer Libraryの翻訳文書だ。
[iOS]CoreAnimation(flip view)
画面に表示する画像を差し替える場合、カードをめくるような効果を使える例だ。
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
[UIView beginAnimations:@"flip view" context:nil];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft
forView:self.imageView
cache:YES];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationDuration:1.0];
if (self.isAtMark) {
self.isAtMark = NO;
self.imageView.image = self.arrowImage;
}
else {
self.isAtMark = YES;
self.imageView.image = self.atmarkImage;
}
[UIView commitAnimations];
}
前回の例との差は、transitionとタイミングの指定の追加だ。
ソースコード
GitHubからどうぞ。
https://github.com/murakami/workbook/tree/master/ios/CoreAnimation - GitHub
関連情報
Core Animation for Mac OS X and the iPhone
Creating Compelling Dynamic User Interfaces
Core Animationプログラミングガイド
アニメーションのタイプとタイミング
iOS Developer Libraryの翻訳文書だ。
[iOS]iOS 5.1
今回は、iOS 5.1リリースに伴う、開発環境の更新に時間がかかっているため、いつもの練習が行えない。そこで、Developerサイトで見つけたページを紹介する。
iOSがバージョンアップすると、Xcodeもバージョンアップしないと、実機での動作確認が行えない。何時も、Xcodeのバージョンアップの方が少し遅れて始まるので、リリースを控えている場合は注意が必要だ。
そして、iOSがバージョナップすると、Xcodeのバージョンアップは必要か?ターゲットは、以前のバージョンのOSからなので、Xcodeのバージョンアップは?ということが話題になるように思えるが、その疑問に答えるサイトだ。
Create Aps for iOS 5.1
以前のADC時代から考えると、本当に最近のApple Developerサイトは、親切になったね!
[iOS]CoreAnimation(animation block)
CoreAnimationは奥が深い。その為、申し訳ないが、今、開発中のアプリケーションで利用しそうな機能を中心に取り上げてゆく。今回はアニメーション・ブロック。
画面をタッチすると、タッチした位置に画像が移動するコードだ。
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = touches.anyObject;
[UIView beginAnimations:@"center" context:nil];
self.atMarkImageView.center = [touch locationInView:self];
[UIView commitAnimations];
}
beginAnimations:context:とcommitAnimationsに囲まれた部分がブロックだ。ブロック内に記述されたUIViewの変更内容がアニメーションとなる。
ソースコード
GitHubからどうぞ。
https://github.com/murakami/workbook/tree/master/ios/CoreAnimation - GitHub
関連情報
Core Animation for Mac OS X and the iPhone
Creating Compelling Dynamic User Interfaces
Core Animationプログラミングガイド
アニメーションのタイプとタイミング
iOS Developer Libraryの翻訳文書だ。
[iOS]文字列を描画する
iOSでは文字列を描画する方法が複数あるが、それぞれ、長所と短所があるので、適材適所で使い分ける事が大事なようだ。
UILabelを使用する方法。単に描画したいだけなので、ビューでなくてもと思うかもしれないが、高機能なので便利だ。
- (void)viewDidLoad
{
[super viewDidLoad];
self.label = [[UILabel alloc] initWithFrame:CGRectMake(10.0, 100.0, 200, 50)];
self.label.font = [UIFont systemFontOfSize:48.0];
self.label.text = @"UILabel";
self.label.adjustsFontSizeToFitWidth = YES;
[self.view addSubview:self.label];
}
UIViewのサブクラスを作成して、-drawRect:で、NSStringのUIKit Additionsで描画するのも手軽だ。
- (void)drawRect:(CGRect)rect
{
NSString *str = @"NSString";
[str drawAtPoint:CGPointMake(10.0, 20.0) withFont:[UIFont systemFontOfSize:48.0]];
}
CoreGraphicsを使う方法もあるが、日本語の扱いや、座標の扱いが難しいので、理由が無い限りはお勧めできない。
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGFloat height = self.bounds.size.height;
CGContextTranslateCTM(context, 0.0, height);
CGContextScaleCTM(context, 1.0, - 1.0);
CGColorSpaceRef cs = CGColorSpaceCreateDeviceRGB();
CGContextSetFillColorSpace(context, cs);
CGColorSpaceRelease(cs);
CGContextSetTextDrawingMode(context, kCGTextFill);
CGContextSetRGBFillColor(context, 0.0, 0.0, 0.0, 1.0);
CGContextSelectFont(context, "Helvetica", 48.0, kCGEncodingMacRoman);
CGContextShowTextAtPoint(context, 10.0, 10.0, "Quartz", strlen("Quartz"));
CGContextFlush(context);
CGContextRestoreGState(context);
}
これら三つを使って文字列を描画した例だ。
ソースコード
GitHubからどうぞ。
https://github.com/murakami/workbook/tree/master/ios/DrawString - GitHub
関連情報
iOS描画および印刷ガイド
Apple Developerサイトの情報。日本語に翻訳されている。
MOSADeN Online:「iPhoneアプリ初級脱出Online:高橋政明」
豊平文庫アプリケーションの高橋さんの記事。丁寧な説明で参考になる。
[iOS]イベント駆動のXMLプログラミング(その2)
前回の続き。用語を整理する。
エレメントは以下の初期となる。
<タグ>内容</タグ>
エレメントとは、タグで囲まれたデータという事になる。
XMLデータを頭から処理していき、エレメントに到達すると- parser:didStartElement:namespaceURI:qualifiedName:attributes:が呼ばれる。そのエレメントの内容に到達すると- parser:foundCharacters:が呼ばれるイメージだ。
XMLデータは木構造となるが、SAXではイベント駆動でデリゲートのメソッドが呼ばれるので、アプリケーション側で木構造を意識して処理する事になる。
例えば、以下のようなXMLデータ。
<?xml version= "1.0" encoding="UTF8">
<article author="Yukio MURAKAMI">
<para>とても短い文章。</para>
</article>
- 処理開始
- エレメントarticleの開始タグが得られる。
- エレメントarticleの属性authorと値"Yukio MURAKAMI"が得られる。
- エレメントparaの開始タグが得られる。エレメントarticleの終了タグはまだなので、paraはarticleに包含されている事が分かる。
- エレメントparaの内容”とても短い文書。”が得られる。
- エレメントparaの終了タグが得られる。
- エレメントarticleの終了タグが得られる。
- 処理終了
ソースコード
GitHubからどうぞ。
https://github.com/murakami/workbook/tree/master/ios/XMLParser - GitHub
関連情報
Event-Driven XML Programming Guide
Apple Developerサイトの情報。
[iOS]イベント駆動のXMLプログラミング
XMLデータを操作するAPIに、DOM(Document Object Model)とSAX(Simple API for XML)があるが、これに対応するCocoaのクラスがNSXMLDocumentとNSXMLParserだ。ただし、iOSではNSXMLDocumentが利用できない。iOSでDOMを使用したい場合はlibxml2を利用する事になる。
XMLデータからエレメント名と値を取得する例は、以下のとおり。
ビュー・コントローラをNSXMLParserDelegateに対応させる。
@interface ViewController : UIViewController
@property (strong, nonatomic) NSString *elementName;
@end
指定されたURLのXMLデータを読み込み、エレメントとそれの値を見つけたらデバッグ出力する例だ。
@implementation ViewController
@synthesize elementName = _elementName;
- (void)viewDidLoad
{
[super viewDidLoad];
NSString *requestString = [NSString stringWithString:@"http://www.kyuden.co.jp/power_usages/xml/electric_power_usage20120304.xml"];
NSURL *url = [NSURL URLWithString:requestString];
[self parseXMLFile:url];
}
- (void)parseXMLFile:(NSURL *)url
{
NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:url];
[parser setDelegate:self];
[parser parse];
}
- (void)parser:(NSXMLParser *)parser
didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qualifiedName
attributes:(NSDictionary *)attributeDict
{
if (elementName) {
NSLog(@"element: %@", elementName);
self.elementName = elementName;
}
}
- (void)parser:(NSXMLParser *)parser
didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
{
if (self.elementName) {
self.elementName = nil;
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
if ((self.elementName)
&& (![self.elementName isEqualToString:@""])
&& (string)) {
NSLog(@"char: %@", string);
}
}
@end
これ以上については著者も調査中なので、機会があれば次回で。
ソースコード
GitHubからどうぞ。
https://github.com/murakami/workbook/tree/master/ios/XMLParser - GitHub
関連情報
Event-Driven XML Programming Guide
Apple Developerサイトの情報。
[Mac][iOS]zlib ファイルの圧縮と解凍
zipファイルの操作でなく、メモリ上のデータを圧縮/解凍するには、どんな方法がいいのか?
以前、zlibの解説文章を読んだ事があり、全く難解で理解できなかったトラウマがあって、zlibを直接利用する事は避けていたのだが、今、改めて調べてみると、それ程、怖がるものではないように感じている。
という訳で、今回は、直接、zlibを利用する話だ。
OS X / iOSでzlibを利用するのは、簡単だ。"libz.dylib"をプロジェクトに追加するだけでいい。
データを圧縮するコードは以下のとおり。
#define OUTBUFSIZ 1024
- (void)zip:(NSString *)path
{
NSMutableData *data = [[NSMutableData alloc] init];
z_stream strm;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
deflateInit(&strm, Z_DEFAULT_COMPRESSION);
char str[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
strm.next_in = (Bytef *)str;
strm.avail_in = strlen(str);
char buffer[OUTBUFSIZ];
strm.next_out = (Bytef *)buffer;
strm.avail_out = OUTBUFSIZ;
int status;
for (;;) {
if (strm.avail_in == 0) {
status = deflate(&strm, Z_FINISH);
}
else {
status = deflate(&strm, Z_NO_FLUSH);
}
if (status == Z_STREAM_END) {
break;
}
if (status != Z_OK) {
DBGMSG(@"deflate: %s", (strm.msg) ? strm.msg : "error");
break;
}
if (strm.avail_out == 0) {
[data appendBytes:buffer length:OUTBUFSIZ];
strm.next_out = (Bytef *)buffer;
strm.avail_out = OUTBUFSIZ;
}
}
if (strm.avail_out != OUTBUFSIZ) {
[data appendBytes:buffer length:(OUTBUFSIZ - strm.avail_out)];
}
deflateEnd(&strm);
//[data writeToFile:path atomically:YES];
}
文字列strを圧縮するコードだ。圧縮したデータを保存する様にしてみたのだが、これだけだと、zip形式のファイルにならないようで、unzip出来ないので、コメントアウトしている。
ソースコード
GitHubからどうぞ。
https://github.com/murakami/workbook/tree/master/mac/Zip
関連情報
zlib
A Massively Spiffy Yet Delicately Unobtrusive Compression Library
Minizip
Zip and UnZIp additionnal library
ZipArchive
An Objective C class for zip/unzip on iPhone and Mac OSX
objective-zip
An iOS wrapper for ZLib and MiniZip
Objective-CでZIPアーカイブを読み取る
@marvelphさんのブログです。
Objective-Cでzlibを使った圧縮
分かりやすくていい。初めの情報として助かった。
zlib入門
丁寧な説明とサンプルが参考になった。