UIScrollView - 拡大縮小

2010年7月7日水曜日 | Published in | 0 コメント

このエントリーをはてなブックマークに追加

[前回] Cocoaの日々: UIScrollView - フリックで画像(ページ)をめくる

今回は画像の拡大縮小を行って見る。やるべきことはプロパティとデリゲートの設定。

(1)プロパティ設定


拡大縮小可能なスケール(倍率)を設定する。
self.scrollView.minimumZoomScale = 0.1  // 1/10まで縮小可能
self.scrollView.maximumZoomScale = 10.0;  // 10倍まで拡大可能

倍率は Interface Builder でも設定が可能。


(2) UIScrollViewDelegate


デリゲートを実装し、拡大縮小対象のビューを viewForZoomingInScrollView: で指定する。
@interface ScrollViewStudy2ViewController :
   UIViewController <UIScrollViewDelegate> {

 UIScrollView* scrollView_;
}

今回は1枚のビューを使っているので subviews の最初の要素を返すだけ。
-(UIView*)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
 return [[scrollView subviews] objectAtIndex:0];
}

実装したら delegateプロパティを設定するか、Interface Buidlerで delegateの接続を行っておく。

実行してみよう。まず元画像はこれ。

拡大は問題なし。

縮小は..

ああ、ビューが一枚だから全体が縮小されてしまった。ページ単位で拡大縮小するにはビューを画像ごとに分ける必要があるのか。


参考情報

UIScrollViewDelegate Protocol Reference
プロトコルのリファレンス


その他


(メモ)iPhoneシミュレータでのピンチ操作は Optionキーを押しながらマウスを動かす。


 

UIScrollView - フリックで画像(ページ)をめくる

2010年7月6日火曜日 | Published in | 11 コメント

このエントリーをはてなブックマークに追加

UIScrollViewを使い、指でフリックしてめくっていく簡易的な画像ビューアを作ってみた。

画像サンプル


8枚ほどの検証用画像を用意した(320x460ピクセル)。

画像はここから拝借した。
夜景 - フリー写真素材(無料壁紙画像)Futta.NET


実装


まずスクロール対象のビューを用意する。これは前回のコード(ImageView)をそのまま流用して単純に8枚の画像を横にならべてみた (全体で 2560x460ピクセル)。

[前回] Cocoaの日々: UIScrollView - サムネイル画像を並べて指でスクロールさせる


UIScrolViewの設定も基本的には前回と同じ。今回はこれに Paging設定を追加する。
self.scrollView.contentSize = imageView.bounds.size;  // ビューのサイズを指定
[self.scrollView addSubview:imageView]; // ビューの追加

// new stuffs
self.scrollView.pagingEnabled = YES;
self.scrollView.showsHorizontalScrollIndicator = NO;// 横スクロールバー非表示
self.scrollView.showsVerticalScrollIndicator = NO; // 縦スクロールバー非表示
self.scrollView.scrollsToTop = NO; // ステータスバーのタップによるトップ移動禁止

UIScrollView.paginEnabled = YES とすることで、スクロールの単位が画面横幅(320ピクセル)となる。指を離すと必ず左右どちらかかの画像が表示されるまでスクロールされる。
こんな感じ。
右から左へフリックすると

右へスクロールする。指を離すと

右側の画像までスクロールして止まる。


参考情報

Scrolling Using the Paging Mode
UIScrollViewのPaging Modeについての解説。
PageControl
今回のようなページめくりのサンプルコード。参考になる。

UIScrollView - サムネイル画像を並べて指でスクロールさせる

2010年7月5日月曜日 | Published in | 18 コメント

このエントリーをはてなブックマークに追加

UIScrollView について直接使ったことが無いので調べてみた。


情報&サンプル


iPhone OS Reference Library に解説とサンプルがある。
UIScrollView解説
Scroll View Programming Guide for iPhone OS
スクロールサンプル
Scrolling
2種類の UIScrollView を使ったサンプルプログラム。
サンプルは基本的なところが押さえられているので参考になる。


ポイント


UIScrollView を使うのは簡単で次の2つをやるだけでいい。
1. UIScrollView.contentSize にスクロール対象ビューの全体の大きさを設定する
2. スクロール対象ビューを UIScrollView へ追加する


検証


解説とサンプルを参考にして簡単なプログラムを組んでみた。複数の画像を横へ並べてスクロールするようにしてみた。


実装


UIImageViewを使わず、表示用に UIView のサブクラス ImageViewを用意した。渡された UIImageの配列を元に横方向へ画像を描画する。
@implementation ImageView

- (void)drawRect:(CGRect)rect {

 CGPoint p = CGPointZero;
 for (UIImage* image in imageList_) {
  [image drawAtPoint:p];
  p.x += image.size.width;
 }
}
これで次のようなビューができる(640x80ピクセル)。

nib を開き UIScrollView(320x80ピクセル)を配置し、File's Ownerのアウトレットへ接続しておく。

UIViewControllerの初期化コードで画像の準備と、これらの紐付けを行う。
- (void)viewDidLoad {
 
 NSMutableArray* imageList = [NSMutableArray array];
 for (int i=0; i < 8; i++) {
  UIImage* image = [UIImage imageNamed:
        [NSString stringWithFormat:@"image%04d.png", i+1]];
  [imageList addObject:image];
 }
 ImageView* imageView = [[ImageView alloc] initWithImageList:imageList];

 self.scrollView.contentSize = imageView.bounds.size;
 [self.scrollView addSubview:imageView];

 [imageView release];
}

これで終わり。あとは勝手にフリックをハンドリングしてスクロールしてくれる。

(イメージ)


追記)2011-06-21
サンプル追加
ImageViewTap at master from xcatsan/iOS-Sample-Code - GitHub

サンプルのイメージ


※このサンプルについては下記コメントを参照のこと。

loadView と nib

2010年7月4日日曜日 | Published in | 0 コメント

このエントリーをはてなブックマークに追加

UIViewControllerでは、nib を使わない場合のビューの初期化に loadViewが使える。

loadView


このメソッドは UIViewController.viewへアクセスがあった時で、かつ view==nil の場合に呼び出される。プログラムで viewを用意する時にはこのメソッドをオーバーライドして viewを用意する。一方、Interface Builder を使い viewを用意している場合はこのメソッドは使わず initWithNibName:bundle: を使う。


ポイント


  • このメソッドをオーバーライドすると nibファイルの読み込みが行われなくなる(これにはハマった)
  • loadView をオーバーライドする場合は必ず UIViewのサブクラスを用意して self.viewへ設定する。設定せずに viewDidLoad内で self.viewを参照すると無限ループに陥る


参考情報


UIViewController Class Reference - loadView:


.

-[NSArray indexOfObjectIdenticalTo:]

2010年7月3日土曜日 | Published in | 0 コメント

このエントリーをはてなブックマークに追加

indexOfObject: と indexOfObjectIdenticalTo:


NSArray のメソッド indexOfObject: と indexOfObjectIdenticalTo: についての質問が出ていた。

indexOfObject vs. indexOfObjectIdenticalTo - Stack Overflow

indexOfObject:は値等価(isEqual:)、indexOfObjectIdenticalTo: はアドレス等価とのこと。ほお、こんなメソッドがあったのか。


参考情報


NSArray Class Reference

iOS4からデバイス毎・解像度毎に用意した画像を自動選択する仕組みが導入された

2010年7月2日金曜日 | Published in | 0 コメント

このエントリーをはてなブックマークに追加

デバイス毎/解像度毎に画像を用意しておき、実行時のデバイスに合わせて適切な画像を自動選択する仕組みが iOS4 から導入された。

画像ファイルの命名規約


デバイス毎/解像度毎の画像を用意する場合、次の命名規約に従う。
標準解像度: <画像名><device_modifier>.<拡張子>
高解像度 : <画像名>@2x<device_modifier>.<拡張子>
[情報元] iPhone Application Programming Guide: Supporting High-Resolution Screens - Updating Your Image Resource Files

高解像度の場合は画像名の後ろに '@2x' を付ける。
(例)ButtonImage@2x.png

<device_modifier> は ~ipad や ~iphone が指定できる。

UIImageのメソッド、imageNamed:, imageWithContentsOfFile: などはこの命名規約を解釈して、基本となるファイル名を渡すと実行しているデバイスに合わせた画像を読み込んでくれる。例えば次のコードがあった場合。
UIImage* ibuttonImage = [UIImage imageNamed:@"ButtonImage"];
iPhone4で実行している場合、"ButtonImage@2x.png" が存在すればそちらを使う。iPhone3GSでは "ButtonImage.png"が使われる。


検証


iPhoneシミュレータを使い検証してみた。違いがわかるように同じ大きさの内容の異なる画像を2枚用意した。
BrowserIcon.png
BrowserIcon@2x.png

UIImageViewを用意して、これらの画像を表示する。

UIImage* icon = [UIImage imageNamed:@"BrowserIcon"];
 self.iconView.image = icon;

結果は次の通り。

iPhone3(シミュレータ)


iPhone4(シミュレータ)


どちらも意図通りの結果となった。なお iPhone4ではさらにスケーリング(縮小)が行われているのがわかる。そこで次のコードを追加してそれぞれの場合の scaleを見てみた。
NSLog(@"scale=%f", icon.scale);

iPhone3(シミュレータ)

scale=1.000000

iPhone4(シミュレータ)

scale=2.000000

UIImage.scale がそれぞれのケースで適切に設定されるのがわかる。

UIImage から縮小画像を生成する (2) iPhone4 高解像度対応

2010年7月1日木曜日 | Published in | 2 コメント

このエントリーをはてなブックマークに追加

[前回] Cocoaの日々: UIImage から縮小画像を生成する

前回作成したメソッドに手を入れて iPhone4向け高解像度対応を行う。

デバイス毎の解像度に対応した縮小


例えば 960x300 の縮小画像を作成する場合、iPhone 3G/3GS で横幅ぴったりに表示できる画像のサイズは 320 x 100 となる。一方、iPhone4の場合は 640 x 200 が望ましい。どちらか一方のデバイスをターゲットにするアプリの場合は特に問題ないが、両方のデバイスをターゲットとする場合はデバイスの解像度に合わせた縮小率を適用する必要がある。


UIGraphicsBeginImageContextWithOptions


iOS4 からは UIGraphicsBeginImageContextWithOptions() が導入されて、これを使うとデバイス毎の解像度の違いを吸収することができる。
UIKit Function Reference - UIGraphicsBeginImageContextWithOptions

この関数ではビットマップに適用する倍率を指定することができる。
(例)UIGraphicsBeginImageContextWithOptions(CGRectMake(100, 100), NO, 2.0);

この場合、実際に作成されるビットマップのサイズは 200x200(ピクセル)となる。この倍率(scale)は 0 を指定することができて、その場合はデバイスに適した倍率が自動的い採用される。現在のところ iPhone3G/3GS は 1.0、iPhone4 は 2.0 となる。


高解像度対応版 縮小処理


前回のコードに手を入れて UIGraphicsBeginImageContext() の代わりに UIGraphicsBeginImageContextWithOptions()を使うようにする。
#import <CoreGraphics/CoreGraphics.h>

@implementation UIImage (extension)

- (UIImage*)imageByShrinkingWithSize:(CGSize)size
{
 CGFloat widthRatio  = size.width  / self.size.width;
 CGFloat heightRatio = size.height / self.size.height;
 
 CGFloat ratio = (widthRatio < heightRatio) ? widthRatio : heightRatio;

 if (ratio >= 1.0) {
  return self;
 }

 CGRect rect = CGRectMake(0, 0,
        self.size.width  * ratio,
        self.size.height * ratio);
 
 UIGraphicsBeginImageContextWithOptions(rect.size, NO, 0.0); // 変更

 [self drawInRect:rect];

 UIImage* shrinkedImage = UIGraphicsGetImageFromCurrentImageContext();
 
 UIGraphicsEndImageContext();
 
 return shrinkedImage;
}


実行例


次の画像を縮小してみた。サイズ 320x480 ピクセル。
縮小後のサイズは iPhone3G/3GS で 80x120 ピクセルとする。

生成されるビットマップ画像のサイズがそれぞれのデバイスで異なることをiPhoneシミュレータを使って確認してみる。

検証に使ったコードの一部
UIImage* image = [UIImage imageNamed:@"sample1.png"];
 CGSize size = CGSizeMake(80, 120);
 
 UIImage* shrinkedImage = [image imageByShrinkingWithSize:size];
 NSLog(@"image.scale: %f, size:[%f, %f]",
    shrinkedImage.scale,
    shrinkedImage.size.width,
    shrinkedImage.size.height);
 
 NSLog(@"cgimage.size:[%d, %d]",
    CGImageGetWidth(shrinkedImage.CGImage),
    CGImageGetHeight(shrinkedImage.CGImage));
UIImage.size と CGImageGetWidth/Height をコンソールへ出力して見比べてみた。

iPhone3の結果(iPhoneシミュレータ)

image.scale: 1.000000, size:[80.000000, 120.000000]
cgimage.size:[80, 120]

iPhone4の結果(iPhoneシミュレータ)

image.scale: 2.000000, size:[80.000000, 120.000000]
cgimage.size:[160, 240]

シミュレータでは見た目の違いはわからないが、コンソールの出力からは予想通りiPhone4では scaleが 2.0 となっており、ビットマップのサイズも iPhone3の縦横2倍となっているのがわかる。一方で、UIImage.size は両者とも同じになっている。実は iOS4から UIImage.sizeの定義が変わっている。リファレンスによると iOS4 からはピクセルではなく、ポイントを返すようになっている。
In iPhone OS 4.0 and later, this value reflects the logical size of the image and is measured in points. In iPhone OS 3.x and earlier, this value always reflects the dimensions of the image measured in pixels.

UIImage Class Reference

単位が変わるなんてちょっとドラスティックな変更な気もするが、従来のコードの修正を最小限に抑えるという意味ではうまい方法かもしれない。

参考情報


iPhone Application Programming Guide: Supporting High-Resolution Screens
アプリを高解像度対応させる方法についての解説

人気の投稿(過去 30日間)