Archive for the ‘iPhone apps’ Category

Navigation-basedだけど最初の画面はTableViewにしたくないとき

2011年10月27日

Navigation-based applicationでプロジェクトを作成したが、最初の画面はTableViewにしたくないとき

  1. 新たにUIViewControllerクラスを追加(XIBファイル付きで)
  2. MainWindow.xib の Objects 内にある Navigation Controller の下の Root View Controller について
    1. 名前を変える
    2. Attributes Inspector にある NIB Name を、上で作成したXIB Name に変える

      Change NIB name of RootViewController

      RootViewController の NIB name を変更

    3. Identiy Inspector にある Class を、上で作成したクラスに変える

      Change class name of RootViewController

      Class name も変える

  3. MainWindow.xib の Objects 内にある Navigation Controller の下の Root View Controller について
    1. AppDelegate.m の – (void)awakeFromNib に RootViewControllerに関するコードが有るので、これは削除する。ここで行われている TableViewController に managedObjectContext を渡す処理は、TableViewController をinitialize するところで行う。
    2. Root View Controller は、不要なら削除

Picasaを使う(iPhone)

2011年9月16日

今度は iPhone アプリで Picasa Web Album を使うサンプルを作成した。(ソース

Google data API のObjective-C 版は以下の場所に紹介してある。
http://code.google.com/p/gdata-objectivec-client/

ソースをダウンロードするとサンプルコードも一緒についてくるが、iOS 用のサンプルは、OAuth のサンプルしかない。Picasa Web Album にアクセスするサンプルはOS X用のサンプル(GooglePhotoSample)がある。

OS X 用のサンプルプログラム

これを参考にiOS用に書き換えるしかなさそうだ。

プロジェクトの作成

今回は単純にするために、Window based application で作成した。Window は TextView だけで構成され、取得したデータをこの TextViewに表示するだけの簡単なものにする。

プロジェクトの設定

まずは、Google Data API をリンクするための設定。Google Data API ライブラリのプロジェクトは GData.xcodeproj。この中に、ライブラリはOSX用のGDataFrameworkとiOS用のGDtataTouchStaticLibがある。GooglePhotoSampleのプロジェクトには、このライブラリのプロジェクト( GData.xcodeproj)自体が取り込まれている。これに倣って、GData.xcodeprojをプロジェクトに追加する。

GData.xcodeprojを追加

Target Dependencies

GDataFramework の代わりに GDtataTouchStaticLib を設定。

OS X 版はGDataFramework

iOS版はGDataTouchStaticLibにする

Link Binary With Libraries

GDataFramework の代わりに GDtataTouchStaticLib を設定。
さらに、libxml2 も必要だった。

OS X版はGDataFramework

iOS版はlibGDataTouchStaticLibとlibxml2が必要

Header Search Path

OSXでは Framework Search Path を指定する。Framework にヘッダファイルも含まれるためだろう。

iOSでは、実際のヘッダファイルの場所を指定。API の Source フォルダの下(Recursiveに指定)と、libxml2 のフォルダを指定する。なお、Source フォルダの場所を指定するために、GDATA_SRC というユーザー定義を作成した。

OS X

iOS

ヘッダファイルのimport

OSX版のサンプルでは、

#import "GooglePhotosSampleWindowController.h"
#import "GData/GDataServiceGooglePhotos.h"
#import "GData/GDataEntryPhotoAlbum.h"
#import "GData/GDataEntryPhoto.h"
#import "GData/GDataFeedPhoto.h"

このように GData/ をつけてヘッダファイルを指定していた。Sourceの下にある実際のヘッダファイルは GData というフォルダの下にはないが、このような書き方が可能なのは、デッダファイルはFrameworkに含まれているからだと思われる。

iOS版ではこのような書き方はできないが、Header Search Path に実際のヘッダファイルの場所を再帰的に検索するよう指定したので、フォルダの階層は意識せず、ただヘッダファイル名だけを指定すればよい。

処理

OSX版のサンプルでは、ユーザー名とパスワードを入力してボタンを押すと、アルバムの一覧を表示し、選択されたアルバムの情報と写真の一覧を表示し、画像のアップロードなども可能だが、今回はまず、ただAPIが使えることを確かめたかっただけなので、できるだけシンプルに、だたアルバムの情報を取得して表示するだけにした。OSX版のソースから、アルバムの情報を取得する処理だけを取り出してコピーした。ユーザー名とパスワードはソース内に直書き(なので、事項する際は自分のアカウントで書き換えてください)、アルバムの一覧を取得して、リストの先頭のアルバムの情報だけを表示する。

実行画面

最初の行はアルバムのリストで、この例では1つ(DropBox)だけ。このDropBoxの情報を下に表示している。

ドロップダウンリストをNavigatorControl+TableViewで実装する

2011年7月17日

「ゴルフのスコアカウンター(iPhone版)」で、PARの選択にドロップダウンリスト風にTableViewを使うように修正してみた。Windowベースで作成したアプリをNavigatorControl+TableViewで実装する仕組みに変更する。

ソース

修正前のレイアウト

修正前のレイアウト

修正後の画面

修正後の画面

1.NavigationControllerを nib ファイルに追加。

右側のライブラリからNavigationControllerを網の上にドロップすると、画面のイメージと左端にオブジェクトが追加される。

Navigatorコントロールを追加

Navigatorコントロールを追加

2.Navigation Controller の Output を AppDelegate に追加

(1)View>Editor>Assistant にする

(2)nibウィンドウからNavigationControllerを右クリックしてAppDelegateのヘッダーファイルにドラッグ&ドロップ

NavigationControllerのOutletを追加

NavigationControllerのOutletを追加

3.Window の rootViewController をNavigator Controller にする

(1)nibウィンドウで Window を選択

(2)Connections Inspector の rootViewController の右側の丸印をドラッグして、2で追加した Navigation Controller の上にあわせる。

rootViewControllewを設定

rootViewControllewを設定

4.TableViewControllerを上のnib に追加

右側のライブラリからNavigationControllerを網の上にドロップすると、画面のイメージと左端にオブジェクトが追加される。

5.TableViewController のクラスファイルを追加(RootTableViewControler)

6.Window にのっていたUIのコントロールを4で追加した TableViewController に移す

(1)TableViewController のヘッダー部分に下地となる View を追加し、その上にWindowからPAR選択部分の上にあるコントロール群をカット&ペースト

(2)TableViewController のフッター部分に下地となる View を追加し、その上にWindowからPAR選択部分の下にあるコントロール群をカット&ペースト

7.Controllerに作成していた、各コントロールのOutletとイベントハンドラをRootTableViewControlerにコピーし、nib上でOutletとコントローラー、およびイベントハンドラの結びつけを行う。

8.RootTableViewControler の Output を AppDelegate に追加

(1)View>Editor>Assistant にする

(2)nibウィンドウから RootTableViewControler を右クリックしてAppDelegateのヘッダーファイルにドラッグ&ドロップ

9.最初に表示される View を設定

ApplicationDelegate の didFinishLaunchingWithOptions で 2で作成したNavigationController の Outlet に 7で作成した RootTableViewControler の view を initWithRootViewController する。

10.RootTableViewControler に、dataSource のメソッドを実装。

★アイテムは1つしかないので。

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
  // Return the number of sections.
  return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
  // Return the number of rows in the section.
  return 1;
}

★メニュー内の各セルのスタイルとテキストを設定。サブメニューがあることを示す”>”を表示し(UITableViewCellAccessoryDisclosureIndicator)、現在の値(詳細)も表示するスタイル(UITableViewCellStyleValue1)に設定。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
  static NSString *CellIdentifier = @"Cell";

  UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
  if (cell == nil) {
    cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
  }

  // Configure the cell...
  cell.textLabel.text = @"PAR:";
  cell.detailTextLabel.text =
  [NSString stringWithFormat:@"%d",m_score_table[m_hole - 1][SCORE_TABLE_PAR]];

  cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;

  return cell;
}

11.nib に もう一つの TableViewController を追加、PAR数選択用

12.上の TableViewController のクラスファイルを追加(ParSelTableViewControler)

13.ParSelTableViewControler の Output を RootTableViewControler に追加

14.RootTableViewControler の didSelectRowAtIndexPath に、リストが選択されたときの動作を記述。PAR選択用のView(ParSelTableViewControler の view)に移動する。

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
  // Navigation logic may go here. Create and push another view controller.
  golfscntAppDelegate * app = (golfscntAppDelegate*)[UIApplication sharedApplication].delegate;
  [app.navigationController pushViewController:parSelTableViewController animated:YES];
}

15.PAR選択用ViewのParSelTableViewControler に、dataSource のメソッドを実装。
★アイテムは3つ。

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
  // Return the number of sections.
  return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
  // Return the number of rows in the section.
  return 3;
}

★スタイルは標準。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
  static NSString *CellIdentifier = @"Cell";

  UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
  if (cell == nil) {
    cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
  }

  // Configure the cell...
  int sel = indexPath.row;
  switch (sel) {
    case 0:
      cell.textLabel.text = @"PAR 3";
      break;
    case 1:
      cell.textLabel.text = @"PAR 4";
      break;
    case 2:
      cell.textLabel.text = @"PAR 5";
      break;
    default:
      break;
  }
  return cell;
}

16.ParSelTableViewControler の didSelectRowAtIndexPath に、リストが選択されたときの動作を記述。データを更新し、元のView(RootTableViewControler の view)に移動する。

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Navigation logic may go here. Create and push another view controller.
    golfscntAppDelegate * app = (golfscntAppDelegate*)[UIApplication sharedApplication].delegate;
    RootTableViewController* c = app.rootTableViewController;
    int hole = c->m_hole;
    switch (indexPath.row) {
        case 0:
            c->m_score_table[hole - 1][SCORE_TABLE_PAR]=3;
            break;
        case 1:
            c->m_score_table[hole - 1][SCORE_TABLE_PAR]=4;
            break;
        case 2:
            c->m_score_table[hole - 1][SCORE_TABLE_PAR]=5;
            break;
        default:
            break;
    }
    [app.navigationController popViewControllerAnimated:YES];
    [c update_display];
  }
}

17.画面データを更新するタイミングで、tableView reloadData を呼び出し、テーブルに変更後のデータが反映されるようにする。

iPhonenのドロップダウンリスト(またはメニュー)=Navigation Controller + Table View Controller だった

2011年7月5日

iPhonenのUIにドロップダウンリストやメニューがないので困っていたが、その機能は Navigation Controller + Table View Controller で実装できるらしい。

ドロップダウンやメニューだと、同じ画面上に選択肢がベロッと出てくるが、Navigation Controller + Table View Controller では、選択肢だけの別画面に移動するような感じになる。確かに狭い画面で操作することを考えれば、こちらのほうが理にかなっている気がする。でも、実装が面倒くさそうで・・・慣れるまでは苦労しそうだ。

まず最初に、1画面でいけるのか、あるいは複数画面になるのか、を決めておかないと、後で変更するのは面倒だ。ドロップダウンやメニューで選択させる場合は複数画面確定。・・・ということは、新規作成するときに、とりあえずNavigation based アプリで作っておくのがいいのかもしれない。Navigation based アプリが新規作成画面の一番左にあるのは、そういうことだったのか・・・。

ゴルフのスコアカウンター(iPhone版)

2011年5月28日

ゴルフのスコアカウンターのiPhone版。

ソース

●画面のレイアウト

layout

レイアウト

Window baseアプリケーションとして作成。図のように配置した。PARの値を選択するのにドロップダウンリストを使いたかったが、ドロップダウンリストがなかった。仕方なくSegmented controlを使用した。

●クラス構成

xibファイルのFileOwnerはAppDelegateなので、イベントハンドラはここに書くこともできたが、今回はあえてGUIイベントハンドラとして、Controllerという名前のNSObjectの派生クラスを作成した。同時にxibファイルにもObjectを追加し、Custom Class にControllerクラスを設定して連携させ、AppDelegateにOutletとして追加することでインスタンス化する。(一方、Viewを使った場合はView毎にxibファイルを作成するので、UIViewControllerの派生クラスはxibファイルのFileOwnerに指定する。よって、ControllerのObjectを別途xibに追加しなくてよい。アプリ初期化時にinitWithNibNameにxibファイル名を指定して呼び出すことで、xibを読み込んでインスタンス化する。)

●データの初期化

スコアのデータは2次元配列に保持する。Controllerを分けたので、モデルも別にしようかとは思ったが、面倒なのでControllerに持たせた。パーの値は4を初期値として設定する。この初期化処理は、AppDelegateのdidFinishLaunchingWithOptionsから呼び出す。

●イベント処理

前述のControllerクラスに各ボタンが操作された際のActionを定義し、xibで各ボタンのイベントと関連づける。

●課題

ドロップダウンリストの実装方法・・・。リストから選択させるときは何を使うのか?iPhoneを持っていないのでよくわからないが、買うと高いし・・・。サンプルなどをよく調べる必要がある。

Cocoa Application Tutorial の Converterアプリを iPhone に移植

2011年4月9日

Cocoa Application Tutorial (下)の Converterアプリを iPhone に移植してみた。

CocoaTutrial

CocoaTutrial

プロジェクトの選択

NewProjectWindowBased

NewProjectWindowBased

プロジェクトの新規作成では Window-based Application を選択。
このあとは、Cocoa Application Tutorial の指示通りにすすめればOK。(ただし、コントロールのクラス名はNSTextField → UITextField という要領で置き換える。)

変更すべき点

しかし、Controllerの定義と実装には、NSTextField と UITextField の違いにより若干変更が必要。

【ConverterController.h】
★NSTextField を UITextField に置き換える。

@interface ConverterController : NSObject {
	IBOutlet UITextField *amountField;
	IBOutlet UITextField *dollarField;
	IBOutlet UITextField *rateField;
	Converter *converter;
}
- (IBAction)convert:(id)sender;
@end

【ConverterController.m】
★NSTextField にはあるが UITextField にはないメソッドを書き換える。

@implementation ConverterController
- (IBAction)convert:(id)sender {
    float amount;
    converter = [[Converter alloc]init]; 

//    [converter setSourceCurrencyAmount:[dollarField floatValue]];
// UITextField には floatValue がない
    [converter setSourceCurrencyAmount: [dollarField.text floatValue]]; 	

//    [converter setRate:[rateField floatValue]];
// UITextField には floatValue がない
    [converter setRate: [rateField.text floatValue]]; 	

    amount =   [converter convertCurrency];

//    [amountField setFloatValue:amount];
// UITextField には floatValue がない
    [amountField setText: [[NSNumber numberWithFloat: amount] stringValue]]; 

//    [rateField selectText:self];
// UITextField には selectText がない。
// 書き換えができなかったので、保留。

// iOS にはガベージコレクタがないので、リリースする必要がある。
	[converter release];
}
@end


また、数値の入力フィールドについては、キーボードを Number&Punctuation に設定した方が便利。


シミュレーターでの実行結果