この質問が古い場合、私はここで解決策を見つけられず、答えることは素晴らしいと感じました。
簡単な答えは、UIScrollViewDelegateプロトコルのscrollViewWillEndDragging:withVelocity:targetContentOffset: メソッドです。
ユーザーがスクロールを終了し、アニメーションが減速を開始すると、targetContentOffsetが表示されます。このメソッドでtargetContentOffsetを変更することができますので、できる限りアニメーションが終了します。あなたの仕事は目標位置を計算することだけです。
ここに私が作成したUIViewサブクラスがあります。私はクラスのようなUIPickerViewを作成したいと思っていましたが、特定の位置(日付ピッカーのようなもの)で止めたかったです。
UIScrollViewDelegateに準拠したUIViewサブクラスを作成しました。このUIViewでは、私はscrollviewを追加しました。このスクロールビューには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
この問題を回避するには、 'UIScrollView'をサブクラス化し、' hitTest:withEvent: 'をオーバーライドして、スクロール可能な領域内のもの(この場合は親ビューの全幅)に対して' YES'を返します。 –
私はそれを試みるべきです。しかし、ページング・スクロール・ビューは別の根本的な問題となります。ユーザーが「クイックスワイプ」をすると、1回の画像(または固定された画像セット)だけが毎回右にスクロールするでしょうか?それは、スワイプの距離とスピードに応じて毎回スクロールするイメージの数が変わるフリースクロールビューのようなものではありません。申し訳ありませんが、ここに悪魔の提唱者を演じているimのように見えますが、機能性を正しく取得しようとしています。 – Nathan