90

UIScrollViewページングとスクロールがオンになっている を、特定の瞬間に垂直方向または水平方向にのみ移動させるにはどうすればよいですか?

私の理解では、directionalLockEnabledプロパティはこれを達成する必要がありますが、斜めにスワイプすると、動きが単一の軸に制限されるのではなく、ビューが斜めにスクロールされます。

編集:より明確にするために、ユーザーが水平方向または垂直方向にスクロールできるようにしたいと思いますが、両方を同時にスクロールすることはできません。

4

21 に答える 21

117

あなたは非常に厳しい状況にあります、私は言わなければなりません。

pagingEnabled=YESページを切り替えるには、でUIScrollViewを使用する必要がありますがpagingEnabled=NO、垂直方向にスクロールする必要があることに注意してください。

2つの可能な戦略があります。どちらが機能するか/実装が簡単かわからないので、両方を試してください。

最初:ネストされたUIScrollViews。率直に言って、これを機能させている人はまだいません。しかし、私は個人的に十分に努力していません。私の実践では、十分に努力すれば、UIScrollViewに好きなことをさせることができることを示しています。

したがって、戦略は、外側のスクロールビューが水平スクロールのみを処理し、内側のスクロールビューが垂直スクロールのみを処理するようにすることです。これを実現するには、UIScrollViewが内部でどのように機能するかを知っている必要があります。メソッドをオーバーライドhitTestし、常に自分自身を返すため、すべてのタッチイベントがUIScrollViewに入ります。次にtouchesBegan、内部touchesMovedなどで、イベントに関心があるかどうかをチェックし、それを処理するか、内部コンポーネントに渡します。

タッチを処理するか転送するかを決定するために、UIScrollViewは最初にタッチしたときにタイマーを開始します。

  • 150ミリ秒以内に指を大きく動かさなかった場合は、イベントが内部ビューに渡されます。

  • 150ミリ秒以内に指を大きく動かすと、スクロールが開始されます(イベントが内部ビューに渡されることはありません)。

    テーブル(スクロールビューのサブクラス)にタッチしてすぐにスクロールを開始すると、タッチした行が強調表示されないことに注意してください。

  • 150ミリ秒以内に指を大きく動かさ、UIScrollViewがイベントを内部ビューに渡し始めたが、スクロールを開始するのに十分な距離まで指を動かした場合、UIScrollViewは内部ビューを呼び出してスクロールを開始しますtouchesCancelled

    テーブルに触れ、指を少し押したままスクロールを開始すると、触れた行が最初に強調表示され、後で強調表示が解除されることに注意してください。

これらの一連のイベントは、UIScrollViewの構成によって変更できます。

  • NOの場合delaysContentTouches、タイマーは使用されません—イベントはすぐに内部コントロールに移動します(ただし、指を十分に動かすとキャンセルされます)
  • NOの場合cancelsTouches、イベントがコントロールに送信されると、スクロールは発生しません。

CocoaTouchからすべて touchesBegintouchesMoved、、、touchesEndedおよびイベントを受信するのはUIScrollViewであることに注意してください(そうするように指示されているため)。次に、必要に応じて、必要に応じてそれらを内部ビューに転送します。touchesCanceledhitTest

UIScrollViewについてすべて理解したので、その動作を変更できます。ユーザーがビューに触れて指を少しでも動かし始めると、ビューが垂直方向にスクロールし始めるように、垂直スクロールを優先することをお勧めします。ただし、ユーザーが指を水平方向に十分に動かしたときに、垂直スクロールをキャンセルして水平スクロールを開始する必要があります。

外側のUIScrollViewをサブクラス化して(たとえば、クラスにRemorsefulScrollViewという名前を付けます)、デフォルトの動作の代わりに、すべてのイベントをすぐに内側のビューに転送し、大きな水平方向の動きが検出された場合にのみスクロールします。

RemorsefulScrollViewをそのように動作させるにはどうすればよいですか?

  • delaysContentTouches垂直スクロールを無効にしてNOに設定すると、ネストされたUIScrollViewが機能するように見えます。残念ながら、そうではありません。UIScrollViewは、高速モーション(無効にすることはできません)に対して追加のフィルタリングを行うように見えます。そのため、UIScrollViewは水平方向にしかスクロールできない場合でも、常に十分な速度の垂直方向のモーションを消費します(無視します)。

    影響が非常に大きいため、ネストされたスクロールビュー内の垂直スクロールは使用できません。(この設定が正確に行われているようです。試してみてください。指を150ミリ秒間押し続けてから、垂直方向に移動します。ネストされたUIScrollViewは期待どおりに機能します!)

  • これは、UIScrollViewのコードをイベント処理に使用できないことを意味します。RemorsefulScrollViewの4つのタッチ処理メソッドすべてをオーバーライドし、最初に独自の処理を実行するsuper必要があります。水平スクロールを使用することにした場合にのみ、イベントを(UIScrollView)に転送します。

  • ただし、UIScrollViewに渡す必要があります。これはtouchesBegan、将来の水平スクロールのために基本座標を記憶する必要があるためです(後で水平スクロールであると判断した場合)。touchesBegan引数を格納できないため、後でUIScrollViewに送信することはできません。touches引数には、次のイベントの前に変更されるオブジェクトが含まれておりtouchesMoved、古い状態を再現することはできません。

    したがってtouchesBegan、すぐにUIScrollViewに渡す必要がありますが、touchesMoved水平方向にスクロールすることを決定するまで、UIScrollViewからそれ以上のイベントを非表示にします。NotouchesMovedはスクロールがないことを意味するので、このイニシャルtouchesBeganは害を及ぼしません。ただしdelaysContentTouches、追加のサプライズタイマーが干渉しないように、NOに設定してください。

    (オフトピック—あなたとは異なり、UIScrollViewタッチを適切に保存し、元のイベントを後で再現して転送できますtouchesBegan。未公開のAPIを使用するという不公平な利点があるため、変更される前にタッチオブジェクトのクローンを作成できます。)

  • 常に転送することを考えると、転送するtouchesBegan必要がtouchesCancelledありtouchesEndedます。ただし、UIScrollViewはシーケンスをタッチクリックとして解釈し、それtouchesEndedを内部ビューに転送するため、に変換する必要があります。すでに適切なイベントを自分で転送しているので、UIScrollViewに何も転送させたくありません。touchesCancelledtouchesBegantouchesEnded

基本的に、ここにあなたがする必要があることの擬似コードがあります。簡単にするために、マルチタッチイベントが発生した後は水平スクロールを許可しません。

// RemorsefulScrollView.h

@interface RemorsefulScrollView : UIScrollView {
  CGPoint _originalPoint;
  BOOL _isHorizontalScroll, _isMultitouch;
  UIView *_currentChild;
}
@end

// RemorsefulScrollView.m

// the numbers from an example in Apple docs, may need to tune them
#define kThresholdX 12.0f
#define kThresholdY 4.0f

@implementation RemorsefulScrollView

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

- (id)initWithCoder:(NSCoder *)coder {
  if (self = [super initWithCoder:coder]) {
    self.delaysContentTouches = NO;
  }
  return self;
}

- (UIView *)honestHitTest:(CGPoint)point withEvent:(UIEvent *)event {
  UIView *result = nil;
  for (UIView *child in self.subviews)
    if ([child pointInside:point withEvent:event])
      if ((result = [child hitTest:point withEvent:event]) != nil)
        break;
  return result;
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    [super touchesBegan:touches withEvent:event]; // always forward touchesBegan -- there's no way to forward it later
    if (_isHorizontalScroll)
      return; // UIScrollView is in charge now
    if ([touches count] == [[event touchesForView:self] count]) { // initial touch
      _originalPoint = [[touches anyObject] locationInView:self];
    _currentChild = [self honestHitTest:_originalPoint withEvent:event];
    _isMultitouch = NO;
    }
  _isMultitouch |= ([[event touchesForView:self] count] > 1);
  [_currentChild touchesBegan:touches withEvent:event];
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
  if (!_isHorizontalScroll && !_isMultitouch) {
    CGPoint point = [[touches anyObject] locationInView:self];
    if (fabsf(_originalPoint.x - point.x) > kThresholdX && fabsf(_originalPoint.y - point.y) < kThresholdY) {
      _isHorizontalScroll = YES;
      [_currentChild touchesCancelled:[event touchesForView:self] withEvent:event]
    }
  }
  if (_isHorizontalScroll)
    [super touchesMoved:touches withEvent:event]; // UIScrollView only kicks in on horizontal scroll
  else
    [_currentChild touchesMoved:touches withEvent:event];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
  if (_isHorizontalScroll)
    [super touchesEnded:touches withEvent:event];
    else {
    [super touchesCancelled:touches withEvent:event];
    [_currentChild touchesEnded:touches withEvent:event];
    }
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
  [super touchesCancelled:touches withEvent:event];
  if (!_isHorizontalScroll)
    [_currentChild touchesCancelled:touches withEvent:event];
}

@end

私はこれを実行したり、コンパイルしたりすることはしていません(そして、クラス全体をプレーンテキストエディターで入力しました)が、上記から始めて、うまくいけば動作させることができます。

私が見る唯一の隠れた落とし穴は、UIScrollView以外の子ビューをRemorsefulScrollViewに追加した場合、子がUIScrollViewのように常にタッチを処理しない場合、子に転送したタッチイベントがレスポンダーチェーンを介して戻ってくる可能性があることです。防弾のRemorsefulScrollView実装は、touchesXxx再突入から保護します。

2番目の戦略:何らかの理由でネストされたUIScrollViewが機能しない場合、または正しく実行するのが難しい場合は、1つのUIScrollViewだけを使用して、デリゲートメソッドpagingEnabledからそのプロパティをオンザフライで切り替えることができます。scrollViewDidScroll

斜めのスクロールを防ぐには、最初にcontentOffsetを記憶し、斜めの動きを検出した場合はscrollViewWillBeginDragging内部のcontentOffsetを確認してリセットする必要があります。scrollViewDidScroll試すもう1つの戦略は、contentSizeをリセットして、ユーザーの指がどちらの方向に進むかを決定したら、一方向へのスクロールのみを有効にすることです。(UIScrollViewは、デリゲートメソッドからcontentSizeとcontentOffsetをいじることについてかなり寛容なようです。)

それが機能しないか、見た目が悪くなる場合はtouchesBegantouchesMovedなどをオーバーライドする必要があり、斜めの動きのイベントをUIScrollViewに転送しないでください。(ただし、この場合、ユーザーエクスペリエンスは最適ではありません。これは、斜めの動きを一方向に強制するのではなく無視する必要があるためです。本当に冒険心がある場合は、RevengeTouchのような独自のUITouchのそっくりさんを作成できます。Objective -Cは昔ながらのCであり、Cほどダックタイプのものはありません。オブジェクトの実際のクラスをチェックする人がいない限り、他のクラスのように見せることができます。これにより、他のクラスと同じように見せることができます。好きなタッチを好きな座標で合成する可能性。)

バックアップ戦略: TTScrollViewがあります。これは、 Three20ライブラリのUIScrollViewの適切な再実装です。残念ながら、それはユーザーにとって非常に不自然で非響きを感じます。ただし、UIScrollViewを使用するたびに失敗した場合は、カスタムコード化されたスクロールビューにフォールバックできます。可能であれば、これに反対することをお勧めします。UIScrollViewを使用すると、将来のiPhone OSバージョンでどのように進化しても、ネイティブのルックアンドフィールを確実に得ることができます。

さて、この小さなエッセイは少し長すぎました。数日前にScrollingMadnessで作業した後、私はまだUIScrollViewゲームに夢中です。

PSこれらのいずれかが機能し、共有したい場合は、関連するコードをandreyvit@gmail.comに電子メールで送信してください。これを、ScrollingMadnessのトリックバッグに入れておきます。

PPSこの小さなエッセイをScrollingMadnessREADMEに追加します。

于 2009-05-10T03:28:18.543 に答える
56

これは私にとって毎回うまくいきます...

scrollView.contentSize = CGSizeMake(scrollView.frame.size.width * NumberOfPages, 1);
于 2010-07-07T18:51:25.137 に答える
15

この問題を解決するために次の方法を使用しました。

最初に、コントローラーのヘッダー ファイルで次の変数を定義します。

CGPoint startPos;
int     scrollDirection;

デリゲートがscrollViewWillBeginDraggingメッセージを受信すると、startPos はcontentOffset値を保持します。したがって、このメソッドではこれを行います。

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{
    startPos = scrollView.contentOffset;
    scrollDirection=0;
}

次に、これらの値を使用して、scrollViewDidScrollメッセージでユーザーが意図したスクロール方向を決定します。

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

   if (scrollDirection==0){//we need to determine direction
       //use the difference between positions to determine the direction.
       if (abs(startPos.x-scrollView.contentOffset.x)<abs(startPos.y-scrollView.contentOffset.y)){          
          NSLog(@"Vertical Scrolling");
          scrollDirection=1;
       } else {
          NSLog(@"Horitonzal Scrolling");
          scrollDirection=2;
       }
    }
//Update scroll position of the scrollview according to detected direction.     
    if (scrollDirection==1) {
       [scrollView setContentOffset:CGPointMake(startPos.x,scrollView.contentOffset.y) animated:NO];
    } else if (scrollDirection==2){
       [scrollView setContentOffset:CGPointMake(scrollView.contentOffset.x,startPos.y) animated:NO];
    }
 }

最後に、ユーザーがドラッグを終了したときにすべての更新操作を停止する必要があります。

 - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{
    if (decelerate) {
       scrollDirection=3;
    }
 }
于 2010-11-09T15:41:07.410 に答える
13

私はここで掘り下げているかもしれませんが、私は同じ問題を解決しようとしていたので、今日この投稿に出くわしました。これが私の解決策です、うまく機能しているようです。

画面一杯のコンテンツを表示したいのですが、ユーザーが他の4つの画面一杯のいずれかに上下左右にスクロールできるようにします。サイズが320x480でcontentSizeが960x1440の単一のUIScrollViewがあります。コンテンツオフセットは320,480から始まります。scrollViewDidEndDecelerating:で、5つのビュー(中央のビューとその周囲の4つのビュー)を再描画し、コンテンツのオフセットを320,480にリセットします。

これが私のソリューションの要であるscrollViewDidScroll:メソッドです。

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{   
    if (!scrollingVertically && ! scrollingHorizontally)
    {
        int xDiff = abs(scrollView.contentOffset.x - 320);
        int yDiff = abs(scrollView.contentOffset.y - 480);

        if (xDiff > yDiff)
        {
            scrollingHorizontally = YES;
        }
        else if (xDiff < yDiff)
        {
            scrollingVertically = YES;
        }
    }

    if (scrollingHorizontally)
    {
        scrollView.contentOffset = CGPointMake(scrollView.contentOffset.x, 480);
    }
    else if (scrollingVertically)
    {
        scrollView.contentOffset = CGPointMake(320, scrollView.contentOffset.y);
    }
}
于 2010-03-04T01:04:41.037 に答える
4

サブビューの高さをスクロールビューの高さやコンテンツサイズの高さと同じにするのと同じくらい簡単です。次に、垂直スクロールが無効になります。

于 2010-06-05T19:26:30.587 に答える
3

UIScrollViewこれは、直交スクロールのみを許可するページングの私の実装です。に設定pagingEnabledしてくださいYES

PagedOrthoScrollView.h

@interface PagedOrthoScrollView : UIScrollView
@end

PagedOrthoScrollView.m

#import "PagedOrthoScrollView.h"

typedef enum {
  PagedOrthoScrollViewLockDirectionNone,
  PagedOrthoScrollViewLockDirectionVertical,
  PagedOrthoScrollViewLockDirectionHorizontal
} PagedOrthoScrollViewLockDirection; 

@interface PagedOrthoScrollView ()
@property(nonatomic, assign) PagedOrthoScrollViewLockDirection dirLock;
@property(nonatomic, assign) CGFloat valueLock;
@end

@implementation PagedOrthoScrollView
@synthesize dirLock;
@synthesize valueLock;

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

  self.dirLock = PagedOrthoScrollViewLockDirectionNone;
  self.valueLock = 0;

  return self;
}

- (void)setBounds:(CGRect)bounds {
  int mx, my;

  if (self.dirLock == PagedOrthoScrollViewLockDirectionNone) {
    // is on even page coordinates, set dir lock and lock value to closest page 
    mx = abs((int)CGRectGetMinX(bounds) % (int)CGRectGetWidth(self.bounds));
    if (mx != 0) {
      self.dirLock = PagedOrthoScrollViewLockDirectionHorizontal;
      self.valueLock = (round(CGRectGetMinY(bounds) / CGRectGetHeight(self.bounds)) *
                        CGRectGetHeight(self.bounds));
    } else {
      self.dirLock = PagedOrthoScrollViewLockDirectionVertical;
      self.valueLock = (round(CGRectGetMinX(bounds) / CGRectGetWidth(self.bounds)) *
                        CGRectGetWidth(self.bounds));
    }

    // show only possible scroll indicator
    self.showsVerticalScrollIndicator = dirLock == PagedOrthoScrollViewLockDirectionVertical;
    self.showsHorizontalScrollIndicator = dirLock == PagedOrthoScrollViewLockDirectionHorizontal;
  }

  if (self.dirLock == PagedOrthoScrollViewLockDirectionHorizontal) {
    bounds.origin.y = self.valueLock;
  } else {
    bounds.origin.x = self.valueLock;
  }

  mx = abs((int)CGRectGetMinX(bounds) % (int)CGRectGetWidth(self.bounds));
  my = abs((int)CGRectGetMinY(bounds) % (int)CGRectGetHeight(self.bounds));

  if (mx == 0 && my == 0) {
    // is on even page coordinates, reset lock
    self.dirLock = PagedOrthoScrollViewLockDirectionNone;
  }

  [super setBounds:bounds];
}

@end
于 2011-08-28T13:59:58.980 に答える
3

今後の参考のために、私は Andrey Tanasov の回答に基づいて構築し、正常に機能する次のソリューションを思いつきました。

最初に contentOffset を格納する変数を定義し、それを 0,0 座標に設定します

var positionScroll = CGPointMake(0, 0)

scrollView デリゲートに以下を実装します。

override func scrollViewWillBeginDragging(scrollView: UIScrollView) {
    // Note that we are getting a reference to self.scrollView and not the scrollView referenced passed by the method
    // For some reason, not doing this fails to get the logic to work
    self.positionScroll = (self.scrollView?.contentOffset)!
}

override func scrollViewDidScroll(scrollView: UIScrollView) {

    // Check that contentOffset is not nil
    // We do this because the scrollViewDidScroll method is called on viewDidLoad
    if self.scrollView?.contentOffset != nil {

        // The user wants to scroll on the X axis
        if self.scrollView?.contentOffset.x > self.positionScroll.x || self.scrollView?.contentOffset.x < self.positionScroll.x {

            // Reset the Y position of the scrollView to what it was BEFORE scrolling started
            self.scrollView?.contentOffset = CGPointMake((self.scrollView?.contentOffset.x)!, self.positionScroll.y);
            self.scrollView?.pagingEnabled = true
        }

        // The user wants to scroll on the Y axis
        else {
            // Reset the X position of the scrollView to what it was BEFORE scrolling started
            self.scrollView?.contentOffset = CGPointMake(self.positionScroll.x, (self.scrollView?.contentOffset.y)!);
            self.collectionView?.pagingEnabled = false
        }

    }

}

お役に立てれば。

于 2015-10-21T12:39:14.940 に答える
3

私もこの問題を解決しなければなりませんでした.Andrey Tarantsovの答えには、どのようにUIScrollViews機能するかを理解するための有用な情報がたくさんありますが、解決策は少し複雑すぎると感じています. サブクラス化やタッチ転送を含まない私の解決策は次のとおりです。

  1. 各方向に 1 つずつ、2 つのネストされたスクロール ビューを作成します。
  2. 2 つのダミーUIPanGestureRecognizersを作成します。これも各方向に 1 つずつです。
  3. UIScrollViews' panGestureRecognizer プロパティと、セレクターUIPanGestureRecognizerを使用して、UIScrollView の目的のスクロール方向に垂直な方向に対応するダミーとの間に失敗の依存関係を作成しますUIGestureRecognizer's -requireGestureRecognizerToFail:
  4. -gestureRecognizerShouldBegin:ダミーの UIPanGestureRecognizersのコールバックで、ジェスチャの -translationInView: セレクターを使用してパンの初期方向を計算しUIPanGestureRecognizersます (タッチがパンとして登録するのに十分に変換されるまで、このデリゲート コールバックは呼び出されません)。計算された方向に応じてジェスチャ レコグナイザーの開始を許可または禁止します。これにより、垂直 UIScrollView パン ジェスチャ レコグナイザーの開始を許可するかどうかを制御する必要があります。
  5. では-gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:、ダミーUIPanGestureRecognizersをスクロールと一緒に実行させないでください (追加したい追加の動作がある場合を除きます)。
于 2014-07-02T18:50:31.833 に答える
2

私がしたことは、ビュー画面のサイズのフレームでページング UIScrollView を作成し、コンテンツ サイズをすべてのコンテンツに必要な幅と高さ 1 に設定することでした (Tonetel に感謝)。次に、各ページにフレームが設定されたメニュー UIScrollView ページ、ビュー画面のサイズを作成し、それぞれのコンテンツ サイズを画面の幅とそれぞれに必要な高さに設定しました。次に、各メニュー ページをページング ビューに追加するだけです。ページング スクロール ビューではページングが有効になっているが、メニュー ビューではページングが無効になっていることを確認してください (デフォルトでは無効になっているはずです)。

ページング スクロール ビューは水平方向にスクロールするようになりましたが、コンテンツの高さのために垂直方向にはスクロールしません。各ページは垂直にスクロールしますが、コンテンツのサイズにも制約があるため、水平にはスクロールしません。

その説明が望まれるものを残した場合のコードは次のとおりです。

UIScrollView *newPagingScrollView =  [[UIScrollView alloc] initWithFrame:self.view.bounds]; 
[newPagingScrollView setPagingEnabled:YES];
[newPagingScrollView setShowsVerticalScrollIndicator:NO];
[newPagingScrollView setShowsHorizontalScrollIndicator:NO];
[newPagingScrollView setDelegate:self];
[newPagingScrollView setContentSize:CGSizeMake(self.view.bounds.size.width * NumberOfDetailPages, 1)];
[self.view addSubview:newPagingScrollView];

float pageX = 0;

for (int i = 0; i < NumberOfDetailPages; i++)
{               
    CGRect pageFrame = (CGRect) 
    {
        .origin = CGPointMake(pageX, pagingScrollView.bounds.origin.y), 
        .size = pagingScrollView.bounds.size
    };
    UIScrollView *newPage = [self createNewPageFromIndex:i ToPageFrame:pageFrame]; // newPage.contentSize custom set in here        
    [pagingScrollView addSubview:newPage];

    pageX += pageFrame.size.width;  
}           
于 2011-09-12T18:08:07.493 に答える
2

ありがとうトネテル。私はあなたのアプローチを少し変更しましたが、それはまさに水平スクロールを防ぐために必要なものでした.

self.scrollView.contentSize = CGSizeMake(self.scrollView.contentSize.width, 1);
于 2010-08-07T17:25:05.527 に答える
1

大きなスクロールビューがあり、斜めスクロールを制限したい場合http://chandanshetty01.blogspot.in/2012/07/restricting-diagonal-scrolling-in.html

于 2012-07-10T09:58:12.973 に答える
1

ドキュメントから:

「デフォルト値は NO です。これは、水平方向と垂直方向の両方でスクロールが許可されていることを意味します。値が YES で、ユーザーが 1 つの一般的な方向 (水平または垂直) にドラッグを開始した場合、スクロール ビューは他の方向のスクロールを無効にします。 "

重要な部分は、「ユーザーが一般的な方向にドラッグし始めた場合」だと思います。したがって、それらが斜めにドラッグし始めた場合、これは機能しません。解釈に関しては、これらのドキュメントが常に信頼できるというわけではありませんが、それはあなたが見ているものに合っているようです.

これは実際には賢明なようです。お聞きしたいのですが、いつでも水平または垂直のみに制限したいのはなぜですか? おそらく UIScrollView はあなたのためのツールではありませんか?

于 2009-04-08T00:28:55.253 に答える
1

私のビューは 10 個の水平ビューで構成されており、それらのビューの一部は複数の垂直ビューで構成されているため、次のようになります。


1.0   2.0   3.1    4.1
      2.1   3.1
      2.2
      2.3

横軸と縦軸の両方でページングを有効にした場合

ビューには次の属性もあります。

[self setDelaysContentTouches:NO];
[self setMultipleTouchEnabled:NO];
[self setDirectionalLockEnabled:YES];

斜めスクロールを防ぐには、次のようにします。

-(void)scrollViewDidScroll:(UIScrollView *)scrollView {
    int pageWidth = 768;
    int pageHeight = 1024;
    int subPage =round(self.contentOffset.y / pageHeight);
    if ((int)self.contentOffset.x % pageWidth != 0 && (int)self.contentOffset.y % pageHeight != 0) {
        [self setContentOffset:CGPointMake(self.contentOffset.x, subPage * pageHeight];
    } 
}

私にとって魅力のように機能します!

于 2010-08-17T11:02:34.297 に答える
1

_isHorizontalScrollおよびで NO にリセットする必要がtouchesEndedありtouchesCancelledます。

于 2009-10-09T07:04:55.297 に答える
0

3.0 ベータ版でこれを試したことがない場合は、試してみることをお勧めします。現在、スクロール ビュー内で一連のテーブル ビューを使用していますが、期待どおりに動作します。(とにかく、スクロールはします。まったく別の問題の修正を探しているときにこの質問を見つけました...)

于 2009-06-09T06:05:33.217 に答える
0

@AndreyTarantsovでSwiftを見ている人にとって、2番目のソリューションはコードで次のようになります。

    var positionScroll:CGFloat = 0

    func scrollViewWillBeginDragging(scrollView: UIScrollView) {
        positionScroll = self.theScroll.contentOffset.x
    }

    func scrollViewDidScroll(scrollView: UIScrollView) {
        if self.theScroll.contentOffset.x > self.positionScroll || self.theScroll.contentOffset.x < self.positionScroll{
             self.theScroll.pagingEnabled = true
        }else{
            self.theScroll.pagingEnabled = false
        }
    }

ここで行っているのは、スクロールビューがドラッグされる直前に現在の位置を保持し、x の現在の位置と比較して x が増加または減少したかどうかを確認することです。はいの場合、pagingEnabled を true に設定し、そうでない場合 (y が増加/減少)、pagingEnabled を false に設定します。

新規参入者に役立つことを願っています!

于 2015-06-28T12:00:18.977 に答える
-3

インターフェイス ビルダーを使用してインターフェイスを設計している場合、これは非常に簡単に行うことができます。

インターフェイス ビルダーで UIScrollView をクリックし、(インスペクターで) 一方向スクロールのみに制限するオプションを選択します。

于 2009-04-07T23:47:52.730 に答える