Я боролся с подобной проблемой в течение нескольких дней, и я нашел несколько возможных решений. Я нашел лучший способ, а также самое простое решение - создать подкласс UIGestureRecognizer для обработки горизонтального перемещения и присоединить его к вашим UITableViews.
Способ, которым он работает, заключается в том, что он перехватывает любые сенсорные события, прежде чем они перейдут в UITableView (также UIScrollView). UITableView, являясь подклассом UIScrollView, имеет встроенный пользовательский UIPanGestureRecognizer, который обнаруживает перетаскивание и прокручивает его представление соответствующим образом. Добавив свой собственный подкласс UIGestureRecognizer, вы можете получить прикосновения раньше, чем распознаватель жестов UIScrollView. Если ваш распознаватель видит, что пользователь перетаскивает по горизонтали, он должен изменить свое состояние в переопределенном touchesMoved: method на UIGestureRecognizerStateBegan. В противном случае он устанавливает свое состояние в UIGestureRecognizerCancelled, что позволяет базовому UIScrollView обрабатывать касания.
Вот как выглядит мой подкласс UIGestureRecognizer:
#import <UIKit/UIGestureRecognizerSubclass.h>
@interface TableViewCellPanGestureRecognizer : UIGestureRecognizer
{
CGPoint startTouchPoint;
CGPoint currentTouchPoint;
BOOL isPanningHorizontally;
}
- (void)reset;
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;
@end
@implementation TableViewCellPanGestureRecognizer
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesBegan:touches withEvent:event];
startTouchPoint = [[touches anyObject] locationInView:nil];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesMoved:touches withEvent:event];
currentTouchPoint = [[touches anyObject] locationInView:nil];
if ( !isPanningHorizontally ) {
float touchSlope = fabsf((currentTouchPoint.y - startTouchPoint.y) / (currentTouchPoint.x - startTouchPoint.x));
if ( touchSlope < 1 ) {
self.state = UIGestureRecognizerStateBegan;
isPanningHorizontally = YES;
[self.view touchesCancelled:touches withEvent:event];
} else {
self.state = UIGestureRecognizerStateCancelled;
[self.view touchesCancelled:touches withEvent:event];
}
} else {
self.state = UIGestureRecognizerStateChanged;
}
}
-(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesCancelled:touches withEvent:event];
self.state = UIGestureRecognizerStateCancelled;
[self.view touchesCancelled:touches withEvent:event];
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesEnded:touches withEvent:event];
self.state = UIGestureRecognizerStateCancelled;
}
-(void)reset
{
[super reset];
startTouchPoint = CGPointZero;
currentTouchPoint = CGPointZero;
isPanningHorizontally = NO;
}
@end
Затем у меня есть подкласс UITableView, который присоединяет распознаватель к себе и реализует метод действия для запуска горизонтального перемещения отдельных строк:
В моем UITableView init:
horizontalPanGesture = [[TableViewCellPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleHorizontalDrag:)];
[self addGestureRecognizer:horizontalPanGesture];
[horizontalPanGesture release];
И метод действия:
-(void)handleHorizontalDrag:(UIGestureRecognizer *)gesture
{
UIGestureRecognizerState state = gesture.state;
// Set the touched cell
if (!touchedCell){
NSIndexPath *indexPathAtHitPoint = [self indexPathForRowAtPoint:[gesture locationInView:self]];
id cell = [self cellForRowAtIndexPath:indexPathAtHitPoint];
touchedCell = cell;
startTouchPoint = [gesture locationInView:touchedCell];
}
if ( state == UIGestureRecognizerStateBegan || state == UIGestureRecognizerStateChanged ) {
// move your views horizontally
} else if ( state == UIGestureRecognizerStateEnded || state == UIGestureRecognizerStateCancelled ) {
touchedCell = nil;
}
}
Выше приведено касание текущей ячейки в табличном представлении, а затем применение к ней горизонтальных перемещений при перетаскивании пользователем влево или вправо. Однако, если мой распознаватель жестов определит, что касания предназначены для вертикальной прокрутки, он просто отменяет себя, и последующие касания отправляются в UITableView для автоматического запуска вертикальной прокрутки.
Эта настройка кажется намного проще, чем переопределение hitTest и выполнение всевозможных хитростей сенсорных событий в самом UITableView. Он просто немедленно определяет направление движения касания. Вы захотите прочитать о UIGestureRecognizers - в частности, о том, как его следует разделить на подклассы. Вы должны убедиться, что перенаправили на определенные сенсорные события, такие как touchesCancelled, в UITableView, так как встроенный в UITableView panGestureRecognizer не будет обрабатывать эти события, как обычно. Очевидно, вы захотите переместить все представления таблицы, а не отдельные ячейки, но это должно быть довольно просто.
Это простое решение заняло у меня некоторое время, чтобы точно соответствовать моим точным потребностям. Я довольно новичок в разработке для IOS, поэтому мне пришлось потратить много времени на чтение и изучение распознавателей жестов и представлений прокрутки, чтобы понять это.