如何强制在分页和滚动都开启的情况下,UIScrollView
在给定时刻只能沿垂直或水平方向移动?
我理解 directionalLockEnabled
属性可以实现这一点,但是对角线滑动仍然会导致视图在两个方向上同时滚动而不是限制在单个轴上。
编辑:更明确地说,我希望允许用户水平或垂直滚动,但不能同时进行。
如何强制在分页和滚动都开启的情况下,UIScrollView
在给定时刻只能沿垂直或水平方向移动?
我理解 directionalLockEnabled
属性可以实现这一点,但是对角线滑动仍然会导致视图在两个方向上同时滚动而不是限制在单个轴上。
编辑:更明确地说,我希望允许用户水平或垂直滚动,但不能同时进行。
UIScrollView *newPagingScrollView = [[UIScrollView alloc] initWithFrame:self.view.bounds];
[newPagingScrollView setPagingEnabled:YES];
[newPagingScrollView setShowsVerticalScrollIndicator:NO];
[newPagingScrollView setShowsHorizontalScrollIndicator:NO];
[newPagingScrollView setDelegate:self];
[newPagingScrollView setContentSize:CGSizeMake(self.view.bounds.size.width * NumberOfDetailPages, 1)];
[self.view addSubview:newPagingScrollView];
float pageX = 0;
for (int i = 0; i < NumberOfDetailPages; i++)
{
CGRect pageFrame = (CGRect)
{
.origin = CGPointMake(pageX, pagingScrollView.bounds.origin.y),
.size = pagingScrollView.bounds.size
};
UIScrollView *newPage = [self createNewPageFromIndex:i ToPageFrame:pageFrame]; // newPage.contentSize custom set in here
[pagingScrollView addSubview:newPage];
pageX += pageFrame.size.width;
}
这是改进的icompot解决方案,相比之前的版本更加稳定。它易于实现,以下是具体步骤:
- (void) scrollViewWillBeginDragging: (UIScrollView *) scrollView
{
self.oldContentOffset = scrollView.contentOffset;
}
- (void) scrollViewDidScroll: (UIScrollView *) scrollView
{
float XOffset = fabsf(self.oldContentOffset.x - scrollView.contentOffset.x );
float YOffset = fabsf(self.oldContentOffset.y - scrollView.contentOffset.y );
if (scrollView.contentOffset.x != self.oldContentOffset.x && (XOffset >= YOffset) )
{
scrollView.pagingEnabled = YES;
scrollView.contentOffset = CGPointMake(scrollView.contentOffset.x,
self.oldContentOffset.y);
}
else
{
scrollView.pagingEnabled = NO;
scrollView.contentOffset = CGPointMake( self.oldContentOffset.x,
scrollView.contentOffset.y);
}
}
- (void) scrollViewDidEndDecelerating: (UIScrollView *) scrollView
{
self.oldContentOffset = scrollView.contentOffset;
}
1.0 2.0 3.1 4.1
2.1 3.1
2.2
2.3
在水平和垂直轴上启用分页
视图还具有以下属性:
[self setDelaysContentTouches:NO];
[self setMultipleTouchEnabled:NO];
[self setDirectionalLockEnabled:YES];
现在要防止对角线滚动,请执行以下操作:
-(void)scrollViewDidScroll:(UIScrollView *)scrollView {
int pageWidth = 768;
int pageHeight = 1024;
int subPage =round(self.contentOffset.y / pageHeight);
if ((int)self.contentOffset.x % pageWidth != 0 && (int)self.contentOffset.y % pageHeight != 0) {
[self setContentOffset:CGPointMake(self.contentOffset.x, subPage * pageHeight];
}
}
对我来说简直太棒了!
需要在touchesEnded
和touchesCancelled
中将_isHorizontalScroll
重置为NO。
来自文档:
“默认值为NO,这意味着可以在水平和垂直方向上滚动。如果值为YES并且用户开始沿一个方向(水平或垂直)拖动,则滚动视图禁用另一个方向的滚动。”
我认为重要的部分是“如果...用户开始沿一个方向拖动”。因此,如果他们开始对角线拖动,这种情况不会发生。 虽然这些文档在解释方面并不总是可靠 - 但这似乎符合您所看到的情况。
这实际上似乎很明智。我必须问一下 - 为什么您想随时限制只水平或只垂直?也许UIScrollView不适合您?
如果您有一个大的滚动视图...并且想要限制对角线滚动http://chandanshetty01.blogspot.in/2012/07/restricting-diagonal-scrolling-in.html
对于那些在Swift中查看@AndreyTarantsov的第二个解决方案,代码如下:
var positionScroll:CGFloat = 0
func scrollViewWillBeginDragging(scrollView: UIScrollView) {
positionScroll = self.theScroll.contentOffset.x
}
func scrollViewDidScroll(scrollView: UIScrollView) {
if self.theScroll.contentOffset.x > self.positionScroll || self.theScroll.contentOffset.x < self.positionScroll{
self.theScroll.pagingEnabled = true
}else{
self.theScroll.pagingEnabled = false
}
}
我们在这里做的是在scrollview被拖动之前保持当前位置,然后检查x是否与当前位置的x相比增加或减少。如果是,则将pagingEnabled设置为true;如果不是(y已经增加/减少),则将pagingEnabled设置为false。
希望对新手有所帮助!
如果你还没有在3.0 beta中尝试过这个,我建议你试一试。我目前正在使用一个滚动视图内的一系列表视图,它的效果正如预期一样。(好吧,至少滚动是可以的。当我在寻找解决一个完全不同的问题时,发现了这个问题...)
// add this property to your view controller
var positionScroll: CGPoint = .zero
// make sure to set isDirectionalLockEnabled to true on your scroll view
self.scrollView.isDirectionalLockEnabled = true
// then in scrollview/collectionview/tableview delegate
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
positionScroll = scrollView.contentOffset
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
// The user wants to scroll on the X axis
if scrollView.contentOffset.x > positionScroll.x || scrollView.contentOffset.x < positionScroll.x {
// Reset the Y position of the scrollView to what it was before scrolling started
scrollView.contentOffset = CGPoint(x: scrollView.contentOffset.x, y: positionScroll.y)
scrollView.isPagingEnabled = true
} else {
// The user wants to scroll on the Y axis
// Reset the X position of the scrollView to what it was before scrolling started
scrollView.contentOffset = CGPoint(x: positionScroll.x, y: scrollView.contentOffset.y)
scrollView.isPagingEnabled = false
}
}
我通过实现scrollViewDidBeginDragging(_:), 并查看底层UIPanGestureRecognizer的速度来解决了这个问题。
NB: 使用这种解决方案,每个斜向滑动都将被scrollView忽略。
override func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
super.scrollViewWillBeginDragging(scrollView)
let velocity = scrollView.panGestureRecognizer.velocity(in: scrollView)
if velocity.x != 0 && velocity.y != 0 {
scrollView.panGestureRecognizer.isEnabled = false
scrollView.panGestureRecognizer.isEnabled = true
}
}