UITableView的水平移动?

时间:2011-07-09 19:04:44

标签: ios uitableview

我试图区分水平滑动/平移和 UITableView中的垂直滚动。我正在寻找的行为 模仿(在某种意义上)是Twitter iPad应用程序的模仿 可以在屏幕上水平移动的多个UITableView。如果 我在这些UITableView视图之一上向左或向右滑动我的手指 本身水平移动。如果我垂直滑动,视图会滚动为 预期

我无法找出实现这一目标的正确方法 行为。我已经看过一些关于添加触摸的教程 UITableViewCells中的事件处理程序,并覆盖hitTest中的事件处理程序 UITableView根据方向适当地路由事件 手势正在移动。我已经实现了一些这些技术,但是 它们都没有特别好用。

有没有人知道实施此类行为的正确方式? 有条件地对依赖于UITableView的{​​{1}}执行操作 用户手指移动的方向

感谢。

3 个答案:

答案 0 :(得分:9)

我几天来一直在努力解决类似的问题,而且我已经经历了几个潜在的解决方案。我找到了最好的方法,也是最简单的解决方案,可以将UIGestureRecognizer子类化,以处理水平移动并将其附加到UITableViews。

它的工作方式是它在进入UITableView(也是UIScrollView)之前拦截任何触摸事件。 UITableView是UIScrollView的子类,它内置了一个自定义UIPanGestureRecognizer,可以检测拖动并相应地滚动它的视图。通过添加自己的UIGestureRecognizer子类,您可以在UIScrollView的手势识别器之前进行触摸。如果您的识别器看到用户正在水平拖动,它应该在覆盖的touchesMoved:方法中将其状态更改为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开发很新,所以我不得不花很多时间阅读和修改手势识别器和滚动视图来解决这个问题。

答案 1 :(得分:0)

我自己从未这样做,但由于UITableView是UIScrollView的子类,UITableView的委托也是UIScrollViewDelegates。因此,在您的UITableViewController子类中,您应该能够使用UIScrollView委托,并拦截滚动 - 确保也调用super方法。

答案 2 :(得分:0)

如果你想要“并排”放置UITableViews,当你水平滑动时,你希望它们同时水平地一起移动,(比如带有UITableViews而不是图像的照片库)你可以做到以下几点:

使用UIScrollView并将UITableViews添加为UIScrollView的子视图。您应该像这样设置scrollview的contentSize:

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

以便UIScrollview水平滚动而不是垂直滚动。

您可能还想使用

scrollView.pagingEnabled=YES;

取决于理想的行为。

如果您垂直滑动手指,UITableviews将以正常方式响应,您可以通过水平滑动手指在UITableViews之间切换。

有关如何有效执行此操作的更多详细信息,您可以查看WWDC 2010视频会话104 - 使用滚动视图设计应用程序并查看此处的源代码:http://developer.apple.com/library/ios/#samplecode/PhotoScroller/。此会话描述了如何在图像之间滑动。您将使用UITableViews

而不是图像

但是,如果您希望每个UITableView能够独立水平移动,并且可能与iPad的Twitter应用程序中的另一个UITableView重叠,则此解决方案对您不起作用,至少不是开箱即用。