スクロールするコンテンツの高さ(または幅)にUIScrollView
を自動調整する方法はありますか?
何かのようなもの:
[scrollView setContentSize:(CGSizeMake(320, content.height))];
含まれているサブビューに基づいてUIScrollView
のコンテンツサイズを更新するために私がこれまでに出会った中で最高の方法:
Objective-C
CGRect contentRect = CGRectZero;
for (UIView *view in self.scrollView.subviews) {
contentRect = CGRectUnion(contentRect, view.frame);
}
self.scrollView.contentSize = contentRect.size;
スイフト
var contentRect = CGRect.zero
for view in mainScrollView.subviews {
contentRect = contentRect.union(view.frame)
}
mainScrollView.contentSize = contentRect.size
UIScrollViewは、コンテンツの高さを自動的に知りません。自分で高さと幅を計算する必要があります
のようなものでそれを行う
CGFloat scrollViewHeight = 0.0f;
for (UIView* view in scrollView.subviews)
{
scrollViewHeight += view.frame.size.height;
}
[scrollView setContentSize:(CGSizeMake(320, scrollViewHeight))];
しかし、これはビューが上下にある場合にのみ機能します。隣り合わせにビューがある場合、スクローラーのコンテンツを実際より大きく設定したくない場合にのみ、1つの高さを追加する必要があります。
関連するすべてのビューでtranslatesAutoresizingMaskIntoConstraints
をNO
に設定します。
スクロールビューの外部の制約を使用して、スクロールビューの位置とサイズを設定します。
制約を使用してスクロールビュー内にサブビューをレイアウトします、制約がスクロールビューの4つのエッジすべてに結び付けられていることに依存せず、ビューをスクロールしてサイズを取得します。
ソース: 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;
}
以下は、変換するのが面倒な人のためのSwiftで受け入れられている答えです:)
var contentRect = CGRectZero
for view in self.scrollView.subviews {
contentRect = CGRectUnion(contentRect, view.frame)
}
self.scrollView.contentSize = contentRect.size
@leviatanの答えをSwift 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の優れたソリューション。 Swift(関数型プログラミング)アプローチを使用して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)];
基本的に、ビュー内で最も下にある要素を見つけ出し、下部に10ピクセルのパディングを追加します
ScrollViewは他のscrollViewまたは異なる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()
または単に行う:
int y = CGRectGetMaxY(((UIView*)[_scrollView.subviews lastObject]).frame); [_scrollView setContentSize:(CGSizeMake(CGRectGetWidth(_scrollView.frame), y))];
(このソリューションは、このページにコメントとして追加されました。このコメントに対して19の賛成票を得た後、コミュニティのために正式な回答としてこのソリューションを追加することにしました!)
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
使用方法:
View Controllerに.hファイルをインポートするだけで、通常のUIScrollViewインスタンスではなくSBScrollViewインスタンスを宣言します。
Reduceを使用するSwift4の場合:
self.scrollView.contentSize = self.scrollView.subviews.reduce(CGRect.zero, {
return $0.union($1.frame)
}).size
このように動的コンテンツサイズを設定します。
self.scroll_view.contentSize = CGSizeMake(screen_width,CGRectGetMaxY(self.controlname.frame)+20);
サイズは、その中にロードされたコンテンツとクリッピングオプションに依存します。テキストビューの場合、折り返し、テキストの行数、フォントサイズなどにも依存します。自分で計算することはほぼ不可能です。良いニュースは、ビューが読み込まれた後、viewWillAppearで計算されることです。それ以前は、すべて不明であり、コンテンツサイズはフレームサイズと同じです。ただし、viewWillAppearメソッド以降(viewDidAppearなど)では、コンテンツサイズが実際になります。
なぜ単一行のコードではないのですか??
_yourScrollView.contentSize = CGSizeMake(0, _lastView.frame.Origin.y + _lastView.frame.size.height);
これは、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
}
}
また、私はリヴァイアサンの答えが一番うまくいくと思った。しかし、それは奇妙な高さを計算していました。サブビューをループするときに、スクロールビューがスクロールインジケータを表示するように設定されている場合、それらはサブビューの配列になります。この場合、解決策は、ループする前にスクロールインジケータを一時的に無効にしてから、以前の表示設定を再確立することです。
-(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;
}
それは本当にコンテンツに依存します:content.frame.heightはあなたが望むものを与えるかもしれませんか?コンテンツが単一のものなのか、それともコレクションなのかによって異なります。