読者です 読者をやめる 読者になる 読者になる

ニペブ - iPhone / iOSアプリ開発

iPhone / iOS アプリ開発方法と技術情報、入門レベルの初心者向けの記事を書いています。

自分の信念を貫いて成功をつかみたい

TEDで成功するための素晴らしいプレゼンを見たので共有します。
自分の信念を貫いて、信念を信じてくれる人と一緒に働くことにより成功をつかめるということが分かりました。

TED動画

1500万回も見られている動画なので是非見て何かを感じてもらえれば嬉しいです。

サイモン シネック: 優れたリーダーはどうやって行動を促すか | Video on TED.com

仕事を求めている人を雇うのではなく、自分の信じてくれる人を雇うことを目指すべき

仕事ができるというだけの理由で採用した人は、お金のために働くでしょう。
自分の信じてくれる人を雇えば、その人は血と汗と涙を流して働くのです。

ライト兄弟のストーリー

サミュエル・ピエールポント・ラングレーについては知らない方が多いでしょう。
20世紀の初頭には有力動力飛行の追求は誰もが試みていました。サキュエルは成功のレシピというものを備えていまいした。誰かに聞いたとしましょう。「製品や会社が失敗した理由は何ですか?」。帰って来る答えはいつもこの3点です。
「資金不足」「人材不足」「市場環境の悪化」
詳しく見てみましょう。
サミュエルは5万ドルの資金を陸軍省から与えられ飛行機会を開発していました。資金は問題なし。
ハーバード大に在籍し、スミソニアン博物館で働いていた彼は人脈豊富です。金にものを言わせて最高の人材を集めました。
市場の環境は絶好。ニューヨークタイムズは彼を追いかけ回し、ラングレーを応援していました。

一方、ライト兄弟のオーヴィルとウィルバーは成功のレシピとはまるで無縁でした。
お金がなく、夢に挑む資金は自分たちの自転車店から持ち出しで、ライト兄弟のチームの誰ひとりとして大学を出ていませんでした。オーヴィルとウィルバーも違いました。そしてニューヨークタイムズに追いかけ回されたりもしません。
違っていたことは、オーヴィルとウィルバーが大義と理想と信念に動かされていたということです。
彼らはもしこの飛行機体を作り上げることができたら、それは世界を変えることになると信じていました。
しかし、サミュエルは違っていました。彼が求めていたのは富と名声です。それによって得られるものが目的あり、富を追求していたのです。そしてどうなったのでしょうか。
ライト兄弟の夢を信じた人々は、血と汗と涙を流してともに働きました。もう一方のチームはただ給与のために働きます。
ライト兄弟は外へテストに出かけるたびに部品は5セットずつ持っていったと言います。夕食に帰るまでには5回ぐらい壊れるようなものだったからです。

そして、ついに1903年の12月17日のこと、ライト兄弟は初飛行に成功、それをその場で目撃した者もいませんでした。そのことが広く伝えられたのは数日経った後です。
そしてラングレーの動機が適切でなかったことを示すさらなる証拠にはライト兄弟が飛行した日に彼は諦めたのです。彼はこうも言えたはずでした。
「連中はよくやった。我々の手でもっと改良してやろうじゃないか。」でもそうはせず、一番になれず、金持ちにもなれず、有名にもなれなかったので、彼は諦めました。

(iOS/iPhoneアプリ開発) CSVファイルをパースする

完成イメージ

iPhoneのアプリ開発でCSVファイルをパースするライブラリがあったのでメモします。
区切り文字をカンマ(,)以外に変えることもできますし、ダブルクォーテーションに囲まれて文字列("A,B")などにも対応しています。

導入方法

  1. http://projectswithlove.com/projects/CSVImporter.zip からダウンロードする。
  2. DLしたファイルを解凍し、CSVParser.hCSVPaser.m を自分のプロジェクトにコピーする。


自分のプロジェクトがARCが無効の場合、ARCを無効にする。

  1. ビルド設定の、Build Phaseタブの、Compile Sources 設定を開きます
  2. CSVPaser.mコンパイルオプションに -fno-objc-arc を入力します

使い方

コメントとソースコードを見ながらイメージを掴んでください。

// CSVファイルのパスを取得
NSString *filePath = [homeDir stringByAppendingPathComponent:@"(CSVファイル名).csv"];

// UTF8 エンコードに変換した文字列に変換
// (ファイル内容イメージ)
// id, name
// 1, Oops!
// 2, "well, well, well"
// ....
NSString *text = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];

// Parserを作成する
// 区切り文字を","に設定、ヘッダーは存在する
CSVParser *parser = [[CSVParser alloc] initWithString:text separator:@"," hasHeader:YES fieldNames:nil];

// CSVファイルにパースする
// 各列を配列にし、各列の内容はNSDictonary型で格納されている
NSArray *lines = [parser arrayOfParsedRows];

// 各列を処理する
NSDictionary *row = nil;
for (int i = 0; i < [lines count]; i++) {

    // 列のNSDictonary型を取得
    category = lines[i];
    
    // 値の取得
    NSInteger id = [[category objectForKey:@"id"] integerValue]];
    NSString *name = [row objectForKey:@"name"];
}

(はてなブログ/はてなダイアリー) サイドバーを右側から左側にする方法

完成イメージ

はてなブログの右側にあったサイドバーが。。。
f:id:nipe880324:20131229180447p:plain

左側に!
f:id:nipe880324:20131229180630p:plain

設定方法

1. はてなブログの管理画面から「デザイン」=>「カスタマイズ」=>「デザインCSS」をクリックし、CSSが記載出来るフレームを表示させる。
2. 下記のCSSコードを追加し、「変更を保存する」ボタンを押す。

使用しているデザインが異なると下のソースコードで上手く変更出来ない可能性もあるのであしからず。

/* sidebar changes right side to left side. */
#blog-title, #wrapper {
    float: right;
}

#box2 {
  border-right: 1px solid #ddd;
}

/* <system section="theme" selected="bordeaux"> */
@import "/css/theme/bordeaux/bordeaux.css";
/* </system> */

#content {
  color: #3d3d3d;
  margin: 0 auto;
  background: #fff;
}

(iOS/iPhoneアプリ開発) UITableViewCellの自作カスタムセルを作成する

完成イメージ

自作のカスタムセル(UITableViewCell)にラベル(UILabel)とテキストフィールド(UITextField)とスイッチ(UISwitch)を表示させています。
f:id:nipe880324:20131227144659p:plain:w320

環境

StoryBoardの作成

まずは、次のようにStoryBoardを作成します。
f:id:nipe880324:20131227145132p:plain

  1. TableViewControllerを追加
  2. TableViewControllerのClassに「CustomCellOneViewController」を記載
  3. そのTableViewCellのReuse Identifierに「CustomOneCell」を記載(StyleがCustomであることを一応確認)
  4. TableViewCellの下にあるContentViewに「Label」、「Text Field」、「Switch」を追加

カスタムセル(カスタム UITableViewCell)の作成

次にCustomCellOneViewController.h に次のカスタムセル用のクラスを作成します。

// カスタムセル
@interface CustomOneCell : UITableViewCell

@end

さらに、CustomCellOneViewController.mにも実装を記載します。中は空ですがw

// カスタムセル
@implementation CustomOneCell

@end

StoryBoardの作成(再び)

  1. UITableViewCellのClassに上記で作ったクラス名「CustomOneCell」を記載します。
  2. StoryBoardとCustomCellOneViewController.hの2つのビューを表示し、「Ctrl + ドラッグ」を使って、CustomOneCellに「Label」、「TextField」、「Switch」を追加します。

CustomCellOneViewController.hに次のような記述が記載されます。

// カスタムセル
@interface CustomOneCell : UITableViewCell

@property (weak, nonatomic) IBOutlet UILabel *label;
@property (weak, nonatomic) IBOutlet UITextField *textField;
@property (weak, nonatomic) IBOutlet UISwitch *switchCtrl;

@end

CustomCellOneViewController.hの作成

次に、CustomCellOneViewController.h を作成します。
特に追記することはありません。詳細はコメントを確認してください。

// カスタムセル
@interface CustomOneCell : UITableViewCell

// カスタムセルのパーツ
@property (weak, nonatomic) IBOutlet UILabel *label;
@property (weak, nonatomic) IBOutlet UITextField *textField;
@property (weak, nonatomic) IBOutlet UISwitch *switchCtrl;

@end

// コントローラ部分
@interface CustomCellOneViewController : UITableViewController

@end

CustomCellOneViewController.mの作成

次に、CustomCellOneViewController.m を作成します。
UITableViewControllerを継承して作ったため、最初からソースコードが記載されています。
しかし、コメントアウト部分を削除し、若干修正した実際のソースコードです。
細かくコメントを記載してますのでそれを見れば大体分かると思います。

#import "CustomCellOneViewController.h"

// カスタムセル
@implementation CustomOneCell

@end

// コントローラ部分
@interface CustomCellOneViewController ()

@end

@implementation CustomCellOneViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

#pragma mark - Table view data source

// セル数を返す
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    // 本来はデータベースなどから配列を取得して、countの値を返すとよい
    return 5;
}

// セルの内容を返す
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"CustomOneCell";
    // カスタムセルにキャスト。キャストすることによりカスタムセルのpropertyが使える
    CustomOneCell *cell = (CustomOneCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
    
    // セルの値を設定
    cell.label.text = [NSString stringWithFormat:@"No%d", indexPath.row+1];   // Label
    cell.textField.placeholder = @"値を入れてください";  // UITextField
    cell.switchCtrl.on = indexPath.row % 2; // UISwitch
    
    return cell;
}

@end

UITableViweなどのUIKitに関するサンプルのソースコードGithubに置いてあります。よろしければ、覗いてみてください。
yanagi0324/test-uikit · GitHub

補足

もし、カスタムセル上のSwitchのイベントを処理したい場合、MVCの原則からイベント処理ロジックはCell側(View)ではなくはController側に記載したがいいと思います。そして、Cellの内容を設定する箇所(cellForRowAtIndexPath)でdelegateなどを登録します。

参考情報

分かりづらい箇所やご質問などありましたら、 コメントやメールアドレスにご連絡いただけると嬉しいです。

(iOS/iPhoneアプリ開発) グラフ描画ライブラリ CorePlot でX軸に日付や月を表示させる方法

完成イメージ

棒グラフが表示され、X軸に月が表示されています。
f:id:nipe880324:20131227134126p:plain:w320

環境

xcodeのプロジェクトにCorePlotを導入する

毎度のことですが導入していない人のために、記載しておきます。
次のサイト参考にして、導入しました。
core-plotでグラフを描いてみよう。-入門編- | Developers.IO
現在は「Downloads -> CorePlot_1.4.zip」でした。

X軸に日付や月を表示させる

まずは、ViewController.h を作成します。上記の過去記事の棒グラフと同じですが再掲します。
CorePlotのヘッダを追加し、必要な変数を宣言しておきます。ここは、こうなるんだなぐらいで特に説明はないです。

#import <UIKit/UIKit.h>
#import "CorePlot-CocoaTouch.h"

@interface BarChartViewController : UIViewController
<CPTPlotDataSource, CPTBarPlotDelegate>
{
@private
    // グラフ表示領域(この領域に棒グラフを追加する)
    CPTGraph *graph;
}

// 棒グラフで表示するデータを保持する配列
@property(nonatomic, strong) NSMutableArray *dataForBar;    //1つめの棒グラフ用
@property(nonatomic, strong) NSMutableArray *dataForBar2;   //2つめの棒グラフ用

@end



次に、ViewController.m を作成します。
基本は「CorePlotの過去記事」の棒グラフです。
細かくコメントを記載してますのでそれを見れば大体分かると思います。

X軸に日付や月を表示させるためには、CPTXYAxisSetに表示させたい日付や月をラベルとして設定する必要があります。
次のメソッドで設定しています。今回は月を表示させていますが、ラベルとして日付を設定させればX軸に日付を表示させる事が可能です。

- (void) arbitraryLabels:(CPTGraph*)cptGraph;

そこを中心に見れば難しくないので実装ができると思います。
実際のソースコードです。

#import "BarChartViewController.h"

@interface BarChartViewController ()

@end

@implementation BarChartViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    // グラフに表示するデータを生成
    // 1つめの棒グラフ用のデータ。12ヶ月の棒グラフのX軸データ
    self.dataForBar = [NSMutableArray arrayWithObjects:
                       [NSNumber numberWithDouble:-2.0],[NSNumber numberWithDouble:-1.0],[NSNumber numberWithDouble:0.0],
                       [NSNumber numberWithDouble:1.0],[NSNumber numberWithDouble:2.0],[NSNumber numberWithDouble:3.0],
                       [NSNumber numberWithDouble:4.0],[NSNumber numberWithDouble:5.0],[NSNumber numberWithDouble:6.0],
                       [NSNumber numberWithDouble:7.0],[NSNumber numberWithDouble:8.0],[NSNumber numberWithDouble:9.0],
                       nil];
    // 2つめの棒グラフ用のデータ。12ヶ月の棒グラフのX軸データ
    self.dataForBar2 = [NSMutableArray arrayWithObjects:
                       [NSNumber numberWithDouble:9.0],[NSNumber numberWithDouble:8.0],[NSNumber numberWithDouble:7.0],
                       [NSNumber numberWithDouble:6.0],[NSNumber numberWithDouble:5.0],[NSNumber numberWithDouble:4.0],
                       [NSNumber numberWithDouble:3.0],[NSNumber numberWithDouble:2.0],[NSNumber numberWithDouble:1.0],
                       [NSNumber numberWithDouble:0.0],[NSNumber numberWithDouble:-1.0],[NSNumber numberWithDouble:-2.0],
                       nil];
    
    
    // ホスティングビューを生成する
    CPTGraphHostingView *hostingView =
    [[CPTGraphHostingView alloc] initWithFrame:CGRectMake(0, 0, 320, 320)];
    hostingView.collapsesLayers = NO;
    // 画面にホスティングビューを追加
    [self.view addSubview:hostingView];

    // グラフを生成
    graph = [[CPTXYGraph alloc] initWithFrame:hostingView.bounds];
    hostingView.hostedGraph = graph;
    
    // グラフのテーマを作成して、設定
    // その他のテーマ名 kCPTPlainBlackTheme:黒いテーマ, kCPTDarkGradientTheme:グレーなテーマ
    //                kCPTSlateTheme:グレーなテーマ, kCPTStocksTheme
    CPTTheme *theme = [CPTTheme themeNamed:kCPTPlainWhiteTheme];    // シンプルな白いテーマ
    [graph applyTheme:theme];

    // グラフのボーダー設定
    graph.plotAreaFrame.borderLineStyle = nil;
    graph.plotAreaFrame.cornerRadius    = 0.0f;
    graph.plotAreaFrame.masksToBorder   = NO;
    
    // パディング
    graph.paddingLeft   = 0.0f;
    graph.paddingRight  = 0.0f;
    graph.paddingTop    = 0.0f;
    graph.paddingBottom = 0.0f;
    
    graph.plotAreaFrame.paddingLeft   = 60.0f;
    graph.plotAreaFrame.paddingTop    = 60.0f;
    graph.plotAreaFrame.paddingRight  = 20.0f;
    graph.plotAreaFrame.paddingBottom = 65.0f;

    //プロット間隔の設定
    CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace *)graph.defaultPlotSpace;
    //Y軸は-3〜10の値で設定
    plotSpace.yRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromInt(-3) length:CPTDecimalFromInt(13)];
    //X軸は0〜7の値で設定
    plotSpace.xRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromInt(0) length:CPTDecimalFromInt(12)];
     
    // テキストスタイル
    CPTMutableTextStyle *textStyle = [CPTTextStyle textStyle];
    textStyle.color                = [CPTColor colorWithComponentRed:0.447f green:0.443f blue:0.443f alpha:1.0f];
    textStyle.fontSize             = 13.0f;
    textStyle.textAlignment        = CPTTextAlignmentCenter;
    
    // ラインスタイル
    CPTMutableLineStyle *lineStyle = [CPTMutableLineStyle lineStyle];
    lineStyle.lineColor            = [CPTColor colorWithComponentRed:0.788f green:0.792f blue:0.792f alpha:1.0f];
    lineStyle.lineWidth            = 2.0f;
    
    // X軸のメモリ・ラベルなどの設定
    CPTXYAxisSet *axisSet = (CPTXYAxisSet *)graph.axisSet;
    CPTXYAxis *x          = axisSet.xAxis;
    x.axisLineStyle               = lineStyle;
//    x.majorTickLineStyle          = lineStyle;                // ラベルを設定しているため無効ぽい
//    x.minorTickLineStyle          = lineStyle;                // ラベルを設定しているため無効ぽい
    x.majorIntervalLength         = CPTDecimalFromString(@"2"); // X軸ラベルの表示間隔
    x.orthogonalCoordinateDecimal = CPTDecimalFromString(@"0"); // X軸のY位置
    x.title                       = @"X軸";
    x.titleTextStyle = textStyle;
    x.titleLocation               = CPTDecimalFromFloat(5.0f);
    x.titleOffset                 = 36.0f;
//    x.minorTickLength = 5.0f;                   // X軸のメモリの長さ ラベルを設定しているため無効ぽい
//    x.majorTickLength = 9.0f;                   // X軸のメモリの長さ ラベルを設定しているため無効ぽい
    x.labelTextStyle = textStyle;
    
    // Y軸のメモリ・ラベルなどの設定
    CPTXYAxis *y = axisSet.yAxis;
    y.axisLineStyle               = lineStyle;
    y.minorTickLength = 5.0f;                   // Y軸のメモリの長さ
    y.majorTickLength = 9.0f;                   // Y軸のメモリの長さ
    y.majorTickLineStyle          = lineStyle;
    y.minorTickLineStyle          = lineStyle;
    y.majorIntervalLength         = CPTDecimalFromFloat(1.0f);  // Y軸ラベルの表示間隔
    y.orthogonalCoordinateDecimal = CPTDecimalFromFloat(0.0f);  // Y軸のX位置
    y.title                       = @"Y軸";
    y.titleTextStyle = textStyle;
    y.titleRotation = M_PI*2;
    y.titleLocation               = CPTDecimalFromFloat(10.5f);
    y.titleOffset                 = 25.0f;
    lineStyle.lineWidth = 0.5f;
    y.majorGridLineStyle = lineStyle;
    y.labelTextStyle = textStyle;

    // 2つめの棒グラフの作成と設定
    // horizontalBars:BOOL => YESの場合、横棒グラフ。NOの場合、縦棒グラフ。
    CPTBarPlot *barPlot = [CPTBarPlot tubularBarPlotWithColor:[CPTColor colorWithComponentRed:1.0f green:1.0f blue:0.88f alpha:1.0f] horizontalBars:NO];
    barPlot.fill = [CPTFill fillWithColor:[CPTColor colorWithComponentRed:0.573f green:0.82f blue:0.831f alpha:0.50f]]; // バーの色を設定。上記のカラーが上塗りされる。
    barPlot.identifier = @"Plot1";                      // 1つめの棒グラフの識別子を設定
    barPlot.lineStyle = lineStyle;                      // ラインスタイルを設定
    barPlot.baseValue  = CPTDecimalFromString(@"0");    // グラフのベースの値を設定
    barPlot.dataSource = self;                          // データソースを設定
    barPlot.delegate = self;
    barPlot.barWidth = CPTDecimalFromFloat(0.3f);       // 各棒の幅を設定
    barPlot.barOffset  = CPTDecimalFromFloat(0.3f);     // 各棒の横軸からのオフセット値を設定
    [graph addPlot:barPlot toPlotSpace:plotSpace];      // グラフに棒グラフを追加

    // 2つめの棒グラフの作成と設定
    CPTBarPlot *barPlot2 = [CPTBarPlot tubularBarPlotWithColor:[CPTColor colorWithComponentRed:1.0f green:1.0f blue:0.88f alpha:1.0f] horizontalBars:NO];
    barPlot2.fill = [CPTFill fillWithColor:[CPTColor colorWithComponentRed:0.780f green:0.50f blue:0.531f alpha:0.50f]]; // バーの色を設定。上記のカラーが上塗りされる。
    barPlot2.identifier = @"Plot2";                      // 2つめの棒グラフの識別子を設定
    barPlot2.lineStyle = lineStyle;                      // ラインスタイルを設定
    barPlot2.baseValue  = CPTDecimalFromString(@"0");    // グラフのベースの値を設定
    barPlot2.dataSource = self;                          // データソースを設定
    barPlot2.delegate = self;
    barPlot2.barWidth = CPTDecimalFromFloat(0.3f);       // 各棒の幅を設定
    barPlot2.barOffset  = CPTDecimalFromFloat(0.6f);     // 各棒の横軸からのオフセット値を設定
    [graph addPlot:barPlot2 toPlotSpace:plotSpace];      // グラフに棒グラフを追加

    
    // 任意の文字列のラベルを表示する
    [self arbitraryLabels:graph];
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

#pragma mark -
// 任意の文字列のラベルを表示する
- (void) arbitraryLabels:(CPTGraph*)cpgGraph
{
    CPTXYAxisSet *axisSet = (CPTXYAxisSet *)cpgGraph.axisSet;
    
    NSMutableArray *labels = [NSMutableArray arrayWithCapacity:12];
    int idx = 1;
    for (NSString *year in @[@"1月",@"2月",@"3月",@"4月",@"5月",@"6月",@"7月",@"8月",@"9月",@"10月",@"11月",@"12月"]) // ラベルの文字列
    {
        CPTAxisLabel *label = [[CPTAxisLabel alloc] initWithText:year
                                                       textStyle:axisSet.xAxis.labelTextStyle];
        label.tickLocation = CPTDecimalFromInt(idx); // ラベルを追加するレコードの位置
        label.offset = 5.0f; // 軸からラベルまでの距離
        [labels addObject:label];
        ++idx;
    }
    // X軸に設定
    axisSet.xAxis.axisLabels = [NSSet setWithArray:labels];
    axisSet.xAxis.labelingPolicy = CPTAxisLabelingPolicyNone; // これ重要
    axisSet.xAxis.labelRotation  = M_PI / 3;                // 表示角度

}


#pragma mark Plot Data Source Methods

// グラフに使用する棒グラフのデータ数を返す
-(NSUInteger)numberOfRecordsForPlot:(CPTPlot *)plot
{
    return [self.dataForBar count];
}

// 各棒の設定値を返す
-(NSNumber *)numberForPlot:(CPTPlot *)plot field:(NSUInteger)fieldEnum recordIndex:(NSUInteger)index
{
    NSDecimalNumber *num = nil;
    
    if ( [plot isKindOfClass:[CPTBarPlot class]] ) {
        
        switch ( fieldEnum ) {
            //X軸のラベルをNSNumberで指定(Formatterとか
            case CPTBarPlotFieldBarLocation:
                num = (NSDecimalNumber *)[NSDecimalNumber numberWithUnsignedInteger:index];
                break;
                
            //棒の高さを指定
            case CPTBarPlotFieldBarTip:
                if ([plot.identifier isEqual:@"Plot1"]) {
                    num = [self.dataForBar objectAtIndex:index];
                } else if ([plot.identifier isEqual:@"Plot2"]) {
                    num = [self.dataForBar2 objectAtIndex:index];
                }
                break;
        }
    }
    return num;
}


#pragma mark Plot Delegate Methods

// 各棒をタップしたときに発生するイベント
- (void)barPlot:(CPTBarPlot *)plot barWasSelectedAtRecordIndex:(NSUInteger)index
{
    // グラフタイトルにタップされた各項目のインデックス番号を設定
    graph.title = [NSString stringWithFormat:@"Selected index: %lu", (unsigned long)index];
}

@end


円グラフや棒グラフなどCorePlotのサンプルのソースコードGithubに置いてあります。よろしければ、覗いてみてください。
yanagi0324/test-core-plot · GitHub

参考情報

分かりづらい箇所やご質問などありましたら、 コメントやメールアドレスにご連絡いただけると嬉しいです。

クリエーター、エンジニアのための絶対なにかを作りたくなる文章

  • なにかを作ろう!
  • 勉強など準備するよりも、まず作ろう!
  • 壁にぶつかってもその場その場でなんとかし、諦めずに作ろう!

と思えた記事を共有します。

是非、一読ください。絶対何か作りたくなりますから

最初の一歩は始めること

(iOS/iPhoneアプリ開発) UISegmentedControlを使って画面表示 UIViewController を切り替える

完成イメージ

完成イメージは次の通りです。
上側のセグメンテッドコントロール(UISegmentedControl)をクリックすると、その下側のビューが変わります。
f:id:nipe880324:20131221193703p:plain:w240

("Second"を選択した後)
f:id:nipe880324:20131221193709p:plain:w240

環境

StoryBoardの作成

まずは、次のように3つのStoryBoardを作成します。(左や上側のコントローラは気にしないでください。)
f:id:nipe880324:20131221194110p:plain

  1. UIViewControllerを追加(3つのViewControllerのうち左側のViewController)
  2. 上記のコントローラの「Custom Class」にクラス名を設定(今回は、"TwoViewsViewController"を設定)
  3. 上記のコントローラにUISegmentedControlとUIView(切り替えるコンテンツの表示領域になる)を追加
  4. StoryBoardとViewController.hの2つのビューにし、「Ctrl + ドラッグ」を使って、上記のUISegmentedControlとUISegmentedControlをViewController.hに追加。※SegmentedControlはIBActionとIBOutletの両方を追加。
  5. 切り替え対象のコントローラを作成(今回はUITableViewControllerとUIViewControllerを作成)
  6. 切り替え対象のコントローラのそれぞれの「Storboard ID」と「Restoration ID」に識別子を設定(今回はテーブルビューに"FirstViewController"、ノーマルのビューに"SecondViewController"を設定)

ViewController.hに次のような記述が記載されます。

// セグメンテッドコントローラ
@property (weak, nonatomic) IBOutlet UISegmentedControl *typeSegmentedControl;
// 切り替えるコンテンツを表示させる領域
@property (weak, nonatomic) IBOutlet UIView *contentView;
// SegmentedControlの値を変更したときに呼ばれる
- (IBAction)segmentChange:(UISegmentedControl *)sender;

ViewController.hの作成

次に、ViewController.h を作成します。
詳細はコメントを確認してください。

#import <UIKit/UIKit.h>

@interface TwoViewsViewController : UIViewController

// セグメンテッドコントローラ
@property (weak, nonatomic) IBOutlet UISegmentedControl *typeSegmentedControl;

// 切り替えるコンテンツを表示させる領域
@property (weak, nonatomic) IBOutlet UIView *contentView;

// 現在のViewControllerを保持しておく変数
@property (weak, nonatomic) IBOutlet UIViewController *currentViewController;

// SegmentedControlの値を変更したときに呼ばれる
- (IBAction)segmentChange:(UISegmentedControl *)sender;
@end

ViewController.mの作成

次に、ViewController.m を作成します。

実際のソースコードです。
細かくコメントを記載してますのでそれを見れば大体分かると思います。

#import "TwoViewsViewController.h"

@implementation TwoViewsViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
 
    // SegmentedControlの値により異なるControllerを取得する
    UIViewController *vc = [self viewControllerForSegmentIndex:self.typeSegmentedControl.selectedSegmentIndex];
    // 取得したコントローラを子コントローラとして追加する
    [self addChildViewController:vc];
 
    // 子コントローラのViewを親コントローラのContent表示領域のサイズにする
    // スクロール対応していない場合などは画面から見切れる可能性があるので気をつけてください
    vc.view.frame = self.contentView.bounds;

    [self.contentView addSubview:vc.view];
    self.currentViewController = vc;
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

// SegmentedControlの値により異なるControllerを取得する
- (UIViewController *)viewControllerForSegmentIndex:(NSInteger)index {
    UIViewController *vc;
    switch (index) {
        case 0:
            vc = [self.storyboard instantiateViewControllerWithIdentifier:@"FirstViewController"];
            break;
        case 1:
            vc = [self.storyboard instantiateViewControllerWithIdentifier:@"SecondViewController"];
            break;
    }
    return vc;
}

// SegmentedControlの値を変更したときに呼ばれる
- (IBAction)segmentChange:(UISegmentedControl *)sender
{
    // SegmentedControlの値により異なるControllerを取得する
    UIViewController *vc = [self viewControllerForSegmentIndex:sender.selectedSegmentIndex];
    // 取得したコントローラを子コントローラとして追加する
    [self addChildViewController:vc];
    // ビューを変更する
    [self transitionFromViewController:self.currentViewController toViewController:vc duration:0.5
     options:UIViewAnimationOptionTransitionCurlUp  // 変更するアニメーションを指定
     animations:^{
        [self.currentViewController.view removeFromSuperview];
        vc.view.frame = self.contentView.bounds;
        [self.contentView addSubview:vc.view];
    } completion:^(BOOL finished) {
        [vc didMoveToParentViewController:self];
        [self.currentViewController removeFromParentViewController];
        self.currentViewController = vc;
    }];
}

@end


UISegmentdControlなどのUIKitに関するサンプルのソースコードGithubに置いてあります。よろしければ、覗いてみてください。
yanagi0324/test-uikit · GitHub

参考情報

分かりづらい箇所やご質問などありましたら、 コメントやメールアドレスにご連絡いただけると嬉しいです。