58

我有一个UIViewController子类作为情节提要中的一个场景,其中包含一个UIScrollView包含各种子视图的场景。其中一个子视图是一个UIButton进入另一个场景UIViewController子类的子视图。当我从视图返回时(弹出UIViewController导航控制器堆栈),我发现滚动视图的原点发生了某种变化,尽管contentsizeandcontentoffset看起来是正确的。

同样有趣的是,该应用程序有一个标签栏,当我离开并返回该视图时,滚动视图被正确设置为偏移量为 (0, 0)。

这个过程基本上不涉及任何代码,因为它几乎都在情节提要中。由于我对使用情节提要相当陌生,因此我认为我做错了什么,尽管我不知道是什么。关于那可能是什么的任何想法?也许是规模问题或限制?

4

17 回答 17

92

在 iOS 7/8/9 中,简单self.automaticallyAdjustsScrollViewInsets = NO;地解决了我的问题。

于 2014-02-06T07:42:48.117 回答
31

在你弹回的视图控制器的 viewWillAppear 中试试这个:

 self.scrollView.contentOffset = CGPointMake(0, 0);

编辑:当还添加彼得的代码时,你会得到最好的结果:

- (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);
}

您返回到原始滚动位置,没有视觉副作用,并且滚动视图本身在返回后正确定位在其超级视图中(这是一个问题)。

于 2013-07-10T11:29:46.660 回答
12

实际上,我将那行代码放在 中viewDidDisappear,以便它在视图重新出现时记住偏移量,我在它之前添加了这一行

 self.contentOffset = self.scrollView.contentOffset;

 - (void)viewDidLayoutSubviews { 
       self.scrollView.contentOffset = self.contentOffset; 
 }
于 2013-07-10T15:22:22.207 回答
6

我遇到了类似的问题,在关闭 viewController 后,我的 tableView 的 contentOffset 更改为 (0, -64)。

我的解决方案有点奇怪,我尝试了所有其他答案但没有成功,解决我的问题的唯一方法是在 .xib 的控件树中切换 tableView 位置

它是父视图中的第一个控件,如下所示:

前

我在 ImageView 之后移动了 tableView 并且它起作用了:

后

似乎将表格视图放在第一个位置会导致麻烦,将表格视图移动到另一个位置可以解决问题。

PD我没有使用自动布局也没有故事板

希望这可以帮助某人!

于 2014-04-11T17:19:25.557 回答
5

我正在使用 collectionView 并且遇到了类似的问题。对于 iOS 11:在尺寸检查器中,有“内容插入”。将其设置为“从不”。这为我解决了问题。我希望这可以帮助别人。

目标 C:

if (@available(iOS 11, *)) {
   [UIScrollView appearance].contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
}

迅速:

if #available(iOS 11, *) {
UIScrollView.appearance().contentInsetAdjustmentBehavior = .never
}
于 2017-09-27T00:54:52.890 回答
4

在 iOS 11 中,我遇到了类似的问题,当我在弹出视图控制器后返回时,前一个视图控制器中的 tableview 用于自动调整其内容插入,导致 tableview 内容突然从顶部跳转。以下解决方案在 iOS 11 中对我有用。

在 Storyboard 中,选择 tableview 并转到 Attributes inspector 并取消选中 Row Height 和 Estimate 字段的“Automatic”。还将内容插图从“自动”更改为“从不”。

[ 表视图]

于 2018-01-09T12:27:19.530 回答
0

不幸的是,Peter 和 MacMark 的建议对我不起作用(Xcode 5 w/ auto-layout)。解决方案是转到情节提要,选择视图控制器,然后Reset to Suggested Constraints in View Controller.

在此处输入图像描述

于 2013-09-26T08:05:47.300 回答
0

我最近发布了一个关于类似问题但在不同背景下的问题: Frame doesn't reflect auto layout constraints after dismissing modal view controller

在我的例子中,滚动视图内的自定义容器视图的原点被替换,而不是滚动视图本身的原点。关于自动布局,自定义容器视图被固定到滚动视图的四个侧面。

容器视图是通过编程而不是在 IB 中创建和配置的。尽管容器视图的约束没有改变,但容器视图的原点在关闭模态视图控制器后发生了位移。约束和框架之间的这种脱节是无法解释的。

更值得注意的是,在我删除并重新添加所有相关约束后,原点位移问题仍然存在。

我想出了一个类似的解决方案:保存当前内容偏移的值,将内容偏移设置为“零”,让系统交换您的视图,然后恢复内容偏移(即内容偏移舞蹈)。

然而,就我而言,我不得不采取额外的措施来解决这个问题。我的滚动视图是一个分页滚动视图,它从 tilePages 方法(在旧的 WWDC 视频中演示)获取其子视图。更改滚动视图的内容偏移会通过 UIScrollViewDelegate 的 scrollViewDidScroll: 方法触发 tilePages 方法。在进行内容偏移舞蹈时,我必须设置一个标志来关闭 tilePages,否则应用程序会崩溃。

希望当我升级到 iOS 7 时,我可以删除内容偏移舞蹈的代码。

于 2013-09-27T22:47:22.990 回答
0

遵循当前答案时继续问题:

第二次尝试打开呈现的视图控制器,而没有离开呈现的视图控制器,问题仍然存在。这就是为什么我要发布导致我的解决方案的确切步骤。

  1. 因此,我在 Storyboard 中重置了 collectionView 的约束,确保它们被固定到 presentingViewController 的主视图。

  2. 添加self.view.translatesAutoresizingMaskIntoConstraints = YES;viewDidLoad呈现视图控制器的内部。

  3. 并在模态呈现的视图控制器出现之前私下存储集合视图的 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;
    }
    
于 2015-01-28T23:51:33.500 回答
0

最近遇到了这个bug,可以用这些代码解决:</p>

// 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

谢谢彼得雅各布斯!</p>

于 2015-09-08T04:17:34.480 回答
0
- (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 中发生的错误。首先感谢我的朋友们!

于 2016-02-26T11:46:16.677 回答
0

在尝试了很多事情之后:

  • 将 automaticAdjustsScrollViewInsets 设置为 false 以查看问题是否出在导航栏上。
  • 玩固定的单元格高度...
  • 缓存单元格高度...
  • 使用表视图偏移量保留属性,将其缓存并将其设置在 viewWillAppear ...
  • 等等

我意识到问题在于estimatedRowHeight设置为 50px 的值,而它应该是 ~150px。更新值修复了问题,现在表格视图保持相同的偏移量。

于 2017-05-22T15:11:57.283 回答
0

您是否尝试过检查“不透明条下的延伸边缘”选项?它可以在情节提要内的控制器属性检查器中找到。

它使用 XCode 9 iOS 11 为我解决了问题。

在此处输入图像描述

于 2017-11-14T16:20:15.890 回答
0

以上都不适合我,我设法做我自己的自定义推/拉动画,它就像一个魅力。

首先,添加这个实现 Push 场景的类

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)

    })
}
}

然后添加这个实现pop场景的类

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

看看魔法:)

于 2018-01-12T04:29:18.667 回答
0

我使用了 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 上测试。

于 2018-03-14T20:58:10.187 回答
0

万一上述方法都没有帮助,我遇到了这个问题,对我来说问题是我有以下代码..

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    tableView.reloadData()
}

注释掉这个 reloadData() 行为我解决了这个问题。我不需要这条线,所以不知道为什么我什至添加了它!

希望这个解决方案可以帮助其他人。

于 2019-03-06T16:45:55.093 回答
-9

否则关闭AutoLayout该 xib 的选项。

于 2014-08-26T09:51:56.353 回答