Ios UIScrollView类似于移动Safari选项卡的水平分页
MobileSafari允许您通过输入一种UIScrollView水平分页视图(底部有一个页面控件)来切换页面 我试图复制这种特殊的行为,即水平滚动的UIScrollView显示下一个视图的一些内容 苹果提供的示例:PageControl显示了如何使用UIScrollView进行水平分页,但所有视图都占据整个屏幕宽度Ios UIScrollView类似于移动Safari选项卡的水平分页,ios,iphone,cocoa-touch,uiscrollview,Ios,Iphone,Cocoa Touch,Uiscrollview,MobileSafari允许您通过输入一种UIScrollView水平分页视图(底部有一个页面控件)来切换页面 我试图复制这种特殊的行为,即水平滚动的UIScrollView显示下一个视图的一些内容 苹果提供的示例:PageControl显示了如何使用UIScrollView进行水平分页,但所有视图都占据整个屏幕宽度 如何获得UIScrollView以像mobile Safari那样显示下一个视图的某些内容?启用分页的UIScrollView将在其帧宽度(或高度)的倍数处停止。因此,第一步是确定
如何获得UIScrollView以像mobile Safari那样显示下一个视图的某些内容?启用分页的
UIScrollView将在其帧宽度(或高度)的倍数处停止。因此,第一步是确定页面的宽度。使其成为UIScrollView
的宽度。然后,根据需要设置子视图的大小,并根据UIScrollView
宽度的倍数设置其中心
然后,由于您想查看其他页面,当然,请将clipstobunds
设置为NO
,如前所述。现在的诀窍是当用户在UIScrollView
的框架范围外开始拖动时,让它滚动。我的解决方案(当我最近不得不这样做时)如下:
创建一个UIView
子类(即ClipView
),该子类将包含UIScrollView
及其子视图。本质上,它应该具有您认为在正常情况下UIScrollView
应该具有的框架。将UIScrollView
放在ClipView
的中心。如果ClipView
的宽度小于其父视图的宽度,请确保将其clipToBounds
设置为YES
。另外,ClipView
需要对UIScrollView
的引用
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
return [self pointInside:point withEvent:event] ? scrollView : nil;
}
最后一步是在ClipView
中覆盖-(UIView*)hitTest:withEvent:
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
return [self pointInside:point withEvent:event] ? scrollView : nil;
}
这基本上将UIScrollView
的触摸区域扩展到其父视图的框架,这正是您所需要的
另一个选项是子类化UIScrollView
并覆盖其-(BOOL)pointInside:(CGPoint)pointwithevent:(UIEvent*)event
方法,但是仍然需要容器视图来执行剪裁,仅根据UIScrollView
的框架,可能很难确定何时返回YES
注意:如果您在子视图用户交互方面遇到问题,您也应该看看Juri Pakaste的解决方案。上面的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;
}
我对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;
}
我已经做了另一个可以自动返回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;
}
我实现了上面的向上投票的建议,但是我使用的UICollectionView
认为帧外的任何内容都不在屏幕上。这导致当用户向附近的单元格滚动时,附近的单元格仅在边界外渲染,这是不理想的
我最后做的是通过将下面的方法添加到委托(或UICollectionViewLayout
)来模拟scrollview的行为
这完全避免了刷卡操作的委托,这也是一个额外的好处。UIScrollViewDelegate
有一个类似的方法,名为ScrollViewWillendDraging:withVelocity:targetContentOffset:
,可用于分页UITableView和UIScrollView。我的版本
按下滚动条上的按钮-工作=)
-(UIView*)hitTest:(CGPoint)point with event:(UIEvent*)event{
UIView*child=nil;
对于(int i=0;i启用在滚动视图的子视图上触发点击事件,同时支持此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;
}
(这是user1856273解决方案的一个变体。为了可读性而进行了清理,并合并了Bartserk的错误修复。我曾想过编辑user1856273的答案,但更改太大了。)我自己最终选择了自定义UIScrollView,因为它是我认为最快捷、最简单的方法。但是,我没有看到任何确切的代码,所以我想我会与大家分享。我需要的是一个内容小的UIScrollView,因此UIScrollView本身很小,无法实现分页效果。正如帖子所说的,你不能swipe穿过。但现在你可以了
创建CustomScrollView类和UIScrollView子类。然后,您只需将其添加到.m文件中:
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
return (point.y >= 0 && point.y <= self.frame.size.height);
}
-(BOOL)点内部:(CGPoint)点与事件:(UIEvent*)事件{
return(point.y>=0&&point.y将scrollView的框架大小设置为页面大小:
[self.view addSubview:scrollView];
[self.view addGestureRecognizer:mainScrollView.panGestureRecognizer];
现在您可以在self.view
上平移,滚动视图上的内容将被滚动。
还可以使用scrollView.clipsToBounds=NO;
来防止剪切内容。以下是基于Ed Marty的答案的快速回答,但也包括Juri Pakaste的修改,允许在scrollView内点击按钮等
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
let view = super.hitTest(point, with: event)
return view == self ? scrollView : view
}
只是一个想法…试着让滚动视图的边界比屏幕小,然后摆弄着让视图正确显示。(并将滚动视图的clipsToBounds设置为NO)我想让页面比uiscrollview的宽度(水平滚动)大。Mjoy的想法是真的
[self.view addSubview:scrollView];
[self.view addGestureRecognizer:mainScrollView.panGestureRecognizer];
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
let view = super.hitTest(point, with: event)
return view == self ? scrollView : view
}