UIScrollView를 콘텐츠에 맞게 자동 크기 조정하는 방법
만들 방법이 있습니까?UIScrollView
스크롤하는 콘텐츠의 높이(또는 너비)에 맞게 자동 조정하시겠습니까?
다음과 같은 것:
[scrollView setContentSize:(CGSizeMake(320, content.height))];
콘텐츠 크기를 업데이트하는 최고의 방법입니다.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))];
그러나 이것은 보기가 다른 보기보다 낮은 경우에만 작동합니다.보기가 서로 옆에 있는 경우 스크롤러의 내용을 실제보다 크게 설정하지 않으려면 하나의 높이만 추가하면 됩니다.
자동 레이아웃을 사용하는 경우 해결 방법:
트
translatesAutoresizingMaskIntoConstraints
NO
관련된 모든 견해에 관하여스크롤 뷰 외부의 제약 조건으로 스크롤 뷰를 배치하고 크기를 조정합니다.
제약 조건을 사용하여 스크롤 뷰 내의 하위 뷰를 배치합니다. 제약 조건이 스크롤 뷰의 네 모서리에 모두 연결되고 스크롤 뷰에 의존하여 크기를 가져오지 않도록 합니다.
출처: https://developer.apple.com/library/ios/technotes/tn2154/_index.html
저는 이것을 에스푸즈와 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;
}
여기 변환하기 귀찮은 사람들을 위한 신속한 답변이 있습니다 :)
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()
매우 사용하기 쉽습니다!
스위프트에서 다음 연장이 도움이 될 것입니다.
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
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 패딩을 추가합니다.
아니면 그냥 하라:
int y = CGRectGetMaxY(((UIView*)[_scrollView.subviews lastObject]).frame); [_scrollView setContentSize:(CGSizeMake(CGRectGetWidth(_scrollView.frame), y))];
(이 솔루션은 제가 이 페이지의 주석으로 추가한 것입니다.이 의견에 대한 19표의 사전 투표를 받은 후, 저는 커뮤니티의 이익을 위한 공식적인 답변으로 이 솔루션을 추가하기로 결정했습니다!)
ScrollView는 다른 ScrollView를 가질 수도 있고 Depth 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()
swift4의 경우 감소:
self.scrollView.contentSize = self.scrollView.subviews.reduce(CGRect.zero, {
return $0.union($1.frame)
}).size
크기는 내부에 로드된 내용과 클리핑 옵션에 따라 달라집니다.텍스트 보기인 경우에는 래핑, 텍스트 줄 수, 글꼴 크기 등에 따라 달라집니다.스스로 계산하는 것은 거의 불가능합니다.좋은 소식은 보기가 로드되고 WillAppear 보기에서 계산된다는 것입니다.그 전에는 모두 알 수 없으며 내용 크기는 프레임 크기와 같습니다.그러나 WillAppear 메서드 및 그 이후(예: viewDidAppear)에는 내용 크기가 실제 크기가 됩니다.
Richy의 코드를 래핑하여 콘텐츠 크기 조정을 완전히 자동화하는 사용자 정의 UIScrollView 클래스를 만들었습니다!
SBS 크롤뷰.h
@interface SBScrollView : UIScrollView
@end
SBS crollView.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 인스턴스를 선언하기만 하면 됩니다.
왜 코드 한 줄을 사용하지 않습니까?
_yourScrollView.contentSize = CGSizeMake(0, _lastView.frame.origin.y + _lastView.frame.size.height);
는 하위클래만니다습들의 .ScrollView
를 intrinsicContentSize
그리고 그것은 나에게 완벽하게 효과가 있었습니다.
public final class ContentSizedScrollView: UIScrollView {
override public var contentSize: CGSize {
didSet {
invalidateIntrinsicContentSize()
}
}
override public var intrinsicContentSize: CGSize {
layoutIfNeeded()
return self.contentSize
}
}
이제 이 클래스로 스크롤 뷰를 만들고 모든 측면에 제약 조건을 설정할 수 있습니다.
하위 보기가 스크롤의 네 모서리에 모두 연결되어 있는지 확인합니다. 보기
내용에 따라 달라집니다. content.frame.키가 당신이 원하는 것을 줄 수 있습니까?내용이 단일 항목인지 또는 항목 모음인지에 따라 다릅니다.
저는 또한 일을 하기 위한 리바이어던의 대답이 가장 좋다는 것을 발견했습니다.하지만, 그것은 이상한 키를 계산하고 있었습니다.하위 보기를 반복할 때 스크롤 보기가 스크롤 표시기를 표시하도록 설정된 경우 하위 보기 배열에 포함됩니다.이 경우 해결책은 루프하기 전에 스크롤 표시기를 일시적으로 비활성화한 다음 이전 가시성 설정을 다시 설정하는 것입니다.
-(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
}
}
동적 콘텐츠 크기를 다음과 같이 설정합니다.
self.scroll_view.contentSize = CGSizeMake(screen_width,CGRectGetMaxY(self.controlname.frame)+20);
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)
}
}
자동 레이아웃을 사용하는 경우 테두리 요소의 가장자리를 스크롤 보기와 동일하게 설정하면 됩니다.
예를 들어 수평 스크롤 보기에서 수평 내용을 자동으로 맞추려고 합니다.
스위프트
let bottomConstrint = NSLayoutConstraint.init(item: (bottommost UI element),
attribute: .bottom,
relatedBy: .equal,
toItem: (your UIScrollView),
attribute: .bottom,
multiplier: 1.0,
constant: 0)
bottomConstrint.isActive = true
저처럼 Snapkit를 사용하는 경우 다음과 같이 하십시오.
scrollView.addSubview( (bottommost element) )
(bottommost element).snp.makeConstraints { make in
/*other constraints*/
make.bottom.equalToSuperview()
}
class ContentSizedScrollView: UIScrollView {
override var contentSize:CGSize {
didSet {
invalidateIntrinsicContentSize()
}
}
override var intrinsicContentSize: CGSize {
layoutIfNeeded()
return CGSize(width: UIView.noIntrinsicMetric, height: contentSize.height)
}
}
// In UIViewController
import SnapKit
...
var scrollView: ContentSizedScrollView!
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
scrollView.contentSize = .init(width: view.bounds.width, height: stackView.bounds.height)
}
// Here some example of content composing inside of UIStackView
func setupContent() {
scrollView = ContentSizedScrollView()
blockView.addSubview(scrollView)
scrollView.snp.makeConstraints { make in
make.top.equalTo(19)
make.left.equalToSuperview()
make.right.equalToSuperview()
make.bottom.equalTo(-20)
}
scrollView.contentInset = .init(top: 0, left: 0, bottom: 26, right: 0)
scrollView.showsVerticalScrollIndicator = false
scrollView.clipsToBounds = true
scrollView.layer.cornerRadius = blockView.layer.cornerRadius / 2
stackView = UIStackView()
scrollView.addSubview(stackView)
stackView.snp.makeConstraints { make in
make.top.equalToSuperview()
make.centerX.equalToSuperview()
make.width.equalToSuperview().offset(-10)
}
stackView.axis = .vertical
stackView.alignment = .center
textTitleLabel = Label()
stackView.addArrangedSubview(textTitleLabel)
textTitleLabel.snp.makeConstraints { make in
make.width.equalToSuperview().offset(-30)
}
textTitleLabel.font = UIFont.systemFont(ofSize: 20, weight: .bold)
textTitleLabel.textColor = Color.Blue.oxfordBlue
textTitleLabel.textAlignment = .center
textTitleLabel.numberOfLines = 0
stackView.setCustomSpacing(10, after: textTitleLabel)
}
하위 클래스를 만듭니다.UIScrollView
다음을 포함합니다.
class ContentSizedScrollView: UIScrollView {
override var contentSize:CGSize {
didSet {
invalidateIntrinsicContentSize()
}
}
override var intrinsicContentSize: CGSize {
layoutIfNeeded()
return CGSize(width: UIView.noIntrinsicMetric, height: contentSize.height)
}
}
콘텐츠 높이에 따라 크기가 자동으로 조정됩니다.
언급URL : https://stackoverflow.com/questions/2944294/how-do-i-auto-size-a-uiscrollview-to-fit-its-content
'programing' 카테고리의 다른 글
C# 유닛 테스트 시 "내부" 액세스 한정자 (0) | 2023.05.08 |
---|---|
현재 메서드의 이름을 가져옵니다. (0) | 2023.05.08 |
문자열이 0이고 비어 있는지 확인합니다. (0) | 2023.05.08 |
MongoDB - 중첩 배열의 개체 업데이트 (0) | 2023.05.08 |
Python 3.4 비동기 코드를 테스트하는 방법은 무엇입니까? (0) | 2023.05.08 |