Adding a dynamically sized view (height) to a UIScrollView with Auto Layout(使用自动布局向 UIScrollView 添加动态大小的视图(高度))
问题描述
这是我对此详细视图的视图结构(博客应用程序,我想查看在滚动视图内具有动态高度的整个帖子):
UIView-UIScrollView-SinglePostView(自定义视图)-标题-字幕-内容
通常要向 UIView 添加单个帖子视图",我只需将其实例化,将其提供给我的 Post 对象,然后添加一个约束,将 singlePostView 的宽度固定到超级视图,此时事情会很好地布置.但是,当我尝试将其添加到滚动视图时,它既不显示也不滚动.
UIScrollView *scrollView = [[UIScrollView alloc] init];[self.view addSubview:scrollView];NOBSinglePostView *singlePost = [[NOBSinglePostView alloc] initWithPost:self.post];[scrollView addSubview:singlePost];singlePost.translatesAutoresizingMaskIntoConstraints = NO;scrollView.translatesAutoresizingMaskIntoConstraints = NO;NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(scrollView,singlePost);[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[scrollView]|"选项:0 指标:0 视图:viewsDictionary]];[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[scrollView]|"选项:0 指标:0 视图:viewsDictionary]];[scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[singlePost]|"选项:0 指标:0 视图:viewsDictionary]];
在你呈现的结构中,使用 AutoLayout,你的 UIScrollView
的 contentSize
是由intrinsicContentSize
的子视图,这里是你的 SinglePostView
.
问题是,SinglePostView
是 UIView
的子类,它的 intrinsicContentSize
在考虑时总是 CGSizeZero
本身.您需要做的是使 SinglePostView
的 intrinsicContentSize
依赖于其子视图的 intrinsicContentSize
.
那么,因为你的 SinglePostView
的子视图是 UILabels
,并且因为 UILabel
的 intrinsicContentSize
是显示其内容所需的最小尺寸,您的 SinglePostView
的 intrinsicContentSize
将等于其子视图 intrinsicContentSizes
的总和,即显示所有三个标签的内容所需的总大小.
这里是怎么做的.
第 1 步:删除所有自动设置的约束
首先,正如您部分所做的那样,您需要删除系统自动设置的所有约束.
假设您没有在情节提要或 XIB 中设置任何约束(或者您甚至没有这些约束),只需执行以下操作:
scrollView.translatesAutoresizingMaskIntoConstraints = NO;singlePost.translatesAutoresizingMaskIntoConstraints = NO;titleLabel.translatesAutoresizingMaskIntoConstraints = NO;subtitleLabel.translatesAutoresizingMaskIntoConstraints = NO;contentLabel.translatesAutoresizingMaskIntoConstraints = NO;
现在您有了清晰的计划,您可以开始设置自己的约束条件了.
第 2 步:约束 scrollView
首先,让我们像您一样创建视图引用字典以供 AutoLayout 使用:
NSDictionary *views = NSDictionaryOfVariableBindings(scrollView, singlePost, titleLabel, subtitleLabel, contentLabel);
然后,就像你已经做过的那样,让我们将滚动视图限制为其父视图的大小:
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[scrollView]-0-|"选项:0 指标:0 意见:意见]];[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[scrollView]-0-|"选项:0 指标:0 意见:意见]];
第三步:约束SinglePostView
推送scrollView
的contentSize
要清楚这一步,您必须了解 UIScrollView
及其 subviews
之间设置的每个约束实际上都会改变 contentSize
UIScrollView
,而不是它的实际 bounds
.例如,如果您将 UIImageView
约束到其父 UIScrollView
的边框,然后将 UIScrollView
大小两倍的图像放入 UIImageView
,你的图像不会被缩小,它的 UIImageView
会占用它的图像大小并在 UIScrollView
内变得可滚动.UIImageViewp>
所以你必须在这里设置:
[scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[singlePost]-0-|"选项:0 指标:0 意见:意见]];[scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[singlePost]-0-|"选项:0 指标:0 意见:意见]];[scrollView addConstraint:[NSLayoutConstraint constraintWithItem:singlePost属性:NSLayoutAttributeWidthrelatedBy:NSLayoutRelationEqualtoItem:滚动视图属性:NSLayoutAttributeWidth乘数:1.0f常数:0.0f]];
前两个约束非常明显.然而,第三个在这里是因为,为了让您的 UILabels
正确显示其内容并且仍然可读,您可能希望它们是多行的并且滚动是垂直的,而不是水平的.这就是您将 SinglePostView
的 width
设置为与 scrollView
相同的原因.这样,您可以防止 scrollView
的 contentSize.width
超出其 bounds.width
.
第 4 步:约束您的 UILabels
以推动"您的 SinglePostView
的边界第四步,也是最后一步,您现在需要对 SinglePostView
的子视图设置约束,以便从它们那里获得 intrinsicContentSize
.
这是你的做法(最简单的实现,没有边距,一个标签一个接一个垂直):
[singlePost addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[titleLabel]-0-|"选项:0 指标:0 意见:意见]];[singlePost addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[subtitleLabel]-0-|"选项:0 指标:0 意见:意见]];[singlePost addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[contentLabel]-0-|"选项:0 指标:0 意见:意见]];[singlePost addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[titleLabel]-0-[subtitleLabel]-[contentLabel]-0-|"选项:0 指标:0 意见:意见]];
你应该完成了.
最后一个建议,你绝对应该查看 UIStoryboard
来做这些事情.它更简单,更直观.
希望这会有所帮助,
P.S.:如果你愿意,我可以花一些时间在 Github 上同时使用 UIStoryboard
和 Visual Format Language
推送一个项目.只要告诉我你是否需要一个.
祝你好运.
Here is my structure of views for this detail view (blogging application, I want to view the entire post which has dynamic height inside of a scrollview):
UIView
-UIScrollView
-SinglePostView (custom view)
-Title
-Subtitle
-Content
Normally to add a 'single post view' to a UIView I simply instantiate it, feed it my Post object and then add a single constraint that pins the width of the singlePostView to the superview, at which point things get laid out nicely. However when I try to add it to a scroll view, it doesn't show up nor does it scroll.
UIScrollView *scrollView = [[UIScrollView alloc] init];
[self.view addSubview:scrollView];
NOBSinglePostView *singlePost = [[NOBSinglePostView alloc] initWithPost:self.post];
[scrollView addSubview:singlePost];
singlePost.translatesAutoresizingMaskIntoConstraints = NO;
scrollView.translatesAutoresizingMaskIntoConstraints = NO;
NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(scrollView,singlePost);
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[scrollView]|" options:0 metrics: 0 views:viewsDictionary]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[scrollView]|" options:0 metrics: 0 views:viewsDictionary]];
[scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[singlePost]|" options:0 metrics: 0 views:viewsDictionary]];
In the structure you are presenting, using AutoLayout, the contentSize
of your UIScrollView
is driven by the intrinsicContentSize
of its subviews, here your SinglePostView
.
The problem is, SinglePostView
being a subclass of UIView
, its intrinsicContentSize
is always CGSizeZero
when considered by itself. What you need to do is make the intrinsicContentSize
of your SinglePostView
depend on the intrinsicContentSize
of its subviews.
Then, because the subviews of your SinglePostView
are UILabels
, and because a UILabel
's intrinsicContentSize
is the smallest size it needs to display its content, your SinglePostView
's intrinsicContentSize
will be equal to the sum of its subviews intrinsicContentSizes
, that is the total size needed to display the content of all three of your labels.
Here is how to do it.
Step 1: Removing all automatically set constraints
First, as you partially did, you need to remove all constraints automatically set by the system.
Assuming you don't have any constraints set in your storyboard or XIB (or you don't even have one of these), just do:
scrollView.translatesAutoresizingMaskIntoConstraints = NO;
singlePost.translatesAutoresizingMaskIntoConstraints = NO;
titleLabel.translatesAutoresizingMaskIntoConstraints = NO;
subtitleLabel.translatesAutoresizingMaskIntoConstraints = NO;
contentLabel.translatesAutoresizingMaskIntoConstraints = NO;
Now you have a clear slate and you can start setting your own constraints.
Step 2: Constraining the scrollView
First, let's create, as you did, the views references dictionary for AutoLayout to use:
NSDictionary *views = NSDictionaryOfVariableBindings(scrollView, singlePost, titleLabel, subtitleLabel, contentLabel);
Then, also as you already did, let's constrain the scroll view to be the size of its superview:
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[scrollView]-0-|" options:0 metrics:0 views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[scrollView]-0-|" options:0 metrics:0 views:views]];
Step 3: Constraining the SinglePostView
to push the scrollView
's contentSize
For this step to be clear, you have to understand that every constraints set between a UIScrollView
and its subviews
will actually change the contentSize
of the UIScrollView
, not its actual bounds
. For Example, if you constrain a UIImageView
to the borders of its parent UIScrollView
and then put an image twice the size of the UIScrollView
inside the UIImageView
, your image won't get shrunk, its the UIImageView
that will take the size of its image and become scrollable inside the UIScrollView
.
So here is what you have to set here:
[scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[singlePost]-0-|" options:0 metrics:0 views:views]];
[scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[singlePost]-0-|" options:0 metrics:0 views:views]];
[scrollView addConstraint:[NSLayoutConstraint constraintWithItem:singlePost
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:scrollView
attribute:NSLayoutAttributeWidth
multiplier:1.0f
constant:0.0f]];
First two constraints are pretty obvious. The third one, however, is here because, for your UILabels
to display their content properly and still be readable, you will probably want them to be multilined and the scrolling to be vertical, not horizontal. That's why you set your SinglePostView
's width
to be the same as your scrollView
's. This way, you prevent your scrollView
's contentSize.width
to be anything more than its bounds.width
.
Step 4: Constraining your UILabels
to "push" the bounds of your SinglePostView
Fourth and final step, you now need to set constraints on your SinglePostView
's subviews, so that it gets an intrinsicContentSize
from them.
Here is how you do it (simplest implementation, no margins, one label after the other vertically):
[singlePost addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[titleLabel]-0-|" options:0 metrics:0 views:views]];
[singlePost addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[subtitleLabel]-0-|" options:0 metrics:0 views:views]];
[singlePost addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[contentLabel]-0-|" options:0 metrics:0 views:views]];
[singlePost addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[titleLabel]-0-[subtitleLabel]-[contentLabel]-0-|" options:0 metrics:0 views:views]];
And with that you should be done.
One last advice, you should definitely look into UIStoryboard
to do these kinds of things. It's a lot simpler and more visual.
Hope this helps,
P.S.: If you want, I can take some time and push a project using both UIStoryboard
and the Visual Format Language
on Github. Just tell me if you would need one.
Good luck.
这篇关于使用自动布局向 UIScrollView 添加动态大小的视图(高度)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:使用自动布局向 UIScrollView 添加动态大小的视图
- Android - 我如何找出用户有多少未读电子邮件? 2022-01-01
- 使用自定义动画时在 iOS9 上忽略 edgesForExtendedLayout 2022-01-01
- 用 Swift 实现 UITextFieldDelegate 2022-01-01
- 在测试浓缩咖啡时,Android设备不会在屏幕上启动活动 2022-01-01
- Android - 拆分 Drawable 2022-01-01
- Android viewpager检测滑动超出范围 2022-01-01
- 如何检查发送到 Android 应用程序的 Firebase 消息的传递状态? 2022-01-01
- android 4中的android RadioButton问题 2022-01-01
- 想使用ViewPager,无法识别android.support.*? 2022-01-01
- MalformedJsonException:在第1行第1列路径中使用JsonReader.setLenient(True)接受格式错误的JSON 2022-01-01