답변:
UIScrollView
포함 된 하위보기를 기반으로 콘텐츠의 크기를 업데이트하기 위해 내가 찾은 가장 좋은 방법은 다음과 같습니다.
목표 -C
CGRect contentRect = CGRectZero;
for (UIView *view in self.scrollView.subviews) {
contentRect = CGRectUnion(contentRect, view.frame);
}
self.scrollView.contentSize = contentRect.size;
빠른
let contentRect: CGRect = scrollView.subviews.reduce(into: .zero) { rect, view in
rect = rect.union(view.frame)
}
scrollView.contentSize = contentRect.size
UIScrollView는 내용의 높이를 자동으로 알지 못합니다. 스스로 높이와 너비를 계산해야합니다
다음과 같이하십시오.
CGFloat scrollViewHeight = 0.0f;
for (UIView* view in scrollView.subviews)
{
scrollViewHeight += view.frame.size.height;
}
[scrollView setContentSize:(CGSizeMake(320, scrollViewHeight))];
그러나 이것은 뷰가 서로 아래에있는 경우에만 작동합니다. 서로 옆에보기가있는 경우 스크롤러의 내용을 실제보다 크게 설정하지 않으려면 높이를 추가해야합니다.
int y = CGRectGetMaxY(((UIView*)[_scrollView.subviews lastObject]).frame); [_scrollView setContentSize:(CGSizeMake(CGRectGetWidth(_scrollView.frame), y))];
설정 translatesAutoresizingMaskIntoConstraints
에 NO
관련된 모든 뷰에.
스크롤보기 외부의 제약 조건으로 스크롤보기를 배치하고 크기를 조정하십시오.
제한 조건을 사용하여 스크롤보기 내에 서브 뷰를 배치하십시오. 제한 조건이 스크롤보기의 네 모서리 모두에 연결되고 스크롤보기에 의존하여 크기를 확보하지 않아야합니다.
출처 : https://developer.apple.com/library/ios/technotes/tn2154/_index.html
나는 이것을 Espuz와 JCC의 답변에 추가했습니다. 서브 뷰의 y 위치를 사용하며 스크롤 막대를 포함하지 않습니다. 편집 표시되는 가장 낮은 하위 뷰의 맨 아래를 사용합니다.
+ (CGFloat) bottomOfLowestContent:(UIView*) view
{
CGFloat lowestPoint = 0.0;
BOOL restoreHorizontal = NO;
BOOL restoreVertical = NO;
if ([view respondsToSelector:@selector(setShowsHorizontalScrollIndicator:)] && [view respondsToSelector:@selector(setShowsVerticalScrollIndicator:)])
{
if ([(UIScrollView*)view showsHorizontalScrollIndicator])
{
restoreHorizontal = YES;
[(UIScrollView*)view setShowsHorizontalScrollIndicator:NO];
}
if ([(UIScrollView*)view showsVerticalScrollIndicator])
{
restoreVertical = YES;
[(UIScrollView*)view setShowsVerticalScrollIndicator:NO];
}
}
for (UIView *subView in view.subviews)
{
if (!subView.hidden)
{
CGFloat maxY = CGRectGetMaxY(subView.frame);
if (maxY > lowestPoint)
{
lowestPoint = maxY;
}
}
}
if ([view respondsToSelector:@selector(setShowsHorizontalScrollIndicator:)] && [view respondsToSelector:@selector(setShowsVerticalScrollIndicator:)])
{
if (restoreHorizontal)
{
[(UIScrollView*)view setShowsHorizontalScrollIndicator:YES];
}
if (restoreVertical)
{
[(UIScrollView*)view setShowsVerticalScrollIndicator:YES];
}
}
return lowestPoint;
}
self.scrollView.showsHorizontalScrollIndicator = NO;
self.scrollView.showsVerticalScrollIndicator = NO;
의 시작과 self.scrollView.showsHorizontalScrollIndicator = YES;
self.scrollView.showsVerticalScrollIndicator = YES;
끝 에서 왜 했 습니까?
너무 게으른 사람이라면 누구나 신속하게 받아 들일 수있는 대답입니다 :)
var contentRect = CGRectZero
for view in self.scrollView.subviews {
contentRect = CGRectUnion(contentRect, view.frame)
}
self.scrollView.contentSize = contentRect.size
@leviatan의 답변에 대한 스위프트 3의 적응은 다음과 같습니다.
신장
import UIKit
extension UIScrollView {
func resizeScrollViewContentSize() {
var contentRect = CGRect.zero
for view in self.subviews {
contentRect = contentRect.union(view.frame)
}
self.contentSize = contentRect.size
}
}
용법
scrollView.resizeScrollViewContentSize()
사용하기 매우 편리합니다!
다음 확장은 Swift 에서 도움이 될 것입니다 .
extension UIScrollView{
func setContentViewSize(offset:CGFloat = 0.0) {
// dont show scroll indicators
showsHorizontalScrollIndicator = false
showsVerticalScrollIndicator = false
var maxHeight : CGFloat = 0
for view in subviews {
if view.isHidden {
continue
}
let newHeight = view.frame.origin.y + view.frame.height
if newHeight > maxHeight {
maxHeight = newHeight
}
}
// set content size
contentSize = CGSize(width: contentSize.width, height: maxHeight + offset)
// show scroll indicators
showsHorizontalScrollIndicator = true
showsVerticalScrollIndicator = true
}
}
논리는 주어진 답변과 동일합니다. 그러나 숨겨진 표시를 생략하고 UIScrollView
스크롤 표시기가 숨김으로 설정된 후에 계산이 수행됩니다.
또한 선택적 기능 매개 변수가 있으며 매개 변수를 함수에 전달하여 오프셋 값을 추가 할 수 있습니다.
@leviathan의 훌륭하고 최상의 솔루션. FP (기능 프로그래밍) 접근 방식을 사용하여 신속하게 번역합니다.
self.scrollView.contentSize = self.scrollView.subviews.reduce(CGRect(), {
CGRectUnion($0, $1.frame)
}.size
self.contentSize = self.subviews.reduce(CGRect(), { $0.union($1.frame) }).size
UIScrollView 내에서 컨텐츠의 높이를 얻을 수 있으며 "자식에 도달하는"하위를 계산할 수 있습니다. 이를 계산하려면 원점 Y (시작)와 항목 높이를 고려해야합니다.
float maxHeight = 0;
for (UIView *child in scrollView.subviews) {
float childHeight = child.frame.origin.y + child.frame.size.height;
//if child spans more than current maxHeight then make it a new maxHeight
if (childHeight > maxHeight)
maxHeight = childHeight;
}
//set content size
[scrollView setContentSize:(CGSizeMake(320, maxHeight))];
이런 식으로 작업을 수행하면 항목 (하위 뷰)을 서로 직접 쌓을 필요가 없습니다.
@emenegro의 솔루션을 기반으로 한 다른 솔루션을 생각해 냈습니다.
NSInteger maxY = 0;
for (UIView* subview in scrollView.subviews)
{
if (CGRectGetMaxY(subview.frame) > maxY)
{
maxY = CGRectGetMaxY(subview.frame);
}
}
maxY += 10;
[scrollView setContentSize:CGSizeMake(scrollView.frame.size.width, maxY)];
기본적으로 뷰에서 가장 아래에있는 요소를 찾아 바닥에 10px 패딩을 추가합니다.
scrollView는 다른 scrollViews 또는 다른 inDepth subViews 트리를 가질 수 있으므로 반복적으로 깊이 실행하는 것이 좋습니다.
스위프트 2
extension UIScrollView {
//it will block the mainThread
func recalculateVerticalContentSize_synchronous () {
let unionCalculatedTotalRect = recursiveUnionInDepthFor(self)
self.contentSize = CGRectMake(0, 0, self.frame.width, unionCalculatedTotalRect.height).size;
}
private func recursiveUnionInDepthFor (view: UIView) -> CGRect {
var totalRect = CGRectZero
//calculate recursevly for every subView
for subView in view.subviews {
totalRect = CGRectUnion(totalRect, recursiveUnionInDepthFor(subView))
}
//return the totalCalculated for all in depth subViews.
return CGRectUnion(totalRect, view.frame)
}
}
용법
scrollView.recalculateVerticalContentSize_synchronous()
reduce를 사용하는 swift4의 경우 :
self.scrollView.contentSize = self.scrollView.subviews.reduce(CGRect.zero, {
return $0.union($1.frame)
}).size
Richy의 코드 감싸기 컨텐츠 크기 조정을 완전히 자동화하는 사용자 정의 UIScrollView 클래스를 작성했습니다!
SBScrollView.h
@interface SBScrollView : UIScrollView
@end
SBScrollView.m :
@implementation SBScrollView
- (void) layoutSubviews
{
CGFloat scrollViewHeight = 0.0f;
self.showsHorizontalScrollIndicator = NO;
self.showsVerticalScrollIndicator = NO;
for (UIView* view in self.subviews)
{
if (!view.hidden)
{
CGFloat y = view.frame.origin.y;
CGFloat h = view.frame.size.height;
if (y + h > scrollViewHeight)
{
scrollViewHeight = h + y;
}
}
}
self.showsHorizontalScrollIndicator = YES;
self.showsVerticalScrollIndicator = YES;
[self setContentSize:(CGSizeMake(self.frame.size.width, scrollViewHeight))];
}
@end
사용 방법 :
.h 파일을 뷰 컨트롤러로 가져 와서 일반적인 UIScrollView 인스턴스 대신 SBScrollView 인스턴스를 선언하면됩니다.
또한 최선을 다하는 leviathan의 답변을 찾았습니다. 그러나 그것은 이상한 높이를 계산하고있었습니다. 서브 뷰를 반복 할 때 스크롤 뷰가 스크롤 표시기를 표시하도록 설정된 경우 서브 뷰 배열에있게됩니다. 이 경우 해결책은 반복하기 전에 스크롤 표시기를 일시적으로 비활성화 한 다음 이전 가시성 설정을 다시 설정하는 것입니다.
-(void)adjustContentSizeToFit
UIScrollView의 사용자 정의 서브 클래스에 대한 공용 메소드입니다.
-(void)awakeFromNib {
dispatch_async(dispatch_get_main_queue(), ^{
[self adjustContentSizeToFit];
});
}
-(void)adjustContentSizeToFit {
BOOL showsVerticalScrollIndicator = self.showsVerticalScrollIndicator;
BOOL showsHorizontalScrollIndicator = self.showsHorizontalScrollIndicator;
self.showsVerticalScrollIndicator = NO;
self.showsHorizontalScrollIndicator = NO;
CGRect contentRect = CGRectZero;
for (UIView *view in self.subviews) {
contentRect = CGRectUnion(contentRect, view.frame);
}
self.contentSize = contentRect.size;
self.showsVerticalScrollIndicator = showsVerticalScrollIndicator;
self.showsHorizontalScrollIndicator = showsHorizontalScrollIndicator;
}
UIScrollView의 내용보기 크기를 업데이트하는 깔끔한 방법 일 수 있다고 생각합니다.
extension UIScrollView {
func updateContentViewSize() {
var newHeight: CGFloat = 0
for view in subviews {
let ref = view.frame.origin.y + view.frame.height
if ref > newHeight {
newHeight = ref
}
}
let oldSize = contentSize
let newSize = CGSize(width: oldSize.width, height: newHeight + 20)
contentSize = newSize
}
}
import UIKit
class DynamicSizeScrollView: UIScrollView {
var maxHeight: CGFloat = UIScreen.main.bounds.size.height
var maxWidth: CGFloat = UIScreen.main.bounds.size.width
override func layoutSubviews() {
super.layoutSubviews()
if !__CGSizeEqualToSize(bounds.size,self.intrinsicContentSize){
self.invalidateIntrinsicContentSize()
}
}
override var intrinsicContentSize: CGSize {
let height = min(contentSize.height, maxHeight)
let width = min(contentSize.height, maxWidth)
return CGSize(width: width, height: height)
}
}
viewDidLayoutSubviews
자동 레이아웃이 완료되도록 iOS7에서 잘 작동했지만 iOS6을 테스트하면 어떤 이유로 든 자동 레이아웃이 작업을 완료하지 못하여 높이 값이 잘못되었으므로 이제는 제대로viewDidAppear
작동합니다. 누군가가 이것을 필요로 할 것이라고 지적하기 위해. 감사합니다