Câu trả lời:
Phương pháp tốt nhất tôi từng gặp để cập nhật kích thước nội dung UIScrollView
dựa trên các cuộc phỏng vấn có trong đó:
Mục tiêu-C
CGRect contentRect = CGRectZero;
for (UIView *view in self.scrollView.subviews) {
contentRect = CGRectUnion(contentRect, view.frame);
}
self.scrollView.contentSize = contentRect.size;
Nhanh
let contentRect: CGRect = scrollView.subviews.reduce(into: .zero) { rect, view in
rect = rect.union(view.frame)
}
scrollView.contentSize = contentRect.size
UIScrollView không tự động biết chiều cao của nội dung. Bạn phải tính toán chiều cao và chiều rộng cho mình
Làm điều đó với một cái gì đó như
CGFloat scrollViewHeight = 0.0f;
for (UIView* view in scrollView.subviews)
{
scrollViewHeight += view.frame.size.height;
}
[scrollView setContentSize:(CGSizeMake(320, scrollViewHeight))];
Nhưng cái này chỉ hoạt động nếu các khung nhìn nằm dưới cái kia. Nếu bạn có chế độ xem cạnh nhau, bạn chỉ phải thêm chiều cao của một nếu bạn không muốn đặt nội dung của thanh cuộn lớn hơn thực tế.
int y = CGRectGetMaxY(((UIView*)[_scrollView.subviews lastObject]).frame); [_scrollView setContentSize:(CGSizeMake(CGRectGetWidth(_scrollView.frame), y))];
Đặt translatesAutoresizingMaskIntoConstraints
thành NO
trên tất cả các quan điểm liên quan.
Vị trí và kích thước chế độ xem cuộn của bạn với các ràng buộc bên ngoài đối với chế độ xem cuộn.
Sử dụng các ràng buộc để bố trí các khung nhìn trong chế độ xem cuộn, đảm bảo rằng các ràng buộc đó buộc vào tất cả bốn cạnh của chế độ xem cuộn và không dựa vào chế độ xem cuộn để có kích thước của chúng.
Nguồn: https://developer.apple.com/l Library / ios / technotes / tn2154 / _index.html
Tôi đã thêm nó vào câu trả lời của Espuz và JCC. Nó sử dụng vị trí y của các cuộc phỏng vấn và không bao gồm các thanh cuộn. Chỉnh sửa Sử dụng dưới cùng của chế độ xem phụ thấp nhất có thể nhìn thấ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;
trong đầu và self.scrollView.showsHorizontalScrollIndicator = YES;
self.scrollView.showsVerticalScrollIndicator = YES;
cuối phương pháp?
Đây là câu trả lời được chấp nhận trong swift cho bất cứ ai quá lười biếng để chuyển đổi nó :)
var contentRect = CGRectZero
for view in self.scrollView.subviews {
contentRect = CGRectUnion(contentRect, view.frame)
}
self.scrollView.contentSize = contentRect.size
Đây là bản phóng tác Swift 3 của câu trả lời của @ leviatan:
SỰ MỞ RỘNG
import UIKit
extension UIScrollView {
func resizeScrollViewContentSize() {
var contentRect = CGRect.zero
for view in self.subviews {
contentRect = contentRect.union(view.frame)
}
self.contentSize = contentRect.size
}
}
SỬ DỤNG
scrollView.resizeScrollViewContentSize()
Rất dễ sử dụng!
Phần mở rộng sau sẽ hữu ích trong 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
}
}
Logic là giống nhau với các câu trả lời nhất định. Tuy nhiên, Nó bỏ qua các chế độ xem ẩn bên trong UIScrollView
và tính toán được thực hiện sau khi các chỉ báo cuộn được đặt ẩn.
Ngoài ra, có một tham số chức năng tùy chọn và bạn có thể thêm giá trị bù bằng cách chuyển tham số cho hàm.
Giải pháp tuyệt vời và tốt nhất từ @leviathan. Chỉ cần dịch sang swift bằng cách sử dụng phương pháp tiếp cận FP (lập trình chức năng).
self.scrollView.contentSize = self.scrollView.subviews.reduce(CGRect(), {
CGRectUnion($0, $1.frame)
}.size
self.contentSize = self.subviews.reduce(CGRect(), { $0.union($1.frame) }).size
Bạn có thể lấy chiều cao của nội dung bên trong UIScrollView bằng cách tính toán đứa trẻ nào "đạt đến điểm số". Để tính toán điều này, bạn phải xem xét nguồn gốc Y (bắt đầu) và chiều cao vật phẩm.
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))];
Bằng cách thực hiện mọi thứ theo cách này, các mục (phỏng vấn) không cần phải được xếp chồng trực tiếp lên nhau.
Tôi đã đưa ra một giải pháp khác dựa trên giải pháp của @ emlahoma
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)];
Về cơ bản, chúng tôi tìm ra phần tử nào nằm xa nhất trong chế độ xem và thêm phần đệm 10px ở phía dưới
Bởi vì một scrollView có thể có các scrollView khác hoặc cây subViews inDepth khác, nên chạy theo chiều sâu đệ quy là thích hợp hơn.
Swift 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)
}
}
Sử dụng
scrollView.recalculateVerticalContentSize_synchronous()
Hoặc chỉ cần làm:
int y = CGRectGetMaxY(((UIView*)[_scrollView.subviews lastObject]).frame); [_scrollView setContentSize:(CGSizeMake(CGRectGetWidth(_scrollView.frame), y))];
(Giải pháp này đã được tôi thêm vào dưới dạng nhận xét trong trang này. Sau khi nhận được 19 phiếu bầu cho nhận xét này, tôi đã quyết định thêm giải pháp này làm câu trả lời chính thức vì lợi ích của cộng đồng!)
Đối với swift4 sử dụng giảm:
self.scrollView.contentSize = self.scrollView.subviews.reduce(CGRect.zero, {
return $0.union($1.frame)
}).size
Kích thước tùy thuộc vào nội dung được tải bên trong nó và các tùy chọn cắt. Nếu nó là một textview, thì nó cũng phụ thuộc vào gói, bao nhiêu dòng văn bản, kích thước phông chữ, vân vân và vân vân. Gần như không thể để bạn tự tính toán. Tin tốt là, nó được tính toán sau khi chế độ xem được tải và trong viewWillAppear. Trước đó, tất cả đều chưa biết và kích thước nội dung sẽ giống với kích thước khung. Nhưng, trong phương thức viewWillAppear và sau (như viewDidAppear), kích thước nội dung sẽ là thực tế.
Gói mã của Richy Tôi đã tạo một lớp UIScrollView tùy chỉnh tự động thay đổi kích thước nội dung hoàn toàn!
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
Cách sử dụng:
Chỉ cần nhập tệp .h vào trình điều khiển xem của bạn và khai báo một phiên bản SBScrollView thay vì UIScrollView thông thường.
Đặt kích thước nội dung động như thế này.
self.scroll_view.contentSize = CGSizeMake(screen_width,CGRectGetMaxY(self.controlname.frame)+20);
Tôi cũng tìm thấy câu trả lời của leviathan để làm việc tốt nhất. Tuy nhiên, nó đã tính được một chiều cao kỳ lạ. Khi lặp qua các cuộc phỏng vấn, nếu cuộn xem được đặt để hiển thị các chỉ báo cuộn, chúng sẽ nằm trong mảng các cuộc phỏng vấn. Trong trường hợp này, giải pháp là tạm thời vô hiệu hóa các chỉ báo cuộn trước khi lặp, sau đó thiết lập lại cài đặt hiển thị trước đó của chúng.
-(void)adjustContentSizeToFit
là một phương thức công khai trên một lớp con tùy chỉnh của 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;
}
Tôi nghĩ rằng đây có thể là một cách gọn gàng để cập nhật kích thước chế độ xem nội dung của 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
để tự động thanh toán sẽ kết thúc, trong iOS7 nó hoạt động tốt, nhưng thử nghiệm os iOS6 tự động thanh toán vì một số lý do không hoàn thành công việc, vì vậy tôi có một số giá trị chiều cao sai, vì vậy tôi đã chuyển sangviewDidAppear
hoạt động tốt .. chỉ để chỉ ra có lẽ ai đó sẽ cần điều này. cảm ơn