从模态转换返回后如何重置我的 UI ScrollView 位置?

Posted

技术标签:

【中文标题】从模态转换返回后如何重置我的 UI ScrollView 位置?【英文标题】:How to reset my UIScrollView's position after returning from a modal transition? 【发布时间】:2013-06-06 04:17:11 【问题描述】:

我有一个简单的视图,其中包含一个带有许多按钮的长视图,整个视图都在 UIScrollView 中。 scroller 效果很好,我可以在底部将scroll 并单击button。每个button 触发一个模态seque to 另一个view。新的view 然后被用户交互解除,导致原来的UIScrollView's view 再次加载。

问题出在:如果我单击UIScrollView 顶部的按钮,我会进入模态segue,关闭新的view,然后毫无问题地返回UIScrollView's view。但是,如果我单击UIScrollView 底部的按钮之一,当我返回seque 然后再转换回来时,我的滚动就会一团糟。我只能看到我的scroller下方区域,而scroll 不能再回到顶部!

我很确定一定有某种方法可以在ViewWillAppear 上重置UIScrollView's 的起点和终点,但我想不通。任何帮助表示赞赏!

另外,仅供参考,我只是通过接口生成器添加了UIScrollView,还没有在任何地方实现或合成它。

【问题讨论】:

你有没有初始化你的滚动视图在视图中会出现? , 如果是,则将该代码放入 viewdidload 中,因为当您关闭视图时,它的视图将显示将调用 您能否发布您当前的代码或在您描述的场景之前和之后的一些屏幕截图? @IsaiahNelson 如果您有兴趣,复制大约需要 5 分钟。使用情节提要创建一个新项目。最初的UIViewController 包含一个长滚动视图(高到必须滚动),顶部有一个标签,底部有一个按钮,触发到第二个VC 的segue。第二个 VC 有一个按钮,该按钮具有关闭第二个 VC 的操作(这是您需要编写的唯一代码行来重现此)。在模拟器中运行。向下滚动。单击第一个按钮。单击第二个按钮。 Boom - 你不能再在第一个 VC 中向上滚动到 UIScrollView 的顶部。 【参考方案1】:

试试这个代码:

- (void)viewWillAppear:(BOOL)animated

  [yourscrollview setContentOffset:CGPointZero animated:YES];

【讨论】:

很好的答案。非常感谢@kirti mali。 Swift3: yourscrollview.setContentOffset(CGPoint.zero, animated: true)【参考方案2】:

请注意:此问题和答案所涉及的错误似乎已在 ios 7 中修复。此答案的其余部分仅与 iOS 6 相关(可能更早)。

这里展示的行为是UIScrollView 类中的一个错误。正如 OP 所指出的,在从模态呈现的 UIViewController 返回到包含 UIScrollView 的场景后,UIScrollView 会采用它当前滚动到的任何点并开始表现得好像这是它的起源。这意味着,如果您在模态显示另一个视图控制器之前向下滚动滚动视图,则在返回带有滚动视图的场景时,您将无法向上滚动。

当您从视图层次结构中删除滚动视图并重新添加它时,即使不更改其窗口,也会发生同样的事情。

您可以通过将滚动视图的contentOffset 设置回0,0 来解决此问题,然后在关闭模式视图控制器后再次显示它。如果您真的想保留用户在触发模式之前滚动到的点,那么 after UIScrollView 重新显示后,您可以将 contentOffset 设置回重置之前的状态.

这是一个 UIScrollView 子类,它修复了该错误,而无需在您从模式返回时将滚动视图重置到顶部:

@interface NonBuggedScrollView : UIScrollView

@end

@implementation NonBuggedScrollView 
    CGPoint oldOffset;


-(void)willMoveToWindow:(UIWindow *)newWindow 
    oldOffset = self.contentOffset;
    self.contentOffset = CGPointMake(0,0);


-(void)willMoveToSuperview:(UIView *)newSuperview 
    oldOffset = self.contentOffset;
    self.contentOffset = CGPointMake(0,0);


-(void)didMoveToWindow 
    self.contentOffset = oldOffset;


-(void)didMoveToSuperview 
    self.contentOffset = oldOffset;


@end

如果您宁愿在 UIViewController 中而不是在 UIScrollView 子类中执行此操作,请更改 viewWillAppear:viewDidAppear 方法中的内容偏移量。

如果您不想保留用户从模态返回时的滚动位置,而只想按照 OP 的要求将 UIScrollView 滚动回顶部,那么您只需要偶数更简单:

@interface NonBuggedScrollView : UIScrollView

@end

@implementation NonBuggedScrollView

-(void)willMoveToWindow:(UIWindow *)newWindow 
    self.contentOffset = CGPointMake(0,0);


-(void)willMoveToSuperview:(UIView *)newSuperview 
    self.contentOffset = CGPointMake(0,0);



@end

【讨论】:

【参考方案3】:

首先,感谢上述批准的答案。有人提到它不再适用,但我在表格视图单元格内有一个滚动视图,并且在重用单元格时需要重置它。

这是 Swift 中的解决方案。

@IBOutlet var scrollView: UIScrollView!

// many lines of code later inside a function of some sort...

scrollView.setContentOffset(CGPointMake(0.0, 0.0), animated: false)

【讨论】:

【参考方案4】:

为了解决这个问题,我使用以下代码:

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

    [self.scrollview scrollRectToVisible:CGRectMake(0, 0, 1, 1)
                                animated:NO];   

【讨论】:

【参考方案5】:

您可以通过调用scrollRectToVisible:animated: 更改起点和终点。但我不确定这是否能解决您的问题。

【讨论】:

【参考方案6】:

使用下面的代码 sn-p 恢复 UIScrollview 的滚动位置

将“scrollPosition”变量声明为 CGPoint 类型。

- (void)viewDidDisappear:(BOOL)animated 

    [super viewDidDisappear:animated];
    //get the current offset
    scrollPosition = scrollView.contentOffset;

    //set current view to the beginning point
    self.scrollView.contentOffset = CGPointZero;


- (void)viewDidLayoutSubviews 

    [super viewDidLayoutSubviews];
    //retrieve the previous offset
    self.scrollView.contentOffset = scrollPosition;

【讨论】:

如果我们使用导航控制器会怎样? @GajendraKChauhan : 以上代码将与 NavigationController 一起使用

以上是关于从模态转换返回后如何重置我的 UI ScrollView 位置?的主要内容,如果未能解决你的问题,请参考以下文章

排序某些元素后如何重置 ng-repeat 块?

Kendo UI:单击按钮后将网格数据重置为第一页

从 POST 操作验证模态后无法正常工作

在每个点击事件上重置/刷新模态数据

如何将 segue 标识符添加到以编程方式进行的模态转换?

如何在材质 ui 上使用过渡使模态居中并使其响应?