当前位置: 首页 > 知识库问答 >
问题:

iOS Autolayout with UIScrollview:为什么滚动视图的内容视图没有填充滚动视图?

谷梁裕
2023-03-14

下面的代码(在viewDidLoad中调用)导致一个完全红色的屏幕。我希望它是一个完全绿色的屏幕。为什么是红色的?我怎样才能让它变成绿色的呢?

UIScrollView* scrollView = [UIScrollView new];
scrollView.translatesAutoresizingMaskIntoConstraints = NO;
scrollView.backgroundColor = [UIColor redColor];
[self.view addSubview:scrollView];

UIView* contentView = [UIView new];
contentView.translatesAutoresizingMaskIntoConstraints = NO;
contentView.backgroundColor = [UIColor greenColor];
[scrollView addSubview:contentView];

NSDictionary* viewDict = NSDictionaryOfVariableBindings(scrollView,contentView);

[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[scrollView]|" options:0 metrics:0 views:viewDict]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[scrollView]|" options:0 metrics:0 views:viewDict]];

[scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[contentView]|" options:0 metrics:0 views:viewDict]];
[scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[contentView]|" options:0 metrics:0 views:viewDict]];

共有3个答案

瞿健
2023-03-14

通常,“自动布局”将视图的上边缘、左边缘、下边缘和右边缘视为可见边缘。也就是说,如果将视图固定到其超级视图的左边缘,则实际上将其固定到超级视图边界的最小 x 值。更改超级视图的边界原点不会更改视图的位置。

UIScrollView类通过更改其边界的原点来滚动其内容。为了使自动布局工作,滚动视图中的顶部、左侧、底部和右侧边缘现在表示其内容视图的边缘。

滚动视图子视图上的约束必须导致要填充的大小,然后将其解释为滚动视图的内容大小。(这不应与用于自动布局的intrinsic ContentSize方法混淆。)要使用自动布局调整滚动视图的框架大小,必须明确限制滚动视图的宽度和高度,或者滚动视图的边缘必须绑定到其子树之外的视图。

请注意,您可以通过在视图和滚动视图的子树之外的视图(如滚动视图的超级视图)之间创建约束,使滚动视图的子视图看起来浮动(而不是滚动)在其他滚动内容之上。

下面是有关如何配置滚动视图的两个示例,首先是混合方法,然后是纯方法

危钱明
2023-03-14

我试了试,Rob的答案起初看起来不错。但是!如果您还启用了缩放,此自动布局代码将会碍事。缩放时,它会不断调整内容视图的大小。也就是说,如果我放大(zoomScale

经过几天与Autolayout的斗争,可悲的是我找不到任何解决方案。最后甚至都无所谓了(wat?好吧,不好意思)。最后,我只是在contentView上移除Autolayout(使用固定大小的contentView),然后在layoutSubviews中,我调整< code > self . scroll view . content inset 。(我用的是Xcode5,iOS 7)

我知道这不是这个问题的直接解决方案。但我只想指出一个简单的解决方法。它非常适合在scrollView中居中固定大小的内容视图,只需2行代码!希望它可以帮助某人;)

- (void)layoutSubviews {
    [super layoutSubviews];

    // move contentView to center of scrollView by changing contentInset,
    // because I CANNOT set this with AUTOLAYOUT!!!
    CGFloat topInset = (self.frame.size.height - self.contentView.frame.size.height)/2;
    self.scrollView.contentInset = UIEdgeInsetsMake(topInset, 0, 0, 0);
}
邹麻雀
2023-03-14

滚动视图的约束与其他视图的约束略有不同。contentView和它的SuperviewscrollView)之间的约束是针对scrollViewcontentSize,而不是它的frame。这可能看起来令人困惑,但实际上非常有用,这意味着您永远不必调整contentSize,而是contentSize将自动调整以适应您的内容。技术说明TN2154中描述了这种行为。

例如,如果要定义屏幕上的contentView大小或类似的大小,则必须在contentView和主视图之间添加约束。诚然,这与将内容放入滚动视图是相反的,所以我可能不建议这样做,但这是可以做到的。

为了说明这个概念,即< code>contentView的大小将由其内容决定,而不是由< code>scrollView的< code >边界决定,请在< code>contentView中添加一个标签:

UIScrollView* scrollView = [UIScrollView new];
scrollView.translatesAutoresizingMaskIntoConstraints = NO;
scrollView.backgroundColor = [UIColor redColor];
[self.view addSubview:scrollView];

UIView* contentView = [UIView new];
contentView.translatesAutoresizingMaskIntoConstraints = NO;
contentView.backgroundColor = [UIColor greenColor];
[scrollView addSubview:contentView];

UILabel *randomLabel = [[UILabel alloc] init];
randomLabel.text = @"this is a test";
randomLabel.translatesAutoresizingMaskIntoConstraints = NO;
randomLabel.backgroundColor = [UIColor clearColor];
[contentView addSubview:randomLabel];

NSDictionary* viewDict = NSDictionaryOfVariableBindings(scrollView, contentView, randomLabel);

[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[scrollView]|" options:0 metrics:0 views:viewDict]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[scrollView]|" options:0 metrics:0 views:viewDict]];

[scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[contentView]|" options:0 metrics:0 views:viewDict]];
[scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[contentView]|" options:0 metrics:0 views:viewDict]];

[contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[randomLabel]-|" options:0 metrics:0 views:viewDict]];
[contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[randomLabel]-|" options:0 metrics:0 views:viewDict]];

现在您将看到content View(因此,scrollViewcontent Size)已调整以适应具有标准边距的标签。因为我没有指定标签的宽度/高度,这将根据您放入该标签的文本进行调整。

如果您希望content View也调整到主视图的宽度,您可以像这样重新定义您的viewDict,然后添加这些额外的约束(除了上面的所有其他约束):

UIView *mainView = self.view;

NSDictionary* viewDict = NSDictionaryOfVariableBindings(scrollView, contentView, randomLabel, mainView);

[mainView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:[contentView(==mainView)]" options:0 metrics:0 views:viewDict]];

滚动视图中的多行标签存在一个已知问题(错误?),如果您希望根据文本量调整其大小,则必须进行一些操作,例如:

dispatch_async(dispatch_get_main_queue(), ^{
    randomLabel.preferredMaxLayoutWidth = self.view.bounds.size.width;
});
 类似资料:
  • 是否有任何方法可以使用android: fillViewport="true"和一个子LinearLayout填充所有视图,当LinearLayout的内容不够高时? 到目前为止,在ScrollView中的LinearLayout中,我们必须使用Android:layout _ height = " wrap _ content "。我们可以添加一些东西来填充所有的滚动视图吗?

  • 利用UIScrollView实现视差滚动效果。在demo中,滑动ScrollView,背景图和文字的滚动速度不一样。直接用ScrollView 的协议,对其子视图的坐标进行随机系数比例的位置移动修正,从而实现视差滚动效果。没有用其他的框架,代码简单。 作者说:原创Demo 转载请注明出处。 [Code4App.com]

  • 在我的一个活动中有一个父容器,它调用由一个水平scrollview组成的子容器作为对象之一。有点像recyclerview,其中放置了行对象,有一个由水平滚动视图组成的公共行/项布局。 我的目标是同步horizontalscrollview的位置,这样,当我在其中一个对象上从位置1水平滚动到位置2时,包含HorizonalScrollview的所有其他项目都会从位置1更新到位置2。 这是我的主容器

  • 我有一个水平ScrollView,它有两个元素:CardView和水平RecycerView。所以,当用户水平滚动时,我希望这两个元素滚动。 我想有这样的东西:Goal,橙色的线是CardView,黄色的线是RecycerView。当用户滚动时,两个元素滚动,如下所示:Scrolled Goal。 现在在我的应用程序中,当用户滚动时,只有RecycerView滚动。CardView保持在他的位置。

  • 我有一个android布局,它有一个,里面有很多元素。在的底部有一个,然后由适配器填充。 我遇到的问题是,android将从中排除,因为已经具有可滚动的功能。我希望与内容一样长,并且主滚动视图是可滚动的。 我怎样才能达到这种行为呢? 下面是我的主要布局: 然后以编程方式将组件添加到具有ID:的linearlayour中。下面是加载到LinearLayout中的一个视图。就是这个给我卷轴带来麻烦的。

  • 实现循环ScrollView。有以下特色: 1、循环的scrollview 2、类似于tableview的编程方式 3、可定制化的内容 4、灵活运用可用于移步加载图片 5、结构化,可扩展性高 [Code4App.com]