Jawaban:
Metode terbaik yang pernah saya temui untuk memperbarui ukuran konten UIScrollView
berdasarkan subview yang terkandung:
Objektif-C
CGRect contentRect = CGRectZero;
for (UIView *view in self.scrollView.subviews) {
contentRect = CGRectUnion(contentRect, view.frame);
}
self.scrollView.contentSize = contentRect.size;
Cepat
let contentRect: CGRect = scrollView.subviews.reduce(into: .zero) { rect, view in
rect = rect.union(view.frame)
}
scrollView.contentSize = contentRect.size
UIScrollView tidak mengetahui ketinggian kontennya secara otomatis. Anda harus menghitung tinggi dan lebar untuk diri Anda sendiri
Lakukan dengan sesuatu seperti
CGFloat scrollViewHeight = 0.0f;
for (UIView* view in scrollView.subviews)
{
scrollViewHeight += view.frame.size.height;
}
[scrollView setContentSize:(CGSizeMake(320, scrollViewHeight))];
Tapi ini hanya berfungsi jika pandangannya satu di bawah yang lain. Jika Anda memiliki tampilan di samping satu sama lain, Anda hanya perlu menambahkan ketinggian satu jika Anda tidak ingin mengatur konten scroller lebih besar dari yang sebenarnya.
int y = CGRectGetMaxY(((UIView*)[_scrollView.subviews lastObject]).frame); [_scrollView setContentSize:(CGSizeMake(CGRectGetWidth(_scrollView.frame), y))];
Setel translatesAutoresizingMaskIntoConstraints
ke NO
semua tampilan yang terlibat.
Posisikan dan ukuran tampilan gulir Anda dengan kendala di luar tampilan gulir.
Gunakan batasan untuk meletakkan subview dalam tampilan gulir, pastikan kendala mengikat ke keempat tepi tampilan gulir dan jangan mengandalkan tampilan gulir untuk mendapatkan ukurannya.
Sumber: https://developer.apple.com/library/ios/technotes/tn2154/_index.html
Saya menambahkan ini ke jawaban Espuz dan JCC. Ini menggunakan posisi y dari subview dan tidak termasuk bilah gulir. Edit Menggunakan bagian bawah sub tampilan terendah yang terlihat.
+ (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;
di awal dan self.scrollView.showsHorizontalScrollIndicator = YES;
self.scrollView.showsVerticalScrollIndicator = YES;
di akhir metode?
Inilah jawaban yang diterima dengan cepat untuk siapa saja yang terlalu malas untuk mengonversi itu :)
var contentRect = CGRectZero
for view in self.scrollView.subviews {
contentRect = CGRectUnion(contentRect, view.frame)
}
self.scrollView.contentSize = contentRect.size
Inilah adaptasi Swift 3 dari jawaban @ leviatan:
PERPANJANGAN
import UIKit
extension UIScrollView {
func resizeScrollViewContentSize() {
var contentRect = CGRect.zero
for view in self.subviews {
contentRect = contentRect.union(view.frame)
}
self.contentSize = contentRect.size
}
}
PEMAKAIAN
scrollView.resizeScrollViewContentSize()
Sangat mudah digunakan!
Mengikuti ekstensi akan sangat membantu di 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
}
}
Logikanya sama dengan jawaban yang diberikan. Namun, ini menghilangkan tampilan tersembunyi di dalam UIScrollView
dan perhitungan dilakukan setelah indikator gulir ditetapkan tersembunyi.
Selain itu, ada parameter fungsi opsional dan Anda dapat menambahkan nilai offset dengan meneruskan parameter ke fungsi.
Solusi hebat & terbaik dari @leviathan. Hanya menerjemahkan ke swift menggunakan pendekatan FP (pemrograman fungsional).
self.scrollView.contentSize = self.scrollView.subviews.reduce(CGRect(), {
CGRectUnion($0, $1.frame)
}.size
self.contentSize = self.subviews.reduce(CGRect(), { $0.union($1.frame) }).size
Anda bisa mendapatkan tinggi konten di dalam UIScrollView dengan menghitung anak mana yang "mencapai lebih jauh". Untuk menghitung ini, Anda harus mempertimbangkan asal Y (mulai) dan tinggi barang.
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))];
Dengan melakukan hal-hal seperti ini, item (subview) tidak harus ditumpuk secara langsung di bawah yang lain.
Saya datang dengan solusi lain berdasarkan pada solusi @ 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)];
Pada dasarnya, kami mencari tahu elemen mana yang paling jauh dalam tampilan dan menambahkan padding 10px ke bawah
Karena scrollView dapat memiliki scrollViews lain atau pohon subViews inDepth yang berbeda, jalankan secara mendalam secara rekursif lebih disukai.
Cepat 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)
}
}
Pemakaian
scrollView.recalculateVerticalContentSize_synchronous()
Atau lakukan saja:
int y = CGRectGetMaxY(((UIView*)[_scrollView.subviews lastObject]).frame); [_scrollView setContentSize:(CGSizeMake(CGRectGetWidth(_scrollView.frame), y))];
(Solusi ini ditambahkan oleh saya sebagai komentar di halaman ini. Setelah mendapat 19 suara untuk komentar ini, saya memutuskan untuk menambahkan solusi ini sebagai jawaban resmi untuk kepentingan masyarakat!)
Untuk swift4 menggunakan kurangi:
self.scrollView.contentSize = self.scrollView.subviews.reduce(CGRect.zero, {
return $0.union($1.frame)
}).size
Ukurannya tergantung pada konten yang dimuat di dalamnya, dan opsi kliping. Jika ini adalah tampilan teks, maka itu juga tergantung pada pembungkusnya, berapa banyak baris teks, ukuran font, dan seterusnya. Hampir tidak mungkin bagi Anda untuk menghitung sendiri. Berita baiknya adalah, ini dihitung setelah tampilan dimuat dan di viewWillAppear. Sebelum itu, semua tidak diketahui dan ukuran konten akan sama dengan ukuran bingkai. Namun, dalam metode viewWillAppear dan setelah (seperti viewDidAppear) ukuran konten akan menjadi aktual.
Membungkus kode Richy, saya membuat kelas UIScrollView khusus yang mengotomatisasi pengubahan ukuran konten sepenuhnya!
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
Cara menggunakan:
Cukup impor file .h ke pengontrol tampilan Anda dan nyatakan instance SBScrollView alih-alih yang normal UIScrollView.
Tetapkan ukuran konten dinamis seperti ini.
self.scroll_view.contentSize = CGSizeMake(screen_width,CGRectGetMaxY(self.controlname.frame)+20);
Saya juga menemukan jawaban leviathan untuk bekerja yang terbaik. Namun, itu menghitung ketinggian yang aneh. Saat mengulangi subview, jika scrollview diatur untuk menampilkan indikator scroll, itu akan berada dalam array subview. Dalam hal ini, solusinya adalah untuk menonaktifkan sementara indikator gulir sebelum mengulang, kemudian membangun kembali pengaturan visibilitas sebelumnya.
-(void)adjustContentSizeToFit
adalah metode publik pada subkelas kustom 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;
}
Saya pikir ini bisa menjadi cara yang rapi untuk memperbarui ukuran tampilan konten 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
sehingga autolayout akan selesai, di iOS7 itu bekerja dengan baik, tetapi menguji os iOS6 autolayout karena beberapa alasan tidak menyelesaikan pekerjaan, jadi saya memiliki beberapa nilai ketinggian yang salah, jadi saya beralih keviewDidAppear
sekarang berfungsi dengan baik .. hanya untuk menunjukkan mungkin seseorang akan membutuhkan ini. terima kasih