Горизонтальное движение UITableView? - PullRequest
7 голосов
/ 09 июля 2011

Я пытаюсь различить горизонтальную прокрутку / панорамирование и вертикальную прокрутку в UITableView.Поведение, которое я хочу имитировать (в некотором смысле), такое же, как и в приложении Twitter iPad, которое имеет несколько UITableView, которые можно перемещать по горизонтали на экране.Если я проведу пальцем влево или вправо по одному из этих UITableView, само представление переместится горизонтально.Если я проведу вертикально, представление прокручивается, как и ожидалось.

У меня возникли проблемы с поиском правильного способа реализации этого поведения.Я видел некоторые учебники по этому вопросу, которые включают добавление обработчиков сенсорных событий в UITableViewCells и переопределение hitTest в UITableView для соответствующей маршрутизации событий в зависимости от того, в каком направлении движется жест.Я реализовал некоторые из этих техник, но ни один из них не работает особенно хорошо.

Кто-нибудь знает правильный способ реализации такого рода поведения?Условно выполнение действий на UITableView в зависимости от направления движения пальца пользователя?

Спасибо.

Ответы [ 3 ]

9 голосов
/ 29 ноября 2011

Я боролся с подобной проблемой в течение нескольких дней, и я нашел несколько возможных решений. Я нашел лучший способ, а также самое простое решение - создать подкласс 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, поэтому мне пришлось потратить много времени на чтение и изучение распознавателей жестов и представлений прокрутки, чтобы понять это.

0 голосов
/ 04 августа 2011

Если вы хотите, чтобы объекты UITableView размещались «бок о бок», и когда вы проводите пальцем по горизонтали, вы ожидаете, что все они будут двигаться вместе по горизонтали одновременно (например, фотогалерея с UITableViews вместо изображений), вы можете сделать следующее:

Используйте UIScrollView и добавьте UITableViews в качестве подпредставлений UIScrollView.Вы должны установить размер прокрутки для contentSize следующим образом:

CGRect bounds = scrollView.bounds;
scrollView.contentSize=CGSizeMake(bounds.size.width * kNumOfTableViews,  bounds.size.height);

, чтобы UIScrollview прокручивал по горизонтали, а не по вертикали.

Вы также можете использовать

scrollView.pagingEnabled=YES;

в зависимости отна желаемое поведение.

UITableviews будет реагировать обычным образом, если вы проведете пальцем по вертикали, и вы сможете переключаться между UITableViews, двигая пальцем по горизонтали.

Для получения дополнительной информации о том, какчтобы сделать это эффективно, вы можете посмотреть видео сессию WWDC 2010 - Проектирование приложений с помощью прокрутки и посмотреть исходный код здесь: http://developer.apple.com/library/ios/#samplecode/PhotoScroller/.Этот сеанс описывает, как скользить между изображениями.Вместо изображений вы будете использовать UITableViews

Однако, если вы хотите, чтобы каждый UITableView мог перемещаться по горизонтали независимо и, возможно, перекрывался с другим, как в приложении Twitter для iPad, это решение не подойдет вам,хотя бы не из коробки.

0 голосов
/ 10 июля 2011

Я никогда не делал этого сам, но поскольку UITableView является подклассом UIScrollView, делегатами UITableView также являются UIScrollViewDelegates. Таким образом, в вашем подклассе UITableViewController вы должны иметь возможность использовать делегаты UIScrollView и перехватывать прокрутки - обязательно вызывая супер метод.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...