UIScrollview
について質問がありました。
ストーリーは、ChartsViewという名前のUIView
があり、それをオーバーライドメソッドdrawRect()
によって自分で再描画することです。描画のコンテンツは動的に生成されました。そのため、実行時までそのサイズはわかりません。問題は、スーパービュー(scrollView)のコンテンツサイズをどのように/どこで動的に設定できますか?
- (void)viewDidLoad
{
[super viewDidLoad];
// not this way. it's fixed size.....
ChartsView *chartsView = [[ChartsView alloc]initWithFrame:CGRectMake(0, 0, 320, 800)];
self.scrollView.contentSize = chartsView.frame.size;
[self.scrollView addSubview:chartsView];
}
もう1つの簡単な方法
- (void)viewDidLoad
{
float sizeOfContent = 0;
UIView *lLast = [scrollView.subviews lastObject];
NSInteger wd = lLast.frame.Origin.y;
NSInteger ht = lLast.frame.size.height;
sizeOfContent = wd+ht;
scrollView.contentSize = CGSizeMake(scrollView.frame.size.width, sizeOfContent);
}
ScrollView.subviews配列の最後のオブジェクトがスクロールビューで最も高いy-Originオブジェクトを返すことは100%保証されていません。サブビュー配列はZ-Indexによって配列されます(つまり、サブビュー配列の最後のオブジェクトは、一番上にスタックされ、スクロールビューのサブビューの一番上のサブビューになります。代わりに、基本的な並べ替え関数を使用する方が正確です)サブビューを反復処理し、y-Originが最も高いオブジェクトを取得します。
Swift 4
extension UIScrollView {
func updateContentView() {
contentSize.height = subviews.sorted(by: { $0.frame.maxY < $1.frame.maxY }).last?.frame.maxY ?? contentSize.height
}
}
使用法(viewDidLayoutSubviews
内、またはコンテンツサイズが更新されるたび):
myScrollView.updateContentView()
Swift(2.0)
@IBOutlet weak var btnLatestButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
let height = btnLatestButton.frame.size.height
let pos = btnLatestButton.frame.Origin.y
let sizeOfContent = height + pos + 10
scrollview.contentSize.height = sizeOfContent
}
もちろん、スクロールビューに表示されるビューの数が決まっている場合です。 IOS Rocksメソッドは利用可能ですが、私にとっては良くありませんでした。必要以上のスペースを作成しました。
let lastView : UIView! = scrollview.subviews.last
let height = lastView.frame.size.height
let pos = lastView.frame.Origin.y
let sizeOfContent = height + pos + 10
scrollview.contentSize.height = sizeOfContent
IOS Rocks and CularBytesのおかげで、これについてのリードが得られました。上記のソリューションには2つの問題(私にとって)が見つかりました。
また、UIScrollViewの側面を固定するために自動レイアウトを使用しているため、幅(CularBytesのように)を心配する必要はありません。
ここに私が思いついたものがあります(Swift 3.0)):
_func setScrollViewContentSize() {
var height: CGFloat
let lastView = self.myScrollView.subviews[0].subviews.last!
print(lastView.debugDescription) // should be what you expect
let lastViewYPos = lastView.convert(lastView.frame.Origin, to: nil).y // this is absolute positioning, not relative
let lastViewHeight = lastView.frame.size.height
// sanity check on these
print(lastViewYPos)
print(lastViewHeight)
height = lastViewYPos + lastViewHeight
print("setting scroll height: \(height)")
myScrollView.contentSize.height = height
}
_
viewDidAppear()
メソッドでこれを呼び出します。
override func viewDidAppear(_ animated: Bool) {
var height: CGFloat
let lastView = self.scrollView.subviews[0].subviews.last!
let lastViewYPos = lastView.convert(lastView.frame.Origin, to: nil).y
let lastViewHeight = lastView.frame.size.height
height = lastViewYPos + lastViewHeight
scrollView.contentSize.height = height
}
これを試して -
- (void)viewDidLoad
{
[super viewDidLoad];
// not this way. it's fixed size.....
ChartsView *chartsView = [[ChartsView alloc]initWithFrame:CGRectMake(0, 0, 320, 800)];
//self.scrollView.contentSize = chartsView.frame.size;
[self.scrollView setContentSize:CGSizeMake(chartsView.frame.size.width, chartsView.frame.size.height)];
[self.scrollView addSubview:chartsView];
}
これを試して
- (void)viewDidLoad
{
[super viewDidLoad];
// not this way. it's fixed size.....
ChartsView *chartsView = [[ChartsView alloc]initWithFrame:CGRectMake(0, 0, 320, 800)];
self.scrollView.contentSize = chartsView.frame.size;
[self.scrollView setNeedsDisplay];
[self.scrollView addSubview:chartsView];
}
UIScrollview contentSizeを動的に計算します(サブビューフレームに依存)
迅速:
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;
});
}
これは、Swift 3
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 + 100)
contentSize = newSize
}
}
ストーリーボードでスクロールビューを使用する場合、コンテンツのサイズを静的な値でプログラムで指定するよりも、スクロールビューに存在するビューの数に応じてコンテンツのサイズを計算する方が適切です。コンテンツサイズを動的に取得する手順は次のとおりです。
ステップ1:Scrollviewを追加してストーリーボードに表示し、先頭、末尾、上部および下部の制約を追加します(すべての値はゼロです)。
ステップ2:直接scrollviewで必要なビューを直接追加しないでください。最初に1つのビューをscrollviewに追加します(すべてのUIのコンテンツビューになります)要素)。このビューに以下の制約を追加します。先頭、末尾、上部および下部の制約(すべての値はゼロです)。メインビュー(つまり、スクロールビューを含む)に同じ高さ、同じ幅を追加します。高さが等しい場合は、優先度を低に設定します。 (これは、コンテンツサイズを設定するための重要な手順です)。このコンテンツビューの高さは、ビューに追加されたビューの数に応じて決まります。最後に追加したビューが1つのラベルで、Yの位置が420、高さが20の場合、コンテンツビューは440になります。
ステップ3:要件に従ってコンテンツビュー内に追加したすべてのビューに制約を追加します。