2010-12-13 60 views
0

我试图为iPad应用程序实现水平滚动视图。滚动视图显示一系列图像。滚动后,当滚动视图停止时,我希望图像沿着水平线的特定点对齐。为此,我尝试了两种方法:停止在特定位置的UIScrollView

1)禁用UIScrollView的滚动,而是实现PanGestureRecogniser,它将检测“滑动/拖动”运动的平移和速度,并相应地将滚动视图的内容偏移设置为所需的预定点数。但是,这里的问题在于,如果用户缓慢地拖动滚动视图,则滚动视图运动非常不稳定,因为滚动视图的所检索的x坐标在手指按下的点周围来回跳动。例如:当手指沿60-70移动时,x值从50到70。我如何使滚动视图的运动平滑?

2)启用UIScrollView的滚动并检查减速结束,然后设置滚动视图的内容偏移量以将其调整到必要的位置。但问题在于,滚动视图只有在停止减速之后才会调整到最终位置,并且存在可见的延迟,并且该动画看起来不太好。有没有办法可以检测滚动视图何时停止滚动,然后调整其位置而不是等待滚动结束。从某些论坛上阅读的内容来看,这是不可能的。

3)在这种情况下,分页滚动视图不起作用,因为我不希望图像的整个宽度被滚出。

有没有人有关于如何实现上述功能的任何想法。

回答

1

您实际上仍然可以使用分页滚动视图来执行此操作。您只需将clipsToBounds设置为NO(以便滚动视图中的内容可以在其帧外呈现),然后将frame设置为所需的对齐步骤。

例如,如果要对齐的200的倍数滚动视图,你可以这样做:

scrollView.pagingEnabled = YES; 
scrollView.clipsToBounds = NO; 

// horizontally center scroll view with a width of 200 and the parent's height 
scrollView.frame = CGRectMake(
    floor((parentView.bounds.size.width - 200)/2), 
    0, 
    200, 
    parentView.bounds.size.height 
); 

[parentView addSubview:scrollView]; 
+0

真。但在这种情况下,“可滚动/可滑动”区域的宽度也会被限制为200?这意味着用户将无法滑过图像渲染的整个水平部分,并且仅限于在200个单位内滚动/滑动。我希望用户能够滚动滚动视图的整个宽度。 – Nathan 2010-12-13 13:41:56

+0

你可以通过继承'UIScrollView'并重写'hitTest:withEvent:'来​​回滚'YES'来区分这个问题,在你想要滚动的区域内(在这个例子中是父视图的全部宽度)。 – 2010-12-13 16:20:19

+0

好的,我应该尝试。但是,通过Paging滚动视图来解决另一个基本问题。如果用户进行“快速滑动”,那么只有一个图像(或一组固定图像)每次都会向右滚动?它不会像一个自由滚动视图,每次滚动出来的图像数量会根据滑动的距离和速度而变化。对不起,如果它看起来像我在这里扮演魔鬼的倡导者,但我只是想获得正确的功能。 – Nathan 2010-12-15 07:49:14

2

我已经有垂直滚动视图所面临的同样的问题,使用的方法2.即使如果这个问题很老,我没有在这里找到解决方案,并且觉得它会很好回答。

简短回答是UIScrollViewDelegate协议中的scrollViewWillEndDragging:withVelocity:targetContentOffset: 方法。

当用户完成滚动并且动画开始减速时,它会为您提供targetContentOffset。您可以在此方法中更改targetContentOffset,以便动画将尽可能地结束。你的工作只是计算目标位置。

这里是我创建的UIView子类。我想创建一个UIPickerView类,但我想它停止在特定位置(如日期选择器)

我创建了一个符合UIScrollViewDelegate的UIView子类。在这个UIView中,我添加了一个滚动视图。这个滚动视图将包含UILabel实例。小心我使用ARC,所以我不释放任何东西。

#import <UIKit/UIKit.h> 

@protocol MyPickerViewDataSource <NSObject> 

-(NSUInteger)numberOfRowsForSender:(id)sender; 
-(NSString *)titleForRowAtIndex:(NSUInteger)rowIndex sender:(id)sender; 

@end 

@interface MyPickerView : UIView <UIScrollViewDelegate> 

@property (weak, nonatomic) id<MyPickerViewDataSource> dataSource; 

@end 

实施:

#import "MyPickerView.h" 

#define CONTENT_ROW_HEIGHT 30 

typedef enum { 
    ScrollDirectionUp, 
    ScrollDirectionDown 
} ScrollDirection; 

@interface MyPickerView() { 

    int topOffset; 
    int bottomOffset; 
    int lastContentOffset; 
    int targetLabelIndex; 
    ScrollDirection scrollDirection; 
} 

@implementation PickerView 

- (void)initSetup { 
self.scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(self.frame.origin.x,self.frame.origin.y, self.frame.size.width, self.frame.size.height)]; 
self.scrollView.delegate = self; 
self.scrollView.showsHorizontalScrollIndicator = NO; 
self.scrollView.showsVerticalScrollIndicator = NO; 
self.scrollView.userInteractionEnabled = YES; 
[self addSubview:self.scrollView]; 

targetLabelIndex = 0; 

topOffset = (self.scrollView.frame.size.height/2)-CONTENT_ROW_HEIGHT/2; 
bottomOffset = topOffset; 
} 

- (id)initWithCoder:(NSCoder *)aDecoder { 
    self = [super initWithCoder:aDecoder]; 
    if(self) { 
     [self initSetup]; 
    } 
    return self; 
} 

- (id)initWithFrame:(CGRect)frame { 
    self = [super initWithFrame:frame]; 
    if(self) { 
     [self initSetup]; 
    } 
    return self; 
} 

- (void)layoutSubviews { 

    [super layoutSubviews]; 

    NSUInteger numberOfRows = [self.dataSource numberOfRowsForSender:self]; 

    self.scrollView.contentSize = CGSizeMake(self.scrollView.frame.size.width, topOffset+numberOfRows*CONTENT_ROW_HEIGHT+bottomOffset); 

    for (int index = 0; index < numberOfRows; index++) 
    { 
     UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(self.scrollView.frame.origin.x, 
                    topOffset+index*CONTENT_ROW_HEIGHT, 
                    self.scrollView.frame.size.width, 
                    CONTENT_ROW_HEIGHT)]; 

     label.backgroundColor = [UIColor clearColor]; 
     label.textColor = [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:1.0]; 
     label.text = [self.dataSource titleForRowAtIndex:index sender:self]; 

     [self.scrollView addSubview:label]; 
    } 

    [(UILabel *)[self.scrollView.subviews objectAtIndex:targetLabelIndex] setTextColor:[UIColor blueColor]]; 
} 

- (void)reloadData { 

    NSUInteger numberOfRows = [self.dataSource numberOfRowsForSender:self]; 

    self.scrollView.contentSize = CGSizeMake(self.scrollView.frame.size.width, numberOfRows*CONTENT_ROW_HEIGHT); 

    [self.scrollView setContentOffset:CGPointMake(0.0, 0.0) animated:NO]; 

    [self layoutSubviews]; 
} 

#pragma mark - UIScrollViewDelegate 

- (void)scrollViewDidScroll:(UIScrollView *)scrollView { 

    if(lastContentOffset>self.scrollView.contentOffset.y) { 

     scrollDirection = ScrollDirectionUp; 
    } 
    else { 

     scrollDirection = ScrollDirectionDown; 
    } 

    lastContentOffset = self.scrollView.contentOffset.y; 
} 

- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset { 

    targetLabelIndex = (targetContentOffset->y/CONTENT_ROW_HEIGHT)+1; 

    if(scrollDirection==ScrollDirectionUp && targetLabelIndex>0) { 

     targetLabelIndex--; 
    } 

    targetContentOffset->y = targetLabelIndex*CONTENT_ROW_HEIGHT; 

    [(UILabel *)[self.scrollView.subviews objectAtIndex:targetLabelIndex] setTextColor:[UIColor blueColor]]; 
} 

@end 
+0

感谢您发布此信息;我遇到了与UICollectionView相同的问题。我注意到方法文档提出了这种方法:“您的应用程序可以更改targetContentOffset参数的值,以调整滚动视图完成其滚动动画的位置。” – JLundell 2013-04-08 16:37:53