UIScrollViewで縦にドラッグしたか横にドラッグしたかで挙動を変える

縦長のビューを作って、縦にドラッグした時と横にドラッグした時で挙動を変えたい。
 
例えば、こんなUIScrollViewがあったとする。
frame => CGRectMake(0,20,320,460)
contentSize => CGSizeMake(320, 800)
 
これなら通常なら横にドラッグしても何も起こらない。
縦のスクロールは生かしたまま、横にドラッグした時に何かさせたい。
 

実装方法

touchesBeganでタップ開始位置を取得。
1回目のtouchesMovedで移動先位置を取得。
移動距離を取って、YとXどっちの方が変化が大きいかで挙動を振り分ける。
Xの変化の方が大きい場合は、scrollEnabledをFLASEにする。
 
だがしかし、touchesBeganしたあとにscrollEnabledを変えてももう遅い。
scrollEnabledの設定をしてからtouchesBeganが呼ばれないといけなかった。
 
で、解決策として、touchesMovedの中で、以下3つを実行する。
これでタップしたあとでもscrollEnabledの設定を変更出来た。
・self setScrollEnabled
・super touchesBegan
・super touchesEnded
 
使い方は、UIScrollSwitchViewを継承して、以下メソッドをオーバーライド。

- (void)touchesSwitchBegan:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesSwitchMoved:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesSwitchEnded:(NSSet *)touches withEvent:(UIEvent *)event;

 

ソース

UIScrollSwitchView.h
#import <UIKit/UIKit.h>

enum {
	TAP_BEGAN,
	TAP_MOVED,
	TAP_ENDED
};

@interface UIScrollSwitchView : UIScrollView {
	NSInteger tapStatus;
	CGPoint tapStart;
}

- (void)touchesSwitchBegan:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesSwitchMoved:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesSwitchEnded:(NSSet *)touches withEvent:(UIEvent *)event;

@property (nonatomic) NSInteger tapStatus;
@property (nonatomic) CGPoint tapStart;
@end

 

UIScrollSwitchView.m
#import "UIScrollSwitchView.h"


@implementation UIScrollSwitchView
@synthesize tapStatus;
@synthesize tapStart;

- (id)initWithFrame:(CGRect)frame {
    if ((self = [super initWithFrame:frame])) {
        // Initialization code
		self.scrollEnabled = YES;
		self.delaysContentTouches = YES;
		self.tapStatus = TAP_ENDED;
    }
    return self;
}

/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
    // Drawing code
}
*/


/* Touches */

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
	//NSLog(@"UIScrollSwitchView touchesBegan");
	tapStatus = TAP_BEGAN;
	UITouch *touch = [[touches allObjects] objectAtIndex:0];
	CGPoint location = [touch locationInView:self];
	[self setTapStart:location];
	[self touchesSwitchBegan:touches withEvent:event];
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
	//NSLog(@"UIScrollSwitchView touchesMoved");
	if (tapStatus==TAP_BEGAN) {
		tapStatus = TAP_MOVED;
		UITouch *touch = [[touches allObjects] objectAtIndex:0];
		CGPoint location = [touch locationInView:self];
		NSInteger move_x = abs(location.x - tapStart.x);
		NSInteger move_y = abs(location.y - tapStart.y);

		// 横に動いた
		if (move_y<move_x) {
			[self setScrollEnabled:FALSE];
			[super touchesBegan:touches withEvent:event];
			[super touchesEnded:touches withEvent:event];
		}
	}
	if (self.scrollEnabled==FALSE) {
		[self touchesSwitchMoved:touches withEvent:event];
	}
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
	//NSLog(@"UIScrollSwitchView touchesEnded");
	tapStatus = TAP_ENDED;
	[self setScrollEnabled:TRUE];
	[self touchesSwitchEnded:touches withEvent:event];
}


/* Touch Switch */

- (void)touchesSwitchBegan:(NSSet *)touches withEvent:(UIEvent *)event {
	NSLog(@"UIScrollSwitchView touchesSwitchBegan");
}
- (void)touchesSwitchMoved:(NSSet *)touches withEvent:(UIEvent *)event {
	NSLog(@"UIScrollSwitchView touchesSwitchMoved");
}
- (void)touchesSwitchEnded:(NSSet *)touches withEvent:(UIEvent *)event {
	NSLog(@"UIScrollSwitchView touchesSwitchEnded");
}


- (void)dealloc {
    [super dealloc];
}


@end