我已經有垂直滾動視圖所面臨的同樣的問題,使用的方法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