UIScrollViewでスクロールをプログラムで強制停止するにはどうすればよいですか?


80

注:ここで与えられた答えは私にはうまくいきません。

UIScrollView(テーブルビューではなく、カスタムのもの)があり、ユーザーが特定のアクションを実行したときに、ビュー内のスクロール(ドラッグまたは減速)をすべて終了したいと思います。私は例えばこれをやってみました:

[scrollView scrollRectToVisible:CGRectInset([scrollView bounds], 10, 10) animated:NO];

すでに表示されていることがわかっている四角形を指定すると、スクロールはその場所で停止するだけですが、これは効果がないことがわかります。スクロールビューでは、指定された四角形が範囲内にあることがわかります。何もしない。現在表示されている境界の外側であるが、ビューのcontentSizeの内側にある四角形を指定すると、スクロールを停止できます。これにより、ビューが期待どおりに停止するようですが、他の場所にジャンプすることもあります。私はおそらくこれを合理的にうまく機能させるために余白で少し遊んでみることができますが、誰かがそのことをしているスクロールビューを停止するクリーンな方法を知っていますか?

ありがとう。

回答:


108

私はあなたの元の解決策で少し遊んだ、そしてこれはうまくいくようだ。ほぼ持っていたと思いますが、使いすぎたrectをオフセットしていて、rectをまっすぐスクロールして元のrectに戻すことができることを忘れていました。

スクロールアクションの一般的な解決策は次のとおりです。

- (void)killScroll 
{
    CGPoint offset = scrollView.contentOffset;
    offset.x -= 1.0;
    offset.y -= 1.0;
    [scrollView setContentOffset:offset animated:NO];
    offset.x += 1.0;
    offset.y += 1.0;
    [scrollView setContentOffset:offset animated:NO];
}

[編集] iOS 4.3(およびおそらくそれ以前)以降、これも機能するようです

- (void)killScroll 
{
    CGPoint offset = scrollView.contentOffset;
    [scrollView setContentOffset:offset animated:NO];
}

1
David:ありがとう。私はこの方向に自分自身をいじっていましたが、スクロール境界のすぐ外側にある1x1の四角形を選択することについての簡単な計算ではなくなりました。オフセットしてすぐに復元するという提案を取り入れると(「結果」が正常に機能しない場合でも、1つのイベントの連続した呼び出しが実際に機能する未公開の動作を利用するように率直に思われます)、正常に機能します。上記の回答を編集して、どのスクロール方向でも機能する一般化されたソリューションを含めます。ありがとう!
ベンゾット2010

(編集を気にしないで、後の旅行者のために明確にしたかったのですが。答えてくれてありがとう!)
Ben Zotto 2010

見栄えがいいです...ところで、どうやって元の場所に戻るのですか?オフセットを強制終了する前に保存してから、そこに戻りますか?
Lior Frenkel

2
iOS 7では、scrollView isDeceleratingの場合、最上位のソリューションのみが機能します(+ = 1、-= 1ソリューション)。
Sahil 2014

1
このソリューションは改善できます。+ = 1の代わりに+ = 0.1を使用するので、1回の呼び出しでsetContentOffset十分です。スクロールビューは、コンテンツオフセットを自動的に切り上げます。
ケリン2015年

91

一般的な答えはそれ、ある[scrollView setContentOffset:offset animated:NO]ある同じではありませんよう[scrollView setContentOffset:offset]

  • [scrollView setContentOffset:offset animated:NO] 実際に実行中のアニメーションを停止します。
  • [scrollView setContentOffset:offset] 実行中のアニメーションを停止しません。
  • 同じscrollView.contentOffset = offset:実行中のアニメーションを停止しません。

これはどこにも文書化されていませんが、iOS6.1とiOS7.1でテストされた動作です。おそらく以前にもそうです。

したがって、実行中のアニメーション/減速を停止するソリューションは次のように簡単です。

[scrollView setContentOffset:scrollView.contentOffset animated:NO];

基本的に、DavidLiuが編集した回答で言ったこと。しかし、これら2つのAPIは同じではないことを明確にしたいと思いました。

スウィフト3:

scrollView.setContentOffset(scrollView.contentOffset, animated:false)

11
私たちの間の「理由探求者」への説明でよくやった...(:
Aviel Gross 2015

3
でもこれはちょっと悲しくなります。
DCMaxxx 2015年

2
このようなものが文書化されていない理由がわかりません... urggggghh
user1105951

(少なくとも)iOS 11.3および11.4でさらに興味深いのは、次のとおりです。contentOffsetがたとえば(300、0)にアニメーション化されると、アニメーションの実行中に「contentOffset =(300、0)」が割り当てられ、contentOffsetは次のようにリセットされる場合があります。 (0、0)!これはバグに違いありません!
1

68

私にとって、上記のDavidLuiの受け入れられた答えは私にとってはうまくいきませんでした。これは私がやったことです:

- (void)killScroll {
    self.scrollView.scrollEnabled = NO;
    self.scrollView.scrollEnabled = YES;
}

その価値のために、私はiOS 6.0 iPhoneSimulatorを使用しています。


2
あなたが言ったように+1、もう一方も私にはうまくいきませんでしたが、この解決策はうまくいきました!
brenjt 2013

1
素晴らしいsupportedInterfaceOrientationsですが、ユーザーがスクロール中にデバイスを回転させている場合にスクロールイベントが続行されないようにするために完全に機能します。これは、実行していることによっては混乱することがあります。
cprcrack 2013年

21

これは、スクロールビューと他のすべての関連サブクラスに対して行うことです。

- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
 {
    *targetContentOffset = scrollView.contentOffset;
 }

これにより、targetContentOffsetscrollView現在のオフセットに設定され、ターゲットに到達したためにスクロールが停止します。実際には、ユーザーがターゲットを設定できることを目的としたメソッドを使用することは理にかなっていますcontentOffset

迅速

func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
    targetContentOffset.pointee = scrollView.contentOffset
}

これは、開発者が使用すると思われる1つのリンゴのように見えます。他のすべてはある時点でバグにつながるからです。私はこれが受け入れられた答えではないことに驚いています。
OlDor 2016年

これが、このデリゲートメソッドの目的です。素晴らしい答え。
ライアン

私の意見では、これはAppleがドキュメントで述べているように、最も洗練されたソリューションです。「アプリケーションはtargetContentOffsetパラメータの値を変更して、scrollviewがスクロールアニメーションを終了する場所を調整できます。」私にとっては非常にうまくいきました
Macistador 2017年

これが正解です。上記のどれも私には
うまくいき

20

スクロールをすばやく停止します:

scrollView.setContentOffset(scrollView.contentOffset, animated: false)

16

実際には...最も「現代的な」方法は->

scrollview.panGestureRecognizer.enabled = false;
scrollview.panGestureRecognizer.enabled = true;

これにより、現在のタッチを強制終了する瞬間のスクロールを担当するジェスチャ認識機能が非アクティブになります。ユーザーは、再びスクロールを開始するには、指を持ち上げて元に戻す必要があります。

編集:これは実際にはユーザーの現在のドラッグを強制終了しますが、スクロールビューが現在この状態にある場合は減速をすぐには停止しません。これを行うには、受け入れられた回答の編集がxDの最善の方法です。

[scrollview setContentOffset: scrollview.contentOffset animated:false];

私はこれを私のアプリで使用しており、OPから要求されたとおりに動作します。もう少しコンテキストを教えていただけますか?何が機能していないのですか、それともなぜですか?
xatian 2014

ああごめんなさい...私は知っていると思います...私はちょうど私が探していた質問の部分に答えました...私が見落とした2番目の部分...:-)->編集しました。
xatian 2014

減速を止めません。
ルドルフアダムコビッチ2015年

5

最もクリーンな方法は、UIScrollViewをサブクラス化し、独自のsetContentOffsetメソッドを提供することです。これは、ブールプロパティをオンにしていない場合にのみ、メッセージを渡す必要がありますfreeze

そのようです:

BOOL freeze; // and the @property, @synthesize lines..

-(void)setContentOffset:(CGPoint)offset
{
    if ( !freeze ) [super setContentOffset:offset];
}

次に、フリーズするには:

scrollView.freeze = YES;

1
ありがとう。これにより、表示されているスクロールは停止しますが、実際には内部減速は停止しません。これをオンに切り替えてからしばらくすると再びオフにすると、スクロールが一時停止し、先にジャンプして減速を続けます。したがって、scrollviewの内部状態はまだスクロールしています。したがって、減速が停止したことがわかるまでフリーズする必要があります。これは、代理人と協力して行うことができますが、私には少し間抜けな感じがします。私は実際にただすぐに減速を打ち負かす何かを望んでいます(例えば、画面をシングルタップする効果があります)。
ベンゾット2010

わかりました、これらの種類の問題は以前の経験からおなじみのように聞こえます...decelerationRate = 1e10;フリーズ==はいの間に設定して減速をザッピングしてみませんか?
mvds 2010

(内部の計算がわからない場合、10 * UIScrollViewDecelerationRateFastは1e10よりも賢明な選択かもしれません)
mvds 2010

面白いアイデア!残念ながら、この値は固定されているようです。試してみましたが、減速がすぐに止まるような値はないようです。私にできる最善のことは、それを遅くすることです。:)
ベンゾット2010

プランBは、スクロールを短期間無効にすることです。とにかくsetContentOffsetをブロックしているので、それを回避できるかもしれません。副作用によってスクロールが無効になるのを防ぐことができます。
mvds 2010


3

ユーザー操作をスクロールするだけで無効にします。(迅速)

scrollView.isScrollEnabled = false

ドラッグ後のスクロールアニメーション中に無効にします。(迅速)

var scrollingByVelocity = false

func scrollViewWillBeginDecelerating(_ scrollView: UIScrollView) {
    if !scrollingByVelocity {
        scrollView.setContentOffset(scrollView.contentOffset, animated: false)
    }
}

0

私はcollectionviewでこのメソッドを試しました:

self.collectionView.collectionViewLayout.finalizeCollectionViewUpdates()


0

これは、中に私の作品スウィフト4.2

   func killScroll() {
    self.scrollView.isScrollEnabled = false;
    self.scrollView.isScrollEnabled = true;
}

...拡張機能として:

extension UIScrollView {
    func killScroll() {
        self.isScrollEnabled = false;
        self.isScrollEnabled = true;

    }
}

0

スクロールビュー内の特定のUIViewがスワイプ中のタッチのソースである場合にのみ、スクロールを無効にしたかったのです。ビュー階層が複雑なため、UIViewをUIScrollViewの外に移動するには、かなりのリファクタリングが必要でした。

回避策として、スクロールを防止したいサブビューに単一のUIPanGestureRecognizerを追加しました。このUIPanGestureRecognizerはcancelsTouchesInView、UIScrollViewのpanGestureがアクティブになるのを防ぎます。

これは少し「ハック」ですが、非常に簡単な変更です。XIBまたはストーリーボードを使用している場合は、パンジェスチャを問題のサブビューにドラッグするだけです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.