UIViewをUIPopoverControllerで表示する

UIPopoverControllerでなにかしらポップアップさせる時、一々UIViewControllerを新規クラスで作成するのが面倒な時ありますよね。
UIViewでの実装がすでにあるものをポップアップさせたい時とか。

こんな時はUIViewControllerを直接インスタンス化してそのviewにUIViewを割り当てればOKっぽいです。
(この辺がobjective-cらしいなーと思う所です)


UIViewController* popupContents 
  = [[[UIViewController alloc]init]autorelease];
popupContents.view 
  = [[XXXXView alloc]initWithFrame:CGRectMake(0, 0, 400, 400)]autorelease];
popupContents.contentSizeForViewInPopover = CGSizeMake(400, 400); //※1

UIPopoverController* popup 
  = [[[UIPopoverController alloc]initWithContentViewController:popupContents]autorelease];

//アニメーション付きで表示する(ここは適当)  
[popup presentPopoverFromRect:CGRectMake(0, 0, 10, 10) 
       inView:self permittedArrowDirections:UIPopoverArrowDirectionAny 
       animated:YES];

※1でcontentSizeForViewInPopoverを指定していますが、これが表示されるポップアップのサイズになります。

UIColorの混合

cocoaの場合、描画関係のAPIが充実しているので自分でグラデーションを描画する事は少ないと思われます。
が、まれーにグラデーションの中間色、色と色とを特定の割合で混合した色を求めたい状況があるわけです。

そんな時はこれ
weightが0の時はcolorFrom、100の時はcolorToの色となるように色成分を混合して
返してくれます。


// weight: 0~100
-(UIColor*)makeBlendColorFrom:(UIColor*)colorFrom colorTo:(UIColor*)colorTo weight:(float)weight
{
    float r1,g1,b1,r2,g2,b2,alpha;

    //RGB値を求める
    [colorFrom getRed:&r1 green:&g1 blue:&b1 alpha:&alpha];
    [colorTo getRed:&r2 green:&g2 blue:&b2 alpha:&alpha];

    //色成分を混合
    float red = (r2*weight + r1*(100.0 - weight))/100.0;
    float green = (g2*weight + g1*(100.0 - weight))/100.0;
    float blue = (b2*weight + b1*(100.0 - weight))/100.0;

    return [UIColor colorWithRed:red green:green blue:blue alpha:1];
}

UIViewの透過(見た目とイベント)

表示上の透過
方法1 alphaを0にする

view.alpha = 0;

これで透明になりますが、これではviewの上にのせた他のSubviewたちも表示されません。

方法2 背景色をクリアにする

view.backgroundcolor = [UIColor clearColor];

これで背景のみが透過されます。

イベントの透過
方法1 isUserInteractionEnabledを設定する

view. isUserInteractionEnabled = NO;

これでview に対してのイベントが透過されますが、subviewについても反応しなくなります。

方法2 hitTestをオーバーライド

こんな感じ


- (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    UIView* view= [super hitTest:point withEvent:event];
    if(view==self){
         return nil;
    }
    return view;
}

hitTestでnilを返すと後ろのviewへイベントが透過されます。
これを使うと、状況によってイベントの発生状況をコントロールする事が可能となります。

3本指のピンチジェスチャーを作る 3

touchesMovedの実装

次にtouchesMovedを実装していきます。

ここでやることは単純でタッチポイント間の距離を求めて、touchsBegan時点で保存した距離との比率を
プロパティscaleに保存すればOK

ただし、念のため3点以外でタッチされた時はジェスチャーを失敗させます。
また、stateがUIGestureRecognizerStatePossibleの時はUIGestureRecognizerStateBeganに書き換えておきます。


- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    [super touchesMoved:touches withEvent:event];
    
    int numberOfTouches =  event.allTouches.count;
    if (numberOfTouches != 3)
    {
        if (self.state == UIGestureRecognizerStatePossible)
        {
            self.state = UIGestureRecognizerStateFailed;
        } else {
            self.state = UIGestureRecognizerStateCancelled;
        }
        return;
    }
    
    UITouch *first = [[event.allTouchesallObjects] objectAtIndex:0];
    UITouch *second = [[event.allTouchesallObjects] objectAtIndex:1];
    UITouch *third = [[event.allTouchesallObjects] objectAtIndex:2];
    
    float distance = [self calcDistance:[first locationInView:self.view]
                                     p2:[second locationInView:self.view]
                                     p3:[third locationInView:self.view]];
    
    self.scale = distance / _distance_initial;
    
    if (self.state == UIGestureRecognizerStatePossible)
    {
        self.state = UIGestureRecognizerStateBegan;
    } 
    
    
}

後処理の実装

あとは終了処理とキャンセルの処理を実装すれば完成です

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    [super touchesEnded:touches withEvent:event];
    
    switch (self.state) {
        caseUIGestureRecognizerStatePossible: 
        caseUIGestureRecognizerStateFailed:    
            self.state = UIGestureRecognizerStateFailed;
            break;
        caseUIGestureRecognizerStateBegan:
        caseUIGestureRecognizerStateChanged:
            // 正常に終了
            self.state = UIGestureRecognizerStateEnded;
            break;
        default:
            // 上記以外はキャンセル扱い
            self.state = UIGestureRecognizerStateCancelled;
            break;
    }
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
    [supertouchesCancelled:touches withEvent:event];
    self.state = UIGestureRecognizerStateFailed;
    self.scale = 1;
}


使い方

使い方は通常のUIPinchGestureRecognizerと大体同じ

ジェスチャーをUIViewに登録して

ThreeFingersPinchGestureRecognizer *pinch = [[[ThreeFingersPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinchAction:)] autorelease];
[self.view addGestureRecognizer:pinch];

ハンドリング

- (void)pinchAction : (ThreeFingersPinchGestureRecognizer *)sender 
{
  //sender.scale を使って拡大縮小などを行う
}

ファイル