問題描述
這是我對此詳細(xì)視圖的視圖結(jié)構(gòu)(博客應(yīng)用程序,我想查看在滾動視圖內(nèi)具有動態(tài)高度的整個帖子):
UIView-UIScrollView-SinglePostView(自定義視圖)-標(biāo)題-字幕-內(nèi)容
通常要向 UIView 添加單個帖子視圖",我只需將其實例化,將其提供給我的 Post 對象,然后添加一個約束,將 singlePostView 的寬度固定到超級視圖,此時事情會很好地布置.但是,當(dāng)我嘗試將其添加到滾動視圖時,它既不顯示也不滾動.
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 指標(biāo):0 視圖:viewsDictionary]];[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[scrollView]|"選項:0 指標(biāo):0 視圖:viewsDictionary]];[scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[singlePost]|"選項:0 指標(biāo):0 視圖:viewsDictionary]];
在你呈現(xiàn)的結(jié)構(gòu)中,使用 AutoLayout,你的 UIScrollView
的 contentSize
是由intrinsicContentSize
的子視圖,這里是你的 SinglePostView
.
問題是,SinglePostView
是 UIView
的子類,它的 intrinsicContentSize
在考慮時總是 CGSizeZero
本身.您需要做的是使 SinglePostView
的 intrinsicContentSize
依賴于其子視圖的 intrinsicContentSize
.
那么,因為你的 SinglePostView
的子視圖是 UILabels
,并且因為 UILabel
的 intrinsicContentSize
是顯示其內(nèi)容所需的最小尺寸,您的 SinglePostView
的 intrinsicContentSize
將等于其子視圖 intrinsicContentSizes
的總和,即顯示所有三個標(biāo)簽的內(nèi)容所需的總大小.
這里是怎么做的.
第 1 步:刪除所有自動設(shè)置的約束
首先,正如您部分所做的那樣,您需要刪除系統(tǒng)自動設(shè)置的所有約束.
假設(shè)您沒有在情節(jié)提要或 XIB 中設(shè)置任何約束(或者您甚至沒有這些約束),只需執(zhí)行以下操作:
scrollView.translatesAutoresizingMaskIntoConstraints = NO;singlePost.translatesAutoresizingMaskIntoConstraints = NO;titleLabel.translatesAutoresizingMaskIntoConstraints = NO;subtitleLabel.translatesAutoresizingMaskIntoConstraints = NO;contentLabel.translatesAutoresizingMaskIntoConstraints = NO;
現(xiàn)在您有了清晰的計劃,您可以開始設(shè)置自己的約束條件了.
第 2 步:約束 scrollView
首先,讓我們像您一樣創(chuàng)建視圖引用字典以供 AutoLayout 使用:
NSDictionary *views = NSDictionaryOfVariableBindings(scrollView, singlePost, titleLabel, subtitleLabel, contentLabel);
然后,就像你已經(jīng)做過的那樣,讓我們??將滾動視圖限制為其父視圖的大小:
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[scrollView]-0-|"選項:0 指標(biāo):0 意見:意見]];[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[scrollView]-0-|"選項:0 指標(biāo):0 意見:意見]];
第三步:約束SinglePostView
推送scrollView
的contentSize
要清楚這一步,您必須了解 UIScrollView
及其 subviews
之間設(shè)置的每個約束實際上都會改變 contentSize
UIScrollView
,而不是它的實際 bounds
.例如,如果您將 UIImageView
約束到其父 UIScrollView
的邊框,然后將 UIScrollView
大小兩倍的圖像放入 UIImageView
,你的圖像不會被縮小,它的 UIImageView
會占用它的圖像大小并在 UIScrollView
內(nèi)變得可滾動.UIImageViewp>
所以你必須在這里設(shè)置:
[scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[singlePost]-0-|"選項:0 指標(biāo):0 意見:意見]];[scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[singlePost]-0-|"選項:0 指標(biāo):0 意見:意見]];[scrollView addConstraint:[NSLayoutConstraint constraintWithItem:singlePost屬性:NSLayoutAttributeWidthrelatedBy:NSLayoutRelationEqualtoItem:滾動視圖屬性:NSLayoutAttributeWidth乘數(shù):1.0f常數(shù):0.0f]];
前兩個約束非常明顯.然而,第三個在這里是因為,為了讓您的 UILabels
正確顯示其內(nèi)容并且仍然可讀,您可能希望它們是多行的并且滾動是垂直的,而不是水平的.這就是您將 SinglePostView
的 width
設(shè)置為與 scrollView
相同的原因.這樣,您可以防止 scrollView
的 contentSize.width
超出其 bounds.width
.
第 4 步:約束您的 UILabels
以推動"您的 SinglePostView
的邊界第四步,也是最后一步,您現(xiàn)在需要對 SinglePostView
的子視圖設(shè)置約束,以便從它們那里獲得 intrinsicContentSize
.
這是你的做法(最簡單的實現(xiàn),沒有邊距,一個標(biāo)簽一個接一個垂直):
[singlePost addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[titleLabel]-0-|"選項:0 指標(biāo):0 意見:意見]];[singlePost addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[subtitleLabel]-0-|"選項:0 指標(biāo):0 意見:意見]];[singlePost addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[contentLabel]-0-|"選項:0 指標(biāo):0 意見:意見]];[singlePost addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[titleLabel]-0-[subtitleLabel]-[contentLabel]-0-|"選項:0 指標(biāo):0 意見:意見]];
你應(yīng)該完成了.
最后一個建議,你絕對應(yīng)該查看 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.
這篇關(guān)于使用自動布局向 UIScrollView 添加動態(tài)大小的視圖(高度)的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網(wǎng)!