我已经有垂直滚动视图所面临的同样的问题,使用的方法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
真。但在这种情况下,“可滚动/可滑动”区域的宽度也会被限制为200?这意味着用户将无法滑过图像渲染的整个水平部分,并且仅限于在200个单位内滚动/滑动。我希望用户能够滚动滚动视图的整个宽度。 – Nathan 2010-12-13 13:41:56
你可以通过继承'UIScrollView'并重写'hitTest:withEvent:'来回滚'YES'来区分这个问题,在你想要滚动的区域内(在这个例子中是父视图的全部宽度)。 – 2010-12-13 16:20:19
好的,我应该尝试。但是,通过Paging滚动视图来解决另一个基本问题。如果用户进行“快速滑动”,那么只有一个图像(或一组固定图像)每次都会向右滚动?它不会像一个自由滚动视图,每次滚动出来的图像数量会根据滑动的距离和速度而变化。对不起,如果它看起来像我在这里扮演魔鬼的倡导者,但我只是想获得正确的功能。 – Nathan 2010-12-15 07:49:14