さまざまなサブビューを含むUIViewController
を含むストーリーボードのシーンとしてUIScrollView
サブクラスがあります。サブビューの1つは、別のシーンUIButton
サブクラスにセグメンテーションするUIViewController
です。ビューから戻ったとき(Navigation ControllerスタックからUIViewController
をポップ)、スクロールビューのOriginが何らかの形で変更されていることがわかりますが、contentsize
とcontentoffset
は正しい。
また興味深いのは、アプリにタブバーがあることです。タブビューでそのビューに戻ると、スクロールビューはオフセット(0、0)で正しく設定されます。
ストーリーボードにはほとんどすべてのコードがあるため、基本的にこのプロセスに関係するコードはありません。ストーリーボードを使用するのはかなり新しいので、何が間違っているのかわかりませんが、何をするのかわかりません。それが何であるかについてのアイデアはありますか?おそらくサイジングの問題や制約ですか?
実際、そのコード行をviewDidDisappear
に配置し、ビューが再表示されたときにオフセットを記憶するように、その前にこの行を追加しました
self.contentOffset = self.scrollView.contentOffset;
と同様
- (void)viewDidLayoutSubviews {
self.scrollView.contentOffset = self.contentOffset;
}
IOS 7/8/9シンプルself.automaticallyAdjustsScrollViewInsets = NO;
私の場合、問題を解決しました。
これを、表示するView ControllerのviewWillAppearで試してください:
self.scrollView.contentOffset = CGPointMake(0, 0);
編集:Peterのコードも追加すると、次のように最適な結果が得られます
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:YES];
self.scrollView.contentOffset = CGPointMake(0, 0);
}
プラス
- (void)viewWillDisappear:(BOOL)animated {
self.recentContentOffset = self.scrollView.contentOffset;
[super viewWillDisappear:animated];
}
そして
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
self.scrollView.contentOffset = CGPointMake(0, self.recentContentOffset.y);
}
元のスクロール位置に戻り、視覚的な副作用がなく、スクロールビュー自体が戻ってきた後、スーパービュー(問題でした)に正しく配置されます。
同様の問題がありました。viewControllerを閉じた後、tableViewのcontentOffsetが(0、-64)に変更されました。
私の解決策は少し奇妙で、他のすべての答えを試してみましたが成功しませんでした。私の問題を解決した唯一のことは、.xibのコントロールツリーでtableViewの位置を切り替えることでした
これは、次のような親ビューの最初のコントロールでした:
ImageViewの直後にtableViewを移動し、動作しました:
テーブルビューを最初の位置に置くことが問題の原因であり、テーブルビューを別の位置に移動すると問題が解決したようです。
P.D. autoLayoutもストーリーボードも使用していません
これが誰かを助けることを願っています!
CollectionViewを使用していますが、同様の問題がありました。 iOS 11の場合:サイズインスペクターに「コンテンツインセット」があります。それを「Never」に設定します。これで問題は解決しました。これが誰かの役に立つことを願っています。
目標C:
if (@available(iOS 11, *)) {
[UIScrollView appearance].contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
}
迅速:
if #available(iOS 11, *) {
UIScrollView.appearance().contentInsetAdjustmentBehavior = .never
}
IOS 11では、View Controllerをポップした後に戻ると、以前のViewControllerのTableViewがコンテンツのインセットを自動的に調整し、TableViewのコンテンツが突然上からジャンプするという同様の問題に直面しました。次のソリューションはiOS 11で機能しました。
ストーリーボードで、tableviewを選択し、属性インスペクターに移動して、[行の高さ]および[見積もり]フィールドの[自動]のチェックを外します。また、コンテンツのインセットを「自動」から「なし」に変更します。
[]
残念ながら、PeterとMacMarkの提案はうまくいきませんでした(Xcode 5 w/auto-layout)。解決策は、ストーリーボードに移動し、View Controllerを選択して、Reset to Suggested Constraints in View Controller
。
私は最近、同様の問題に関する質問を投稿しましたが、異なるコンテキストで: フレームは、モーダルビューコントローラーを閉じた後、自動レイアウト制約を反映しません
私の場合、スクロールビュー自体の原点ではなく、スクロールビュー内のカスタムコンテナビューの原点が移動します。自動レイアウトに関して、カスタムコンテナビューはスクロールビューの4つの側面に固定されます。
コンテナビューは、IBではなくプログラムで作成および構成されます。コンテナビューの制約は変更されていませんが、モーダルビューコントローラを閉じると、コンテナビューのOriginは移動します。制約とフレームの間のこの切断は不可解です。
さらに注目に値するのは、関連するすべての制約を削除して再度追加した後、Originの変位問題が残っていたことです。
同様の解決策を思いつきました:現在のコンテンツオフセットの値を保存し、コンテンツオフセットを「ゼロ」に設定し、システムにビューをスワップさせ、コンテンツオフセット(つまり、コンテンツオフセットダンス)を復元します。
ただし、私の場合は、問題を解決するために追加の手順を実行する必要がありました。私のスクロールビューは、(古いWWDCビデオでデモされた)tilePagesメソッドからサブビューを取得するページングスクロールビューです。スクロールビューのコンテンツオフセットを変更すると、UIScrollViewDelegateのscrollViewDidScroll:メソッドを介してtilePagesメソッドがトリガーされます。 content-offsetダンスを行っている間にtilePagesをオフにするフラグを設定する必要がありました。そうしないと、アプリがクラッシュしました。
IOS 7にアップグレードするときに、コンテンツオフセットダンスのコードを削除できれば幸いです。
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
if ([[[UIDevice currentDevice] systemVersion] floatValue] < 7) {
_isRecoredforios6 = YES;
_recordedOffsetforios6 = _scrollView.contentOffset;
_recordedSizeforios6 = _scrollView.contentSize;
_scrollView.contentOffset = CGPointZero;
}
}
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
if (_isRecoredforios6) {
_isRecoredforios6 = NO;
_scrollView.contentSize = _recordedSizeforios6;
_scrollView.contentOffset = _recordedOffsetforios6;
}
}
このios6バグを修正しましたが、これらのコードを使用して解決できます。 Scrollviewで発生したバグを解決しました。何より私の友人に感謝します!
SOの至る所に投稿されているさまざまなソリューションの組み合わせを使用して、このサブクラスを思い付きました。
// Keeps track of the recent content offset to be able to restore the
// scroll position when a modal viewcontroller is dismissed
class ScrollViewWithPersistentScrollPosition: UIScrollView {
// The recent content offset for restoration.
private var recentContentOffset: CGPoint = CGPoint(x: 0, y: 0)
override func willMove(toWindow newWindow: UIWindow?) {
if newWindow != nil {
// save the scroll offset.
self.recentContentOffset = self.contentOffset
}
super.willMove(toWindow: newWindow)
}
override func didMoveToWindow() {
if self.window != nil {
// restore the offset.
DispatchQueue.main.async(execute: {
// restore it
self.contentOffset = self.recentContentOffset
})
}
super.didMoveToWindow()
}
}
IOS 11.2/Xcode 9.2でテスト済み。
表示中のView Controllerを残さずに、表示中のView Controllerを開こうとすると、問題が残りました。これがexact stepsを投稿し、それが私のソリューションをもたらした理由です。
したがって、I reset StoryboardのcollectionViewの制約は、presentingViewControllerのメインビューに固定されていることを確認します。
追加:self.view.translatesAutoresizingMaskIntoConstraints = YES;
表示するView ControllerのviewDidLoad
内。
そしてstored、プライベートには、モーダル表示されたView Controllerの外観の前のコレクションビューのcontentOffset:
(void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
self.contentOffset = self.collectionView.contentOffset;
self.collectionView.contentOffset = CGPointZero;
}
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
self.collectionView.contentOffset = self.contentOffset;
}
最近、私はこれらのコードを使用して解決できるこのバグに遭遇しました:
// fix ios 6 bug begin
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
if ([[[UIDevice currentDevice] systemVersion] floatValue] < 7) {
isRecoredforios6 = YES;
recordedOffsetforios6 = self.tableView.contentOffset;
recordedSizeforios6 = self.tableView.contentSize;
}
}
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
if (isRecoredforios6) {
isRecoredforios6 = NO;
self.tableView.contentSize = recordedSizeforios6;
self.tableView.contentOffset = recordedOffsetforios6;
}
}
// fix ios 6 bug end
ピーター・ジェイコブスに感謝!
上記のどれもうまくいきませんでした。代わりに、独自のカスタムプッシュ/プルアニメーションを実行することができました。
最初に、プッシュシナリオを実装するこのクラスを追加します
class PushAnimator: NSObject, UIViewControllerAnimatedTransitioning, UIViewControllerTransitioningDelegate {
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return 0.5
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
// get reference to our fromView, toView and the container view that we should perform the transition in
let container = transitionContext.containerView
let fromView = transitionContext.view(forKey: UITransitionContextViewKey.from)!
let toView = transitionContext.view(forKey: UITransitionContextViewKey.to)!
// start the toView to the right of the screen
var frame = toView.frame
frame.Origin.x = container.frame.width
toView.frame = frame
// add the both views to our view controller
container.addSubview(toView)
container.addSubview(fromView)
// get the duration of the animation
let duration = self.transitionDuration(using: transitionContext)
// perform the animation!
UIView.animate(withDuration: duration, animations: {
var frame = fromView.frame
frame.Origin.x = -container.frame.width
fromView.frame = frame
toView.frame = container.bounds
}, completion: { _ in
// tell our transitionContext object that we've finished animating
transitionContext.completeTransition(true)
})
}
}
次に、ポップシナリオを実装するこのクラスを追加します
import Foundation
import UIKit
class PopAnimator: NSObject, UIViewControllerAnimatedTransitioning, UIViewControllerTransitioningDelegate {
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return 0.5
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
// get reference to our fromView, toView and the container view that we should perform the transition in
let container = transitionContext.containerView
let fromView = transitionContext.view(forKey: UITransitionContextViewKey.from)!
let toView = transitionContext.view(forKey: UITransitionContextViewKey.to)!
// set up from 2D transforms that we'll use in the animation
let offScreenRight = CGAffineTransform(translationX: container.frame.width, y: 0)
// start the toView to the right of the screen
var frame = toView.frame
frame.Origin.x = -container.frame.width
toView.frame = frame
// add the both views to our view controller
container.addSubview(toView)
container.addSubview(fromView)
// get the duration of the animation
let duration = self.transitionDuration(using: transitionContext)
// perform the animation!
UIView.animate(withDuration: duration, animations: {
fromView.transform = offScreenRight
toView.frame = container.bounds
}, completion: { _ in
// tell our transitionContext object that we've finished animating
transitionContext.completeTransition(true)
})
}
}
次に、この行をviewDidLoadメソッドに追加して、デフォルトのNavigationController Delegateを変更します
self.navigationController?.delegate = self
そして魔法を参照してください:)
上記のいずれも役に立たない場合に備えて、私はこの問題を抱えていましたが、私にとっての問題は次のコードがあったことでした。
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
tableView.reloadData()
}
このreloadData()行をコメントアウトすると、問題が修正されました。この行は必要なかったので、なぜ追加したのかわからない!
このソリューションが他の人の助けになることを願っています。
多くのことを試した後:
この問題はestimatedRowHeight
の値に関するもので、150pxになるはずの50pxに設定されていることに気付きました。値を更新すると問題が修正され、Table Viewは同じオフセットを保持するようになりました。