草庐IT

关于 ios:Bounds 在 UIScrollView 上自动更改内容插入

codeneng 2023-03-28 原文

Bounds automatically changes on UIScrollView with content insets

我使用 UIScrollView 作为我的分页滚动视图,pagesScrollView。在其中,我放置了专门用于缩放的单个 UIScrollView。在其中的每一个中,我都有一个视图,它是应该可以缩放的页面项目。所有这些都在带有半透明导航栏的 UINavigationController 中。

我的 pagesScrollViewcontentInset.top = 64bounds.origin.y = -64 (这对我来说似乎很奇怪,但这是系统自动为我设置的),这很好用。我的屏幕看起来很棒!

但是,在我滚动 pagesScrollView 一点点之后,只要调用 scrollViewWillEndDraggingpagesScrollView 就会开始从 bounds.origin.y = -64bounds.origin.y = 0 的动画变化,这会导致我的页面项目被遮挡通过导航栏。

左边是加载时的样子,右边是我拖动几个像素然后放开后的样子,它在导航栏下向上滑动(因为 bounds.origin.y 去了到 0).

问题是我没有任何代码可以改变边界,并且在各种滚动委托方法中也没有任何代码可以做任何事情。我添加了一堆滚动委托方法,并且刚刚添加了 NSLog(),这样我就可以确定更改发生的时间/地点,但它并没有在我的代码中的任何地方发生。

所以,我不知道我可以向您展示什么代码来帮助您帮助我。

编辑:我从头开始构建了一个新项目以删除所有其他变量。我将一个裸 UIViewController 放入 UINavigationController。我将一个 UIScrollView 放入我的视图中,整个视图的大小。以下代码是整个项目。

事实证明,问题(如下所述)仅在 UIScrollView 上启用 PAGING 时才会出现!什么? :)

这里是下载一个基本项目的链接,它只有几行代码来演示这个问题。只需单击滚动视图,您就会看到它随着边界的变化而向上移动。 http://inadaydevelopment.com/stackoverflow/WeirdScrollViews.zip

如何在滚动视图上启用分页,而不会在滚动和移动导航栏下的所有内容时出现边界问题?

可以将导航栏设置为不透明并避免问题,但理想的情况是具有标准的 iOS7 行为,以便在内容视图缩放后,然后允许内容位于导航栏下方,并应通过半透明正常。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
- (void) viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];

    NSArray *colors = @[
                        [UIColor blueColor],
                        [UIColor orangeColor],
                        [UIColor magentaColor],
                        ];

    NSArray *zoomerColors = @[
                        [UIColor greenColor],
                        [UIColor yellowColor],
                        [UIColor purpleColor],
                        ];


    self.scroller.pagingEnabled = YES;

    [self.scroller setContentSize:CGSizeMake(self.scroller.frame.size.width*colors.count, self.scroller.frame.size.height)];

    CGRect subviewFrame = CGRectMake(0, 0, 160, 240);
    for (int index=0; index < colors.count; index++) {
        UIColor *color = [colors objectAtIndex:index];
        UIColor *zoomerColor = [zoomerColors objectAtIndex:index];

        UIView *subview = [[UIView alloc] initWithFrame:subviewFrame];
        subview.backgroundColor = color;

        CGRect zoomerFrame = CGRectMake(index*self.scroller.frame.size.width, 0, self.scroller.frame.size.width, self.scroller.frame.size.height);

        UIScrollView *zoomer = [[UIScrollView alloc] initWithFrame:zoomerFrame];
        [zoomer addSubview:subview];
        zoomer.backgroundColor = zoomerColor;

        [self.scroller addSubview:zoomer];

    }
}

  • 如果你使用边界它 x 和 y 点是 0,0 你需要使用 frame.
  • 放置 scrollViewWillEndDragging 的代码或放置单个 UIScrollViews 的代码
  • @nitinkachhadiya,我根本没有改变界限,界限从-64开始......这对我来说看起来不对,但这就是系统自己设置的。
  • @iPatel,我已添加您要求的代码,但正如我所说,它是空的。在我添加它之前,我什至没有在我的类中使用该代码方法,这样我就可以在其中放置一个 NSLog()。


只需关闭调整滚动视图插图


这是一个 iOS 错误。我创建了 UIScrollView 的以下子类,以记录 y 随着时间的推移发生了什么以及谁在推动它:

1
2
3
4
5
6
7
8
9
10
@implementation CSScrollView

- (void)setContentOffset:(CGPoint)contentOffset
{
    NSLog(@"%0.0f %@", contentOffset.y, [NSThread callStackSymbols]);
    NSLog(@"[%@]", self.layer.animationKeys);
    [super setContentOffset:contentOffset];
}

@end

(并更改了故事板中的视图类)

当你松开手指时,一个名为 UIScrollView _smoothScrollDisplayLink: 的方法开始动画滚动视图到它的最终位置。根据第二个日志,没有 CAAnimation 涉及,滚动视图使用自己的显示链接进行自己的转换。该自定义代码似乎犯了从 y = whatevery = 0 的动画错误,没有考虑到内容偏移。

作为概念验证黑客,我将代码更改为:

1
2
3
4
5
6
7
8
9
@implementation CSScrollView

- (void)setContentOffset:(CGPoint)contentOffset
{
    contentOffset.y = -64.0f;
    [super setContentOffset:contentOffset];
}

@end

不出所料,问题就消失了。

您可能不想对 -64.0f 进行硬编码,但我得出的结论是:

  • 这是一个 iOS 错误;
  • 通过使用 - setContentOffset: 的适当自定义实现的 UIScrollView 子类拒绝无意义的值来解决此问题。

一种合理的通用方法可能是检查 self.panGestureRecognizerstate 和其他滚动,而无需依赖任何未记录的 API 或复杂的委托捕获事件。然后,如有必要,从当前值中提取正确的 contentOffset.y 而不是对其进行硬编码。

  • 这很棒!我不知道出了什么问题,尽管我确实怀疑这是 iOS 8 中的一个错误。与您的解决方案完美配合,谢谢


It turns out the issue (described below) only appears once PAGING IS ENABLED on the UIScrollView! Wtf? :)

正如你所说,如果启用滚动分页,UIScrollView 将在拖动或任何移动后停止在分页边缘,这是框架Promise的。 Bounds.origin.y 设置为零意味着第一页边缘与滚动视图框架边缘匹配,因为那里有 64 个 contentInsets。所以这不是错误,就是这样。而且由于您的栏是半透明的,请记住滚动视图的框架边缘在哪里,它在栏下方。总而言之,我认为这不是错误,而是滚动分页的效果。


我已经检查了您在 viewController.m 文件中使用以下代码的示例

1
2
3
4
5
6
-(void)viewDidLoad
{
    if ([[UIDevice currentDevice] systemVersion].floatValue>=7.0) {
        self.edgesForExtendedLayout = UIRectEdgeNone;
    }
}

一切正常……

  • 它确实阻止了该错误的出现,但那是因为它禁用了 iOS7 ui 的核心功能。当 UI 扩展时,它也应该正常运行。


My pagesScrollView has contentInset.top = 64 and bounds.origin.y = -64 (that seems weird to me, but that's what the system is setting automatically for me), and this works just fine. My screen looks great!

这是因为 iOS 7 在所有滚动视图上将 contentInset.top 设置为 64。
只需将这行代码添加到您的视图控制器中,一切都会按预期工作:

1
2
-(UIRectEdge)edgesForExtendedLayout {
return UIRectEdgeNone;

}

我检查了你的示例项目。

  • 感谢您的回复。不幸的是,这个答案只是避免了问题,而不是真正解决问题。当内容视图被缩放和平移时,理想情况下,内容应该位于导航栏下方,并以标准的 iOS7 方式显示。我可以使导航栏不透明并很好地避免该问题,但这并不是真正的理想。这实际上可能是一个 iOS 错误。

有关关于 ios:Bounds 在 UIScrollView 上自动更改内容插入的更多相关文章

  1. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

    很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

  2. ruby-on-rails - Ruby on Rails 迁移,将表更改为 MyISAM - 2

    如何正确创建Rails迁移,以便将表更改为MySQL中的MyISAM?目前是InnoDB。运行原始执行语句会更改表,但它不会更新db/schema.rb,因此当在测试环境中重新创建表时,它会返回到InnoDB并且我的全文搜索失败。我如何着手更改/添加迁移,以便将现有表修改为MyISAM并更新schema.rb,以便我的数据库和相应的测试数据库得到相应更新? 最佳答案 我没有找到执行此操作的好方法。您可以像有人建议的那样更改您的schema.rb,然后运行:rakedb:schema:load,但是,这将覆盖您的数据。我的做法是(假设

  3. ruby - 将数组的内容转换为 int - 2

    我需要读入一个包含数字列表的文件。此代码读取文件并将其放入二维数组中。现在我需要获取数组中所有数字的平均值,但我需要将数组的内容更改为int。有什么想法可以将to_i方法放在哪里吗?ClassTerraindefinitializefile_name@input=IO.readlines(file_name)#readinfile@size=@input[0].to_i@land=[@size]x=1whilex 最佳答案 只需将数组映射为整数:@land边注如果你想得到一条线的平均值,你可以这样做:values=@input[x]

  4. ruby-on-rails - 项目升级后 Pow 不会更改 ruby​​ 版本 - 2

    我在我的Rails项目中使用Pow和powifygem。现在我尝试升级我的ruby​​版本(从1.9.3到2.0.0,我使用RVM)当我切换ruby​​版本、安装所有gem依赖项时,我通过运行railss并访问localhost:3000确保该应用程序正常运行以前,我通过使用pow访问http://my_app.dev来浏览我的应用程序。升级后,由于错误Bundler::RubyVersionMismatch:YourRubyversionis1.9.3,butyourGemfilespecified2.0.0,此url不起作用我尝试过的:重新创建pow应用程序重启pow服务器更新战俘

  5. ruby - Capistrano 3 在任务中更改 ssh_options - 2

    我尝试使用不同的ssh_options在同一阶段运行capistranov.3任务。我的production.rb说:set:stage,:productionset:user,'deploy'set:ssh_options,{user:'deploy'}通过此配置,capistrano与用户deploy连接,这对于其余的任务是正确的。但是我需要将它连接到服务器中配置良好的an_other_user以完成一项特定任务。然后我的食谱说:...taskswithoriginaluser...task:my_task_with_an_other_userdoset:user,'an_othe

  6. ruby-on-rails - 如何在我的 Rails 应用程序 View 中打印 ruby​​ 变量的内容? - 2

    我是一个Rails初学者,但我想从我的RailsView(html.haml文件)中查看Ruby变量的内容。我试图在ruby​​中打印出变量(认为它会在终端中出现),但没有得到任何结果。有什么建议吗?我知道Rails调试器,但更喜欢使用inspect来打印我的变量。 最佳答案 您可以在View中使用puts方法将信息输出到服务器控制台。您应该能够在View中的任何位置使用Haml执行以下操作:-puts@my_variable.inspect 关于ruby-on-rails-如何在我的R

  7. ruby - RuntimeError(自动加载常量 Apps 多线程时检测到循环依赖 - 2

    我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("

  8. ruby - 如何验证 IO.copy_stream 是否成功 - 2

    这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下

  9. ruby - 查找字符串中的内容类型(数字、日期、时间、字符串等) - 2

    我正在尝试解析一个CSV文件并使用SQL命令自动为其创建一个表。CSV中的第一行给出了列标题。但我需要推断每个列的类型。Ruby中是否有任何函数可以找到每个字段中内容的类型。例如,CSV行:"12012","Test","1233.22","12:21:22","10/10/2009"应该产生像这样的类型['integer','string','float','time','date']谢谢! 最佳答案 require'time'defto_something(str)if(num=Integer(str)rescueFloat(s

  10. Ruby 文件 IO 定界符? - 2

    我正在尝试解析一个文本文件,该文件每行包含可变数量的单词和数字,如下所示:foo4.500bar3.001.33foobar如何读取由空格而不是换行符分隔的文件?有什么方法可以设置File("file.txt").foreach方法以使用空格而不是换行符作为分隔符? 最佳答案 接受的答案将slurp文件,这可能是大文本文件的问题。更好的解决方案是IO.foreach.它是惯用的,将按字符流式传输文件:File.foreach(filename,""){|string|putsstring}包含“thisisanexample”结果的

随机推荐