40

私はかなり単純なビュー構成を持っています:

A 、これUIViewControllerに子供UIScrollViewとA がいます。可視領域から抜け出すのに十分な高さでを設定し(つまり、 より高く)、my の制約を固定の正の値 (たとえば) に設定します。UIImageViewUIScrollViewUIImageView1024ptBottom space to superviewUIImageView20

プロジェクトのレイアウト

セットアップ全体が期待どおりに機能し、画像はその親でうまくスクロールします。ビューがスクロールされた場合 (ビューの一番下までスクロールすると、効果がより見やすくなります) が消え、再び表示される場合 (別のビューに切り替えて戻ってきた場合) を除き、スクロール値は復元されますが、スクロール ビューは、その親ビューの外側上部に移動されます。

これを説明するのは簡単ではありません。 前の段落の視覚的表現

ソース (またはストーリーボード) をテスト/表示したい場合は、コードを 1 行も編集していません。github に小さなデモを置きました: https://github.com/guillaume-algis/iOSAutoLayoutScrollView

iOS 6 の変更ログとこの特定のトピックに関する説明を読みましたが、これは 2 番目のオプション (純粋な自動レイアウト) の正しい実装だと思いますが、この場合、UIScrollView動作が不安定なのはなぜですか? 何か不足していますか?

編集:これは#12580434 uiscrollview-autolayout-issueとまったく同じ問題です。誰かがこれを修正する適切な方法を見つけたので、答えは単なる回避策ですか、それともこれは iOS のバグですか?

EDIT 2:スクロール位置をユーザーが残した状態と同じ状態に保つ別の回避策を見つけました(これは12580434の受け入れられた回答に対する改善です):

@interface GAViewController ()

@property CGPoint tempContentOffset;

@end


@implementation GAViewController

-(void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    self.tempContentOffset = self.mainScrollView.contentOffset;
    self.scrollView.contentOffset = CGPointZero;
}

-(void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];

    self.scrollView.contentOffset = self.tempContentOffset;
}

これは基本的に、オフセットを に保存viewWillAppearし、原点にリセットしてから、 に値を復元しますviewDidAppear。問題はこれら 2 つの呼び出しの間に発生しているようですが、その原因がわかりません。

4

7 に答える 7

22

ええ、純粋な自動レイアウト環境で UIScrollView に奇妙なことが起こりました。iOS SDK 6.0 のリリース ノートを 20 回読み直したところ、次のことがわかりました。

スクロール ビューのスーパービューなど、スクロール ビューのサブツリーの外側にあるビューとビューの間に制約を作成することで、スクロール ビューのサブビューを他のスクロール コンテンツの上に浮かんでいる (スクロールしない) ように見せることができることに注意してください。

解決

サブビューを外側のビューに接続します。つまり、スクロールビューが埋め込まれたビューに。

IB では、imageView とスクロール ビューのサブツリーの外側のビュー (スクロール ビューのスーパービューなど) の間に制約を設定することはできないため、コードでそれを行いました。

- (void)viewDidLoad {
    [super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
    [self.view removeConstraints:[self.view constraints]];
    [self.scrollView removeConstraints:[self.scrollView constraints]];
    [self.imageView removeConstraints:[self.imageView constraints]];
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|[_scrollView]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_scrollView)]];
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_scrollView]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_scrollView)]];
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|[_imageView(700)]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_imageView)]];
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_imageView(1500)]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_imageView)]];
}

そしてヴァウ!できます!

于 2013-03-11T22:48:22.347 に答える
10

編集は私にはうまくいきませんでした。しかし、これはうまくいきました:

-(void)viewWillDisappear:(BOOL)animated
{
     [super viewWillDisappear:animated];

     self.tempContentOffset = self.scrollView.contentOffset;
     self.scrollView.contentOffset = CGPointZero;
}

- (void)viewDidLayoutSubviews {
     [super viewDidLayoutSubviews];
     self.scrollView.contentOffset = self.tempContentOffset;
}
于 2013-08-21T19:24:27.620 に答える
5

私にとっては、スクロールビューを含むView ControllerをクリックしてIBに行きました。次に、Attribute Inspector -> View Controller -> Extend Edges -> [Under Top Bars] と [Under Bottom Bars] のチェックを外しました。

于 2014-12-05T20:27:19.170 に答える
-4

dispatch_async中に問題が解決したように見えますviewWillAppear:

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    CGPoint originalContentOffset = self.scrollView.contentOffset;
    self.scrollView.contentOffset = CGPointZero;

    dispatch_async(dispatch_get_main_queue(), ^{
        self.scrollView.contentOffset = originalContentOffset;
    });
}
于 2013-08-27T20:43:21.280 に答える