25

以下是滚动视图的工作方式:一个滚动视图在水平方向启用分页。此滚动视图的每个“页面”都包含一个垂直滚动的 UITableView。如果不进行修改,这可以正常工作,但并不完美。

不正确的行为:当用户在表格视图上上下滚动,但又想快速翻到下一页时,水平滑动/滑动最初不起作用 - 直到表格视图静止时才会起作用(即使滑动非常明显是水平的)。

它应该如何工作:如果滑动明显是水平的,即使表格视图仍在滚动/弹跳,我也希望页面发生变化,因为这也是用户所期望的。


我怎样才能改变这种行为——最简单或最好的方法是什么?


注意由于各种原因,某些答案中所述的 UIPageViewController 将不起作用。我如何使用交叉方向 UIScrollViews 来做到这一点(/one 是一个表格视图,但你明白了)?我已经把头撞到墙上好几个小时了——如果你认为你能做到这一点,那么我会很高兴地奖励赏金。

4

7 回答 7

20

根据我对问题的理解,只有在 tableView 滚动时,我们才想更改默认行为。所有其他行为将是相同的。

子类UITableViewUITableViews 是UIScrollViews 的子类。在UITableView子类上实现一个 UIScrollViewUIGestureRecognizer的委托方法

- (BOOL)gestureRecognizer:(UIPanGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UISwipeGestureRecognizer *)otherGestureRecognizer
{
    //Edit 1
    //return self.isDecelerating;
    //return self.isDecelerating | self.bounces; //If we want to simultaneous gesture on bounce and scrolling
    //Edit 2
    return self.isDecelerating || self.contentOffset.y < 0 || self.contentOffset.y > MAX(0, self.contentSize.height - self.bounds.size.height); // @Jordan edited - we don't need to always enable simultaneous gesture for bounce enabled tableViews
}

因为我们只想在 tableView 减速时更改默认手势行为。

现在将所有 'UITableView' 类更改为新创建的 tableViewSubClass 并运行项目,滑动应该在 tableView 滚动时工作。:]

但是当 tableView 滚动时,滑动看起来有点太敏感了。让我们对滑动进行一些限制。

子类UIScrollView。在UIScrollView子类上实现另一个UIGestureRecognizer的委托方法gestureRecognizerShouldBegin:

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer 
{
    if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) {
        CGPoint velocity = [(UIPanGestureRecognizer *)gestureRecognizer velocityInView:self];
        if (abs(velocity.y) * 2 < abs(velocity.x)) {
            return YES;
        }
    }
    return NO;
}

我们想让“滑动明显是水平的”。上面的代码仅在 x 轴上的手势速度是 y 轴上的两倍时才允许手势开始。[如果您愿意,请随意增加硬编码值“2”。滑动需要更水平的值越高。]

现在将“UiScrollView”类(它有多个 TableView)更改为您的 ScrollViewSubClass。运行项目。:]

在此处输入图像描述

我在 gitHub 上做了一个项目https://github.com/rishi420/SwipeWhileScroll

于 2014-01-18T23:06:57.333 回答
3

在此处输入图像描述

虽然苹果不太喜欢这种方法:

重要提示:您不应该在 UIScrollView 对象中嵌入 UIWebView 或 UITableView 对象。如果这样做,可能会导致意外行为,因为两个对象的触摸事件可能会混淆并错误处理。

我找到了一个很好的方法来实现这一点。

这是该问题的完整解决方案。为了在滚动UIScrollViewUITableView滚动,您需要禁用您拥有的交互。

- (void)viewDidLoad
{
    [super viewDidLoad];
    _myScrollView.contentSize = CGSizeMake(2000, 0);
    data = [[NSMutableArray alloc]init];
    for(int i=0;i<30;i++)
    {
        [data addObject:[NSString stringWithFormat:@"%d",i]];
    }

    UITapGestureRecognizer * tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)];
    [self.view addGestureRecognizer:tap];
}

- (void)handleTap:(UITapGestureRecognizer *)recognizer
{
    [_myTableView setContentOffset:_myTableView.contentOffset animated:NO];
}

- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView
{
          scrollView.userInteractionEnabled = NO;
}

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
          scrollView.userInteractionEnabled = YES;
}

总结上面的代码,如果UITableView是滚动的,设置userInteractionEnabledNO这样UIScrollView会检测到滑动。如果UITableView正在滚动并且用户点击屏幕,userInteractionEnabled将设置为 YES。

于 2014-01-17T12:50:56.310 回答
0

与其UIScrollView用作这些多个表视图的容器,不如尝试使用UIPageViewController.

您甚至可以将其集成到您现有的视图控制器设置中child view controller(直接替换UIScrollView)。

此外,您可能希望实现所需的方法 fromUIPageViewControllerDataSource以及可能的一个或多个方法 from UIPageViewControllerDelegate

于 2013-09-30T02:39:15.680 回答
0

您是否尝试过以下方法:directionalLockEnabled您的表格和滚动并将它们设置为一个水平,另一个垂直?

编辑 :

1) 你想做的事情非常复杂,因为触摸会等待一段时间(比如 0.1 秒)才能知道你的动作是什么。而且,如果您的桌子正在移动,无论它是什么,它都会立即触动您(因为它应该是对它的反应性运动)。

我没有为您看到任何其他解决方案,而是从头开始覆盖触摸运动以立即检测您想要的运动类型(例如,如果运动将是水平的),但要做到这一点非常困难。

2) 我可以建议您的另一个解决方案是让您的表格具有左右边距,您可以在其中触摸父滚动(页面如此),然后即使您的表格正在滚动,如果您触摸这里,只有您的分页滚动会被触动。它更简单,但可能不适合您的设计......

于 2013-10-01T12:54:32.770 回答
0

UIPageViewController在方法中使用and -viewDidLoad(或任何其他最适合您的需要或设计的方法) getUIPageViewControllerUIScrollView子视图并为其分配一个委托。请记住,它的委托属性不会为零。因此,您可以选择将其分配给另一个引用,然后将符合 的对象分配UIScrollViewDelegate给它。例如:

id<UIScrollViewDelegate> originalPageScrollViewDelegate = ((UIScrollView *)[pageViewController.view.subviews objectAtIndex:0]).delegate;
[((UIScrollView *)[pageViewController.view.subviews objectAtIndex:0]) setDelegate:self];

这样您就可以UIScrollViewDelegate轻松实现方法。你UIPageViewController将调用你的委托-scrollViewDidScroll:方法。

顺便说一句,您可能不得不保留原始委托,并使用该对象响应委托方法。ViewPagerController您可以在我的 UI 控件项目的类查看示例实现

于 2013-10-07T20:03:52.163 回答
0

我最近遇到了同样的事情。我UIScrollview的页面处于分页模式,每个页面都包含一个UITableView并且就像您描述的那样有效,但不像您预期​​的那样有效。就这样解决了。

首先我禁用了滚动UIScrollview

然后我为左右滑动添加了一个UISwipeGestureRecognizer实际值。UITableView

这些滑动的动作是:

[scroll setContentOffset:CGPointMake(currentPointX + 320, PointY) animated:YES];
//Or
[scroll setContentOffset:CGPointMake(currentPointX - 320 , PointY) animated:YES];

这完美无缺,唯一的缺点是如果用户将手指拖动UITableVIew到将被视为滑动。他将无法在同一屏幕上看到屏幕 A 的一半和屏幕 B 的一半。

于 2014-01-17T11:11:58.910 回答
0

您可以将滚动视图和表格视图子类化,并将此手势识别器委托方法添加到它们中的每一个...

 - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer    
     shouldRecognizeSimultaneouslyWithGestureRecognizer:
                     (UIGestureRecognizer *)otherGestureRecognizer {
        return YES;
   }

我不能确定这正是你所追求的,但它可能会接近。

于 2014-01-17T18:29:02.430 回答