Mobile Safari允许您通过输入一种UIScrollView水平分页视图来切换页面,页面控件位于底部。

我正在尝试复制这种特殊行为,其中水平可滚动的UIScrollView显示下一个视图的内容。

Apple提供的示例:PageControl显示如何使用UIScrollView进行水平分页,但所有视图占用整个屏幕宽度。

如何让UIScrollView显示移动Safari的下一个视图的某些内容?

有帮助吗?

解决方案

启用分页的UIScrollView将停止在其帧宽(或高度)的倍数处。因此,第一步是确定您希望页面的宽度。将其宽度设为clipsToBounds。然后,将子视图的大小设置为您需要的大小,并根据NO的宽度的倍数设置它们的中心。

然后,因为你想看到其他页面,当然,将UIView设置为ClipView,如mhjoy所述。现在的技巧部分是当用户在YES框架范围之外开始拖动时滚动它。我的解决方案(当我最近必须这样做时)如下:

创建一个- (UIView *)hitTest:withEvent:子类(即- (BOOL)pointInside:(CGPoint) point withEvent:(UIEvent *) event),其中包含<=>及其子视图。从本质上讲,它应该具有你在正常情况下假设<=>的框架。将<=>放在<=>的中心。如果<=>的<=>的宽度小于其父视图的宽度,请确保<=>设置为<=>。此外,<=>需要引用<=>。

最后一步是在<=>中覆盖<=>。

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
  return [self pointInside:point withEvent:event] ? scrollView : nil;
}

这基本上将<=>的触摸区域扩展到其父视图的框架,正是您所需要的。

另一种选择是子类<=>并覆盖它的<=>方法,但是你仍然需要一个容器视图来进行剪切,并且可能很难确定何时返回<=>仅基于<=>的框架。

注意: 您还应该看一下Juri Pakaste的 hitTest:withEvent:modification 如果您遇到子视图用户交互问题。

其他提示

上面的ClipView解决方案对我有用,但我必须做一个不同的-[UIView hitTest:withEvent:]实现。 Ed Marty的版本没有使用垂直滚动视图处理用户交互,而是在水平滚动视图中。

以下版本对我有用:

-(UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event
{
    UIView* child = nil;
    if ((child = [super hitTest:point withEvent:event]) == self)
        return self.scrollView;     
    return child;
}

设置scrollView的帧大小,因为您的页面大小为:

[self.view addSubview:scrollView];
[self.view addGestureRecognizer:mainScrollView.panGestureRecognizer];

现在您可以平移self.view,滚动滚动内容。
也可以使用scrollView.clipsToBounds = NO;来防止剪切内容。

我自己选择使用自定义UIScrollView,因为它是我看来最快捷,最简单的方法。但是,我没有看到任何确切的代码,所以我想分享。我的需求是UIScrollView具有较小的内容,因此UIScrollView本身很小,以实现分页效果。正如帖子所说,你无法滑过。但现在你可以。

创建一个类CustomScrollView和子类UIScrollView。然后你需要做的就是将它添加到.m文件中:

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
  return (point.y >= 0 && point.y <= self.frame.size.height);
}

这允许您从一侧滚动到另一侧(水平)。相应地调整边界以设置滑动/滚动触摸区域。享受!

我做了另一个可以自动返回scrollview的实现。因此,它不需要有一个IBOutlet来限制项目中的重复使用。

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    if ([self pointInside:point withEvent:event]) {
        for (id view in [self subviews]) {
            if ([view isKindOfClass:[UIScrollView class]]) {
                return view;
            }
        }
    }
    return nil;
}

我对ClipView hitTest实现有另一个可能有用的修改。我不喜欢向ClipView提供UIScrollView引用。我在下面的实现允许您重新使用ClipView类来扩展任何东西的命中测试区域,而不必为它提供参考。

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    if (([self pointInside:point withEvent:event]) && (self.subviews.count >= 1))
    {
        // An extended-hit view should only have one sub-view, or make sure the
        // first subview is the one you want to expand the hit test for.
        return [self.subviews objectAtIndex:0];
    }

    return nil;
}

我实施了上面提出的建议,但UICollectionView我正在使用框架内的任何内容都不在屏幕上。这导致附近的单元格在用户向它们滚动时仅渲染出界限,这是不理想的。

我最终做的是通过将以下方法添加到委托(或UICollectionViewLayout)来模拟scrollview的行为。

- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity
{    
  if (velocity.x > 0) {
    proposedContentOffset.x = ceilf(self.collectionView.contentOffset.x / pageSize) * pageSize;
  }
  else {
    proposedContentOffset.x = floorf(self.collectionView.contentOffset.x / pageSize) * pageSize;
  }

  return proposedContentOffset;
}

这完全避免了滑动操作的授权,这也是一个奖励。 UIScrollViewDelegate有一个名为scrollViewWillEndDragging:withVelocity:targetContentOffset:的类似方法,可用于页面UITableViews和UIScrollViews。

在支持此SO问题的技术的同时,在滚动视图的子视图上启用触发点击事件。使用对滚动视图的引用(self.scrollView)以便于阅读。

- (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    UIView *hitView = nil;
    NSArray *childViews = [self.scrollView subviews];
    for (NSUInteger i = 0; i < childViews.count; i++) {
        CGRect childFrame = [[childViews objectAtIndex:i] frame];
        CGRect scrollFrame = self.scrollView.frame;
        CGPoint contentOffset = self.scrollView.contentOffset;
        if (childFrame.origin.x + scrollFrame.origin.x < point.x + contentOffset.x &&
            point.x + contentOffset.x < childFrame.origin.x + scrollFrame.origin.x + childFrame.size.width &&
            childFrame.origin.y + scrollFrame.origin.y < point.y + contentOffset.y &&
            point.y + contentOffset.y < childFrame.origin.y + scrollFrame.origin.y + childFrame.size.height
        ){
            hitView = [childViews objectAtIndex:i];
            return hitView;
        }
    }
    hitView = [super hitTest:point withEvent:event];
    if (hitView == self)
        return self.scrollView;
    return hitView;
}

将其添加到您的子视图以捕获触摸事件:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event

(这是对用户1856273解决方案的一种变体。为了便于阅读而进行了清理并整合了Bartserk的错误修复。我想到了编辑user1856273的答案,但这个改变太大了。)

我的版本 按下滚动上的按钮 - 工作=)

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    UIView* child = nil;
    for (int i=0; i<[[[[self subviews] objectAtIndex:0] subviews] count];i++) {

        CGRect myframe =[[[[[self subviews] objectAtIndex:0] subviews]objectAtIndex:i] frame];
        CGRect myframeS =[[[self subviews] objectAtIndex:0] frame];
        CGPoint myscroll =[[[self subviews] objectAtIndex:0] contentOffset];
        if (myframe.origin.x < point.x && point.x < myframe.origin.x+myframe.size.width &&
            myframe.origin.y+myframeS.origin.y < point.y+myscroll.y && point.y+myscroll.y < myframe.origin.y+myframeS.origin.y +myframe.size.height){
            child = [[[[self subviews] objectAtIndex:0] subviews]objectAtIndex:i];
            return child;
        }


    }

    child = [super hitTest:point withEvent:event];
    if (child == self)
        return [[self subviews] objectAtIndex:0];
    return child;
    }

但只有[[self subviews] objectAtIndex:0]必须是滚动

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top