2010-12-13 21 views
0

iPadアプリの水平スクロールビューを実装しようとしています。スクロールビューには一連の画像が表示されます。スクロールした後、スクロールビューが停止すると、水平方向に沿って特定の点に沿って画像が整列されます。これを行うには、私は2つのアプローチを試しました:特定の位置でUIScrollViewを停止する

1)UIScrollViewのスクロールを無効にし、代わりに "スワイプ/ドラッグ"モーションの移動と速度を検出し、スクロールビューのコンテンツオフセットを設定するPanGestureRecogniserを実装します必要な所定のポイントしかし、ここで問題となるのは、ユーザがスクロールビューをゆっくりドラッグすると、スクロールビューの取り出されたxが、指が押されたポイントの前後で前後にジャンプするため、スクロールビューの動きが非常にぎくしゃくするということです。たとえば:指が60-70に沿って動くと、x値は50から70になります。スクロールビューの動きを滑らかにするにはどうすればいいですか?

2)UIScrollViewのスクロールを有効にし、減速の終了を確認して、スクロールビューのコンテンツオフセットを設定して、必要な位置に調整します。しかし、ここでの問題は、スクロールビューが減速を停止し、目に見える遅れがあり、このアニメーションもうまく見えない場合にのみ、最終位置にスクロールビューが調整されることです。スクロール・ビューがスクロールを止めようとしているときにそれを検出し、スクロールを終了するのを待つのではなく、その位置を調整する方法がありますか?いくつかのフォーラムで何が読まれているのか、これは可能ではありません。

3)画像の幅全体をスクロールさせたくないので、このシナリオではページングスクロールビューは機能しません。

誰も私が上記の機能をどのように実装できるかについてのアイデアはありませんか?

答えて

1

これを行うには、実際にはページングスクロールビューを使用できます。スクロールビュー内のコンテンツがフレーム外でレンダリングされるように、clipsToBoundsNOに設定し、frameを希望のアライメントステップに設定するだけです。あなたは200の倍数にスクロールビューを整列する場合

たとえば、あなたがこれを行うことができます:私は垂直scrollviewと同じ問題に直面したとしてもアプローチ2を使用しました

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

+0

この問題を回避するには、 'UIScrollView'をサブクラス化し、' hitTest:withEvent: 'をオーバーライドして、スクロール可能な領域内のもの(この場合は親ビューの全幅)に対して' YES'を返します。 –

+0

私はそれを試みるべきです。しかし、ページング・スクロール・ビューは別の根本的な問題となります。ユーザーが「クイックスワイプ」をすると、1回の画像(または固定された画像セット)だけが毎回右にスクロールするでしょうか?それは、スワイプの距離とスピードに応じて毎回スクロールするイメージの数が変わるフリースクロ​​ールビューのようなものではありません。申し訳ありませんが、ここに悪魔の提唱者を演じているimのように見えますが、機能性を正しく取得しようとしています。 – Nathan

2

この質問が古い場合、私はここで解決策を見つけられず、答えることは素晴らしいと感じました。

簡単な答えは、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 
+0

これを投稿していただきありがとうございます。 UICollectionViewで同じ問題が発生しました。メソッドドキュメンテーションは、このアプローチを示唆していることに注意してください。 "あなたのアプリケーションは、scrollControlがスクロールアニメーションをどこで終了するかを調整するためにtargetContentOffsetパラメータの値を変更することができます。 – JLundell

関連する問題