[iOS] UITableView でセルをスワイプするとスライドするユーザインタフェースを実装

2011年6月29日水曜日 | Published in | 0 コメント

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

スワイプしてセルが横にスライドする動作を実装してみた。Twitterクライアントなどで実装されているあれ。


サンプル


セルを右方向にスワイプすると

スライドアニメーションが始まり下に隠れていたビューが姿を現す。

開ききった状態。

この後左にスワイプするか、他のセルをスワイプするとスライドが閉じる。


実装


ロジック

スワイプイベントは RootViewController で受け取り、セルの開け閉めを管理する。


ビューの配置


通常表示のビュー(BaseView)の下にスライド時に現れるビュー(SlideView)を重ねておく。普段は SlideView は隠れて見えない。
一時的に順番を入れ替えて内容を確認。SlideView はこんな感じ。




スワイプの処理


RootViewController にUIGestureRecognier を左右両方向について登録しておく。
- (void)viewDidLoad
{
    [super viewDidLoad];
          :   
    UISwipeGestureRecognizer* swipeGesture =
        [[UISwipeGestureRecognizer alloc]
         initWithTarget:self action:@selector(didSwipeCell:)];
    swipeGesture.direction = UISwipeGestureRecognizerDirectionRight;  
    [self.tableView addGestureRecognizer:swipeGesture];  
    [swipeGesture release];

    swipeGesture =
        [[UISwipeGestureRecognizer alloc]
            initWithTarget:self action:@selector(didSwipeCell:)];
    swipeGesture.direction = UISwipeGestureRecognizerDirectionLeft;  
    [self.tableView addGestureRecognizer:swipeGesture];  
    [swipeGesture release];
}
ハンドラはこう。
- (void)didSwipeCell:(UISwipeGestureRecognizer*)swipeRecognizer
{
    CGPoint loc = [swipeRecognizer locationInView:self.tableView];
    NSIndexPath* indexPath = [self.tableViewindexPathForRowAtPoint:loc];
    CustomCell* cell = (CustomCell*)[self.tableViewcellForRowAtIndexPath:indexPath];

    if ([openedIndexPath_ isEqual:indexPath]) {
        if (swipeRecognizer.direction == UISwipeGestureRecognizerDirectionLeft) {
            // close cell
            [cell setSlideOpened:NO animated:YES];
            openedIndexPath_ = nil;
        }
    } else if (swipeRecognizer.direction == UISwipeGestureRecognizerDirectionRight) {
        if (openedIndexPath_) {
            // close previous opened cell
            NSArray* visibleIndexPaths = [self.tableView indexPathsForVisibleRows];
            if ([visibleIndexPaths containsObject:openedIndexPath_]) {
                CustomCell* openedCell =
                    (CustomCell*)[self.tableView cellForRowAtIndexPath:openedIndexPath_];
                [openedCell setSlideOpened:NO animated:YES];
            }
        }
        // open new cell
        [cell setSlideOpened:YES animated:YES];
        openedIndexPath_ = indexPath;
    }
         
}
アーキテクチャで説明した②③④、②’③’を実行する。開けるのは右方向のスワイプの時だけ、また閉める時は左スワイプの時だけ有効にしてある。スワイプの結果開いた状態のセルが存在する場合はその場所を openedIndexPath_ へ取っておく。


スライドアニメーション


カスタムセルにスライドアニメーション用のメソッドを用意する。
@interface CustomCell : UITableViewCell {
    
    BOOL slideOpened_;
}
   :
- (void)setSlideOpened:(BOOL)slideOpened animated:(BOOL)animated;
無駄な開け閉めを防ぐ為、現在の状態を slideOpened_ にとっておいてある。実装はこんな感じ。
- (void)setSlideOpened:(BOOL)slideOpened animated:(BOOL)animated
{
    if (slideOpened == slideOpened_) {
        return;
    }    
    slideOpened_ = slideOpened;
    
    if (animated) {
        if (slideOpened_) {
            // open slide
            [UIViewanimateWithDuration:0.2
                             animations:^{
                                 CGRect frame = self.baseView.frame;
                                 frame.origin.x += frame.size.width;
                                 self.baseView.frame = frame;
                             }];
            
        } else {
            // close slide
            [UIViewanimateWithDuration:0.1
                             animations:^{
                                 CGRect frame = self.baseView.frame;
                                 frame.origin.x = 0;
                                 self.baseView.frame = frame;
                             }];
        }
    } else {
        CGRect frame = self.baseView.frame;
        if (slideOpened_) {
            // open slide
             frame.origin.x += frame.size.width;
            
        } else {
            // close slide
             frame.origin.x = 0;
        }
        self.baseView.frame = frame;
        
    }

}
わざわざアニメーション有り・無しのケースを用意しているのは、セルを初期表示する場合などアニメーションが不要なケースがあるから。アニメーション処理自体は UIViewanimateWithDuration:animations: を使いビューの位置を変えているだけの単純なもの。開くときと閉じるときでかかる時間を変えてみた。


セルの表示


セルは再利用されるため、表示の度にモデルの状態をきちんと反映してやる必要がある。
RootViewController.m

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
        :
    // Configure the cell.
        :
    if ([openedIndexPath_ isEqual:indexPath]) {
        [cell setSlideOpened:YES animated:NO];
    } else {
        [cell setSlideOpened:NO animated:NO];
    }

    return cell;
}
文字や画像の設定の他、スライドの開閉状態を反映しておく。その判断にスワイプジェスチャの処理で取っておいた openedIndexPath_ を使う。


選択状態の自前実装


UITableViewCell上でビューを2枚重ねている場合で選択した時には下のビュー上のコントロールが表示されてしまう。UITableViewCell は選択状態の時にその上に配置されているすべてのビューに対して -setHilight:YES のメッセージを送るようだ(さらにその場合は背景となっているビューよりも前に表示されるようだ)。
これを回避するには標準の選択状態を消した上で自前で描画する。
まず SelectionをNoneにする。
次にカスタムビュークラス BaseView を用意し、選択時の描画を行わせる。単色だと味気ないので選択状態の表示にグラデーションをかけてみた。
@interface BaseView : UIView {
}
@property (nonatomic, assign) BOOL selected;
@end


@implementation BaseView
@synthesize selected;
- (void)drawRect:(CGRect)rect
{
    // draw 
    if (selected) {
        
        CGContextRef context = UIGraphicsGetCurrentContext();    
        
        CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
        CGFloat components[] = { 0.9f, 0.9f, 0.9f, 0.9f,
                                 0.7f, 0.7f, 0.7f, 0.7f };

        
        size_t count = sizeof(components)/ (sizeof(CGFloat)* 4);

        
        CGContextAddRect(context, self.frame);
        
        CGRect frame = self.bounds;
        CGPoint startPoint = frame.origin;
        CGPoint endPoint = frame.origin;
        endPoint.y = frame.origin.y + frame.size.height;

        CGGradientRef gradientRef =
            CGGradientCreateWithColorComponents(colorSpaceRef, components, NULL, count);

        CGContextDrawLinearGradient(context,
                                    gradientRef,
                                    startPoint,
                                    endPoint,
                                    kCGGradientDrawsAfterEndLocation);

        
        
        CGGradientRelease(gradientRef);
        CGColorSpaceRelease(colorSpaceRef);
    }
}
@end
なおSelection を Noneにすると押している間のハイライト状態の表示が変わらなくなるのでこれも手当しておく。
- (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated
{
    UIColor* selectedColor = [UIColor whiteColor];  // default color
    if (highlighted) {
        selectedColor = [UIColor lightGrayColor];
    }
    self.baseView.backgroundColor = selectedColor;
    [super setHighlighted:highlighted animated:animated];
}
これで選択状態はこうなった。


影を付ける


セルがスライドして開いている状態はそのままだとこんな感じ。
平面的で少々味気ない。少し立体感を持たせる為に影を落とすことにする。そこでカスタムビュー SlideView に影を描く。
@interface SlideView : UIView {
}
@end
    
@implementation SlideView


#define CUSTOMCELL_OBJECT_LENGTH    10.0
#define CUSTOMCELL_SHADOW_OFFSET    5.0
#define CUSTOMCELL_SHADOW_BLUR      5.0

- (void)drawRect:(CGRect)rect
{
    // draw edge shadow
    CGRect frame = self.bounds;
    frame.origin.x -= CUSTOMCELL_OBJECT_LENGTH;
    frame.origin.y -= CUSTOMCELL_OBJECT_LENGTH;
    frame.size.width += CUSTOMCELL_OBJECT_LENGTH;
    frame.size.height = CUSTOMCELL_OBJECT_LENGTH;

    CGContextRef context = UIGraphicsGetCurrentContext();    
    
    CGContextSetShadow(context,CGSizeMake(
        CUSTOMCELL_SHADOW_OFFSET, CUSTOMCELL_SHADOW_OFFSET),
            CUSTOMCELL_SHADOW_BLUR);

    [[UIColorwhiteColor] setFill];
    CGContextFillRect(context, frame);
    
}

@end
左上の描画枠外に矩形を描きその影の部分だけ表示するようにするといいあんばいとなる。


ソースコード


GitHub からどうぞ。
CustomCellSample at 2011-06-29b from xcatsan/iOS-Sample-Code - GitHub

その他


すべてのセルに対して開いた時に表示されるビュー(SlideView)を用意するのはメモリ消費の観点から無駄かもしれない。もし改良するとすれば、スワイプが行われた時に SlideView のインスタンスを作り、開く直前にセルへ貼り付ける方法が考えられる。また閉じた後はセルから取り除いて廃棄する。セルの表示情報が多く画面が重くなってしまった時にはこういった方法法は有効だと思われる。


参考情報


カスタムセルのシリーズ

Cocoaの日々: [iOS] UINib を使ったカスタム UITableViewCell の作り方
Cocoaの日々: [iOS] UINib を使ったカスタム UITableViewCell の作り方(その2)ボタンの処理
Cocoaの日々: [iOS] UINib を使ったカスタム UITableViewCell の作り方(その3)ボタンの処理[改良版]
今回のコードはこれらをベースに作っている。

グラデーション

Cocoaの日々: [iOS][Mac] Core Graphics - グラデーション
グラデーションの描き方は前回書いた。

[iOS][Mac] Core Graphics - グラデーション

2011年6月28日火曜日 | Published in | 0 コメント

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

CoreGraphics の グラデーションについての覚書き。



Linear Gradient


2つの点を指定してその間でグラデーションを表現する方式。

CGGradientRef() で定義し、CGContextDrawLinearGradient() で描画する。あらかじめ描画したい形(パス)を登録しておく。コードはこんな感じ。
- (void)drawRect:(CGRect)rect
{
    CGContextRef context = UIGraphicsGetCurrentContext();   
    CGContextSaveGState(context);
   
    CGContextAddRect(context, self.frame);
   
    CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
    CGFloat components[] = {
        1.0f, 1.0f, 1.0f, 0.5f,     // R, G, B, Alpha
        0.0f, 0.0f, 0.0f, 0.5f
    };
    CGFloat locations[] = { 0.0f, 1.0f };

    size_t count = sizeof(components)/ (sizeof(CGFloat)* 4);
   
    CGRect frame = self.bounds;
    CGPoint startPoint = frame.origin;
    CGPoint endPoint = frame.origin;
    endPoint.y = frame.origin.y + frame.size.height;
   
    CGGradientRef gradientRef =
        CGGradientCreateWithColorComponents(colorSpaceRef, components, locations, count);
   
    CGContextDrawLinearGradient(context,
                                gradientRef,
                                startPoint,
                                endPoint,
                                kCGGradientDrawsAftersEndLocation);
   
    CGGradientRelease(gradientRef);
    CGColorSpaceRelease(colorSpaceRef);
   
    CGContextRestoreGState(context);
}

startPoint, endPoint はグラデーションの開始位置、終了位置を決める。例えば左上から左下にした場合はこう。

左上から右上。

左上から右下。

例では2色間のグラデーションを使っているが複数色間のグラデーションを作ることもできる。その場合は上記コードの components に色情報を増やす。
CGFloat components[] = {
        1.0f, 1.0f, 1.0f, 0.5f,
        1.0f, 0.0f, 0.0f, 0.5f,
                  :
        0.0f, 0.0f, 0.0f, 0.5f
    };
components を増やした場合は locations の要素もそれに合わせて増やす。locations は各色の割合を表していて 0〜1 の数値を取る。例えば
CGFloat locations[] = { 0.0f, 0.2f, 1.0f };
とすると全体の描画対象の 0〜20% が1色目と2色目のグラデーション、20%〜100%の領域が2色目と3色目のグラデーションになる。等間隔にしたい場合は CGGradientCreateWithColorComponents() の locations に NULLを渡すこともできる。


Radial Gradient


放射状のグラデーションを表現する。

こちらも2点を指定しその間のグラデーションを表現するが、Linearと違うのは各点から放射状にグラデーションがかかること。コードはこんな感じ。
- (void)drawRect:(CGRect)rect
{
    CGContextRef context = UIGraphicsGetCurrentContext();   
    CGContextSaveGState(context);
   
    CGContextAddEllipseInRect(context, self.frame);
   
    CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
    CGFloat components[] = {
        1.0f, 1.0f, 1.0f, 1.0f,
        0.5f, 0.5f, 0.5f, 1.0f,
        0.25f, 0.25f, 0.25f, 1.0f,
    };   
    CGFloat locations[] = { 0.0, 0.5, 1.0 };
   
    size_t count = sizeof(components)/ (sizeof(CGFloat)* 4);
    CGGradientRef gradientRef =
        CGGradientCreateWithColorComponents(colorSpaceRef, components, locations, count);
       
    CGRect frame = self.bounds;
    CGFloat radius = frame.size.height/2.0*0.8;

    CGPoint startCenter = frame.origin;
    startCenter.x += frame.size.width/2.0;
    startCenter.y += frame.size.height/2.0;
    CGPoint endCenter = startCenter;
   
    CGFloat startRadius = 0;
    CGFloat endRadius = radius;
   
    CGContextDrawRadialGradient(context,
                                gradientRef,
                                startCenter,
                                startRadius,
                                endCenter,
                                endRadius,
                                kCGGradientDrawsAfterEndLocation);
   
    CGGradientRelease(gradientRef);
    CGColorSpaceRelease(colorSpaceRef);
   
    CGContextRestoreGState(context);
}
CGGradientRef の作り方は Linear と同じ。ポイントは2つの点とそれらの点を中心として描かれる円の半径を指定するところ。例では startCenter と endCenter を同じにしているので中心から放射状にグラデーションがかかっているように見える。startRadius は 0。

次は startCenter を左上に動かした例。
擬似 3D ぽい画像になる(見かたを変えると遠くでライトを光らせているようにも見える)。


サンプル


GitHub からどうぞ。

GradientSample at 2011-06-28 from xcatsan/iOS-Sample-Code - GitHub

なお背景には標準で付いていた "Scroll View Textured Background Color" を使っている(これ自体を描画しているわけではない)



参考情報


Gradients
Gradientsの解説はマニュアルが詳しい。


A-Liaison BLOG: CGGradientを用いてUITableViewCellを描画し、テーブルをカッコよく見せる方法
UIColor 元にグラデーションを作るアイディアが面白い。

(旧) Cocoaの日々: NSGradiation
Mac OS X ならこっちも使える。

[iOS] Responder Chain と UIViewController

2011年6月26日日曜日 | Published in | 0 コメント

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

@novi_ さんの指摘をきっかけに UIViewController が UIResponder のサブクラスで Responder Chain に参加していることを知った(今更だが。。)。

Responder Chain


Responder Chain とは UIResponderオブジェクトの連なり(リンク)のことで、イベント処理の順番を決定するのに使われる。イベントが発生すると、システムは Redponder Chain の順番にしたがって UIResponderオブジェクトを評価する。もし最初の UIResponderオブジェクトでイベント処理が行われない場合は Responder Chain の次の UIResponderオブジェクト へと移り再び評価を行う。イベント処理を行う UIResponderオブジェクトが見つかるまで Responder Chain 上のリンクを辿って評価を続けていく。一旦どこかの UIResponderオブジェクトがイベントを処理するとイベントの伝搬はそこで終わる。Responder Chain 上のどの UIResponderオブジェクトも処理を行わない場合はやがては最終的に UIApplication へ到達し、そこでも処理されない場合はそのイベントは処理されず無視される。

例えばボタンがタップされた場合、タップイベントを最初に処理するのは当該ボタンだが、そこでイベント処理が行われない場合、そのボタンが配置されている superview が評価される。もし superview にイベント処理コードが存在すれば、そこで処理が実行されてイベントの伝搬は終わる。もしイベント処理コードが superview上に無ければ、その次の UIWindow, UIApplication と Responder Chain が次々と辿られる。
なお明示的に Responder Chain を利用する場合はイベント登録時のターゲットに nil を渡す。
- (void)viewDidLoad
{
    [super viewDidLoad];
    [self.button addTarget:nil 
                    action:@selector(touchMe:)
          forControlEvents:UIControlEventTouchUpInside];
}
これを nilターゲットと呼ぶ(動作も含めてたしか「nilターゲットアクション」と呼んだりもした)。この仕組は Mac OS X 由来で昔からある(Next由来か)。


Responder Chain と UIViewController


UIViewController は紐づいている UIView が参加している Responder Chain に割り込んで参加している。
UIResponder のサブクラスなのはこの Responder Chain に参加させる為だと思われる。nilターゲットをうまく使うことで紐づいている UIView 上のイベントをすべて UIViewController で集約的に処理することが可能になる。IBActionを宣言してXib上で接続する手間もない(そっちはそっちで明示的にターゲット・アクションの関係がわかりやすいくなるので良い面もあるが)。


※上の図は下記ページより借用
Event Handling Guide for iOS: Event Types and Delivery


サンプル


Responder Chain の確認と nilターゲットアクションが確認できるサンプルプログラムを作ってみた。
"display" ボタンを押すと、そのボタンが参加している Responder Chain をログに出力する。
- (void)_displayResponderChain:(UIResponder*)responder
{
    if (responder != nil) {
        NSLog(@"%@", responder);
        [self _displayResponderChain:[responder nextResponder]];
    }
}
- (IBAction)display:(id)sender {
    [self _displayResponderChain:sender];
    
}
再帰的に Responder Chain を辿って表示させる。結果はこんな感じ。
<UIRoundedRectButton: 0x4e13: 0x4e13c70>
 <UIView: 0x4e12f40;>
 <ResponderChainStudyViewController>
 <UIWindow: 0x4b44b30>
 <UIApplication: 0x4e012b0>
イベントの発生源であるボタンを起点に→superview→UIViewController→UIWindow→UIApplication と連なっているのがわかる。UIViewController は UIView と UIWindow の間に入り込んでいる。

次に nilターゲットアクション。
- (void)viewDidLoad
{
    [super viewDidLoad];
    [self.button2 addTarget:nil 
                 action:@selector(touchMe:)
       forControlEvents:UIControlEventTouchUpInside];
}
としておき、UIViewController にイベントハンドラを書いておく。
- (void)touchMe:(id)sender
{
    NSLog(@"%s|%@", __PRETTY_FUNCTION__, sender);
    
}
すると "touch me !"ボタンが押されたときにそのイベントハンドラが呼び出され、Responder Chain が辿られていることがわかる。


ソースコード


GitHub からどうぞ。
ResponderChainStudy at 2011-06-26 from xcatsan/iOS-Sample-Code - GitHub


参考情報


Event Handling Guide for iOS: Event Types and Delivery

Responder Chain の解説ならびに UIViewController との関係が説明されている。

[iOS] UINib を使ったカスタム UITableViewCell の作り方(その3)ボタンの処理[改良版]

| Published in | 0 コメント

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

[前回] Cocoaの日々: [iOS] UINib を使ったカスタム UITableViewCell の作り方(その2)ボタンの処理

前回のコードで何番目のセルがタップされたかどうかを判断するのに View階層上で特定のクラスに所属するインスタンスを検索する処理をしていた。
- (IBAction)didTouchDoitButton:(id)sender
{
    id cell = sender;
    while (![cell isKindOfClass:[CustomCell class]]) {
        cell = [cell superview];
    }
    NSIndexPath* indexPath = [self.tableView indexPathForCell:cell];
    NSLog(@"%@", indexPath);
}

その後、UITableView を見ていると特定のポイント(CGPoint)から何番目のセルを指しているかどうかを取得するメソッドがあるのに気がついた。
UITableView Class Reference - indexPathForRowAtPoint:
- (NSIndexPath *)indexPathForRowAtPoint:(CGPoint)point
これを使うとクラスの検索は不要でもっと汎用的に書ける。こんな感じ。
- (IBAction)didTouchDoitButton:(id)sender event:(UIEvent*)event
{
    UITouch* touch = [[event allTouches] anyObject];
    CGPoint p = [touch locationInView:self.tableView];
    NSIndexPath* indexPath = [self.tableView indexPathForRowAtPoint:p];
    NSLog(@"%@", indexPath);
}
こっちの方が良さそうだ。

なおボタンのイベントハンドラは引数が0〜2個のいずれかを取るメソッドとして実装が可能で、必要に応じて使い分けられる。
-(IBAction)didTouch;
-(IBAction)didTouch:(id)sender;
-(IBAction)didTouch:(id)sender (UIEvent*)event;
今回はタッチ位置を取得する必要があったので引数に UIEvent を含む方を使った。

[iOS] UINib を使ったカスタム UITableViewCell の作り方(その2)ボタンの処理

2011年6月25日土曜日 | Published in | 0 コメント

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

[参考] Cocoaの日々: [iOS] UINib を使ったカスタム UITableViewCell の作り方

カスタムセルにボタンを貼りつけた時の処理パターンの紹介。

処理パターン


ボタンのタップイベントをどこで受け取るべきか。カスタムセルで受け取るのも手だが単なるビューなのでモデルとのつながりが無い。モデルとの接点があるのは ViewController なのでここでイベントを受け取るのが順当だろう。


実装


まず ViewController に IBAction を追加する。
@interface RootViewController : UITableViewController {
    CGFloat cellHeight_;
}
// cell events
- (IBAction)didTouchDoitButton:(id)sender;
@end

続いて Xib へボタンを追加する。

ここで Xib の File's Owner に RootViewController を指定する。

そしてタップアクションのターゲットとして先ほど用意した IBAction へ接続する。


次にカスタムセルの生成コードに手を入れる。前回は -[UINib instantiateWithOwner:options:] の owner引数に nil を渡していた。これを self(=RootViewController)とする。
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    CustomCell* cell = (CustomCell*)[tableView dequeueReusableCellWithIdentifier:CUSTOM_CELL_NIB];
    if (cell == nil) {
        UINib* nib = [UINib nibWithNibName:CUSTOM_CELL_NIB bundle:nil];
//      NSArray* array = [nib instantiateWithOwner:self options:nil];   // 前回
        NSArray* array = [nib instantiateWithOwner:nil  options:nil];   // 今回
          :
    }
       :
こうすることで Xib がインスタンス化された時に File's Owner が RootViewController のインスタンスとなり、ボタンがタップされた時に所定のメソッドが呼び出されるようになる。

最後にボタンタップ時の処理。
- (IBAction)didTouchDoitButton:(id)sender
{
    id cell = sender;
    while (![cell isKindOfClass:[CustomCell class]]) {
        cell = [cell superview];
    }
    NSIndexPath* indexPath = [self.tableView indexPathForCell:cell];
    NSLog(@"%@", indexPath);
}
タップされたセルがどのモデルと紐づくかを知るには NSIndexPath が必要になるので -[UITableView indexPathForCell:] を使う。ただ、ボタンタップ時に呼び出されるこのメソッドの引数 sender には UIButton のインスタンスが入っているだけなので、ここからCustomCell のインスタンスを手に入れる必要がある。UIButton はカスタムセルの子ビュー(sub view) なので、逆に UIButton のビュー階層を上に辿っていって CustomCellクラスのインスタンスを探せば良い。

(2011-06-27追記)クラス検索は使わずに、タッチ位置から NSIndexPathを取得する方法が見つかった。そちらの方が汎用性があり実用的なので参照されたい。
Cocoaの日々: [iOS] UINib を使ったカスタム UITableViewCell の作り方(その3)ボタンの処理[改良版]

ソースコード


GitHub からどうぞ。
CustomCellSample at 2011-06-23 from xcatsan/iOS-Sample-Code - GitHub


参考情報

なし

[iOS][Mac] Xcode4 : カスタムなコードスニペットの作成

2011年6月9日木曜日 | Published in | 0 コメント

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

やってみたらとても簡単だった。コードを選択して Code Snippet Library へドロップするだけ。

"My Code Snippet" が追加される。

ダブルクリックすると内容の確認ができる。

Edit を押すと内容の編集が可能。編集画面ではタイトルや補完ショートカットなどの設定ができる。

またプラットフォーム(iOS, Mac OS X)や言語(Objective-C, HTML, Perl, ...)、スコープ(宣言部、実装部、メソッド内、コメント内、...)などが選べる。以下はスコープの選択肢。
Title, Summary を対象に検索ができるので自分のものはそれとわかるキーワードを入れておくと探しやすいかも。


"Completion Shortcut" には補完する時にマッチさせる文字列を入れておく。

するとコード上で文字列の一部を入れると選択できるようになる。

置換したい箇所は <#文字列#> を埋め込んでおく。

すると該当箇所が置換を促すように反転表示となる(タブキーでその箇所へ移動可能)。


参考情報


Source Editor Help: Creating a Custom Code Snippet

Source Editor Help: Determining the Shortcut for a Code Snippet


- - - -
こりゃ便利。Evernote で管理していたスニペットを全部 Xcodeへ持ってこられそう。

[iOS][Mac] Xcode4 : ドラッグ&ドロップで IBOutlet コードを生成する

2011年6月8日水曜日 | Published in | 0 コメント

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

知ってはいたが試してなかった。こりゃ便利。
#しこしこ手で書いていた今まではいったいなんだったのか。。

以下、手順

まず Xib を開いた後、右上の Editor から真ん中の Assistant Editor を開く。

次に IBOutlet を作りたいコントロールを選択し、Controlキーを押しながらコードを挿入したい位置で離す。

するとタイプや変数名を聞いてくるので入力する。
これでおしまい。
プロパティだけでなくメンバ変数の宣言も。

もちろん接続も済んでいる。
さらに @synthesize も書いてくれる。

さらにさらに viewDidUnload まで。
ちゃんと dealloc も(抜かり無い)

必要なものはすべてお膳立てしてくれるようだ。こりゃ便利。


IBAction も同様。ヘッダへ落とせば宣言に加え、実装ファイル(*.m)にメソッドの雛形も書いてくれる。





参考情報


Xcode 4 User Guide: Designing User Interfaces in Xcode

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