[英]Auto layout UIScrollView with subviews with dynamic heights
使用自動布局約束我遇到了UIScrollView的麻煩。 我有以下視圖層次結構,通過IB設置約束:
- ScrollView (leading, trailing, bottom and top spaces to superview)
-- ContainerView (leading, trailing, bottom and top spaces to superview)
--- ViewA (full width, top of superview)
--- ViewB (full width, below ViewA)
--- Button (full width, below ViewB)
ViewA和ViewB的初始高度為200點,但可以通過單擊將其垂直擴展到400點的高度。 ViewA和ViewB通過更新其高度約束(從200到400)進行擴展。 這是相應的片段:
if(self.contentVisible) {
heightConstraint.constant -= ContentHeight;
// + additional View's internal constraints update to hide additional content
self.contentVisible = NO;
} else {
heightConstraint.constant += ContentHeight;
// + additional View's internal constraints update to show additional content
self.contentVisible = YES;
}
[self.view setNeedsUpdateConstraints];
[UIView animateWithDuration:.25f animations:^{
[self.view layoutIfNeeded];
}];
我的問題是,如果兩個視圖都被擴展,我需要能夠滾動查看整個內容,現在滾動不起作用。 如何使用約束來更新滾動視圖以反映ViewA和ViewB高度的變化?
到目前為止,我能想到的唯一解決方案是在動畫后手動設置ContainerView的高度,這將是ViewA + ViewB + Button高度的總和。 但我相信還有更好的解決方案嗎?
謝謝
我使用如下的純結構
-view
-scrollView
-view A
-view B
-Button
確保Button( 最后一個視圖 )有一個約束(從底部到superview的垂直間距,即scrollview),在這種情況下,無論你的視圖A和視圖B有什么變化,scrollView的高度都會相應地改變。
我參考了這個偉大的在線圖書網站 。
只需閱讀“創建滾動視圖”部分,您應該有一個想法。
我有類似的問題,我正在創建一個詳細信息視圖和使用Interface Builder與Auto布局是一個非常適合任務!
祝好運!
(其他資源:
iOS 6有一個發行說明,討論了UIScrollView的Auto Layout支持。
關於滾動視圖的免費在線iOS書籍說明 。 這實際上對我幫助很大!
假設我們有這樣的層次結構(Label1是ContentView的子視圖; ContentView是ScrollView的子視圖,ScrollView是viewcontroller視圖的子視圖):
ViewController's View ScrollView ContentView Label1 Label2 Label3
ScrollView以與viewcontroller視圖正常的方式使用autolayout進行約束。
ContentView被固定在scrollview的頂部/左側/右側/底部。 這意味着你有一些約束使ContentView的上/下/前/后邊緣被約束為等於ScrollView上的相同邊。 這是一個關鍵:這些約束是針對ScrollView的contentSize,而不是它的框架大小,如viewcontroller的視圖所示。 因此,它不會告訴ContentView與顯示的ScrollView框架具有相同的框架大小,而是告訴Scrollview ContentView是其內容,因此如果contentview大於ScrollView框架,那么您可以滾動,就像設置scrollView.contentSize更大而scrollView.frame使內容可滾動。
這是另一個關鍵:現在你必須在ContentView,Label1-3和Scrollview之外的任何其他東西之間有足夠的約束,以便ContentView能夠從這些約束中找出它的寬度和高度。
因此,例如,如果您需要垂直滾動的標簽集,則設置約束以使ContentView寬度等於ViewController視圖的寬度,該寬度負責寬度。 為了處理高度,將Label1頂部固定到ContentView頂部,將Label2頂部固定到Label1底部,將Label3頂部固定到Label2底部,最后(並且重要的是)將Label3的底部固定到ContentView的底部。 現在它有足夠的信息來計算ContentView的高度。
我希望這給某人一個線索,因為我閱讀了上面的帖子,仍然無法弄清楚如何正確地使ContentView的寬度和高度限制。 我缺少的是將Label3的底部固定在ContentView的底部,否則ContentView如何知道它有多高(因為Label3將會浮動,並且沒有約束告訴ContentView它的底部y位置在哪里)。
這是我如何使用容器視圖布局純自動布局UIScrollView的示例。 我評論說要更清楚:
容器是標准的UIView,而body是UITextView
- (void)viewDidLoad
{
[super viewDidLoad];
//add scrollview
[self.view addSubview:self.scrollView];
//add container view
[self.scrollView addSubview:self.container];
//body as subview of container (body size is undetermined)
[self.container addSubview:self.body];
NSDictionary *views = @{@"scrollView" : self.scrollView, @"container" : self.container, @"body" : self.body};
NSDictionary *metrics = @{@"margin" : @(100)};
//constrain scrollview to superview, pin all edges
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[scrollView]|" options:kNilOptions metrics:metrics views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[scrollView]|" options:kNilOptions metrics:metrics views:views]];
//pin all edges of the container view to the scrollview (i've given it a horizonal margin as well for my purposes)
[self.scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[container]|" options:kNilOptions metrics:metrics views:views]];
[self.scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-margin-[container]-margin-|" options:kNilOptions metrics:metrics views:views]];
//the container view must have a defined width OR height, here i am constraining it to the frame size of the scrollview, not its bounds
//the calculation for constant is so that it's the width of the scrollview minus the margin * 2
[self.scrollView addConstraint:[NSLayoutConstraint constraintWithItem:self.container attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self.scrollView attribute:NSLayoutAttributeWidth multiplier:1.0f constant:-([metrics[@"margin"] floatValue] * 2)]];
//now as the body grows vertically it will force the container to grow because it's trailing edge is pinned to the container's bottom edge
//it won't grow the width because the container's width is constrained to the scrollview's frame width
[self.container addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[body]|" options:kNilOptions metrics:metrics views:views]];
[self.container addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[body]|" options:kNilOptions metrics:metrics views:views]];
}
在我的例子中,'body'是一個UITextView,但它可能是其他任何東西。 如果您正好使用UITextView,請注意,為了使其垂直增長,它必須具有在viewDidLayoutSubviews中設置的高度約束。 所以在viewDidLoad中添加以下約束並保持對它的引用:
self.bodyHeightConstraint = [NSLayoutConstraint constraintWithItem:self.body attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:nil multiplier:1.0f constant:100.0f];
[self.container addConstraint:self.bodyHeightConstraint];
然后在viewDidLayoutSubviews中計算高度並更新約束的常量:
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
[self.bodyHeightConstraint setConstant:[self.body sizeThatFits:CGSizeMake(self.container.width, CGFLOAT_MAX)].height];
[self.view layoutIfNeeded];
}
需要第二個布局傳遞來調整UITextView的大小。
使用此代碼。 ScrollView setContentSize應該在主線程中調用async。
迅速:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
DispatchQueue.main.async {
var contentRect = CGRect.zero
for view in self.scrollView.subviews {
contentRect = contentRect.union(view.frame)
}
self.scrollView.contentSize = contentRect.size
}
}
目標C:
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
dispatch_async(dispatch_get_main_queue(), ^ {
CGRect contentRect = CGRectZero;
for(UIView *view in scrollView.subviews)
contentRect = CGRectUnion(contentRect,view.frame);
scrollView.contentSize = contentRect.size;
});
}
滾動視圖每時每刻都應該知道其內容大小。 內容大小是從scrollview的子視圖推斷出來的。 將控制器屬性映射到描述子視圖高度的xib文件中的約束非常方便。 然后在代碼(動畫塊)中,您可以只更改這些約束屬性的常量。 如果需要更改整個約束,請保留對它的引用,以便稍后可以在父容器中更新它。
我的滾動視圖變體! Dynamic
! 高度:
1)將scroll view
添加到您的UIView
。 固定所有(頂部,底部,引導,軌跡)約束。
2)將UIView
添加到Scroll View
。 固定所有(頂部,底部,引導,軌跡)約束。 它將是您的Content view
。 您也可以重命名它。
3)控制從Content view
拖動到Scroll view
- Equal width
4)向UIView
添加內容。 設置所需的約束。 和! 在較低的項目添加底部約束不 Greater or equal
( >=
)(像大多數人談話) 但是 Equal
! 例如,將其設置為20
。
在我的情況下,我在內容中有UIImageView
。 我把它的height
連接到代碼。 如果我將其更改為1000
,則滾動顯示。 一切正常。
對我來說就像一個魅力。 有任何問題 - 歡迎提出意見。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.