Відповіді:
Найкращий спосіб, з якого я коли-небудь стикався, щоб оновлювати розмір вмісту на UIScrollView
основі вмісту його підвидів:
Ціль-С
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))];
Але це спрацює лише в тому випадку, якщо погляди розташовуються один під одним. Якщо ви маєте вид один біля одного, вам потрібно додати висоту лише в тому випадку, якщо ви не хочете встановлювати вміст прокрутки більше, ніж є насправді.
int y = CGRectGetMaxY(((UIView*)[_scrollView.subviews lastObject]).frame); [_scrollView setContentSize:(CGSizeMake(CGRectGetWidth(_scrollView.frame), y))];
Встановіть translatesAutoresizingMaskIntoConstraints
для NO
всіх залучених поглядів.
Розмістіть і розміріть свій перегляд прокрутки з обмеженнями, зовнішніми для подання прокрутки.
Використовуйте обмеження, щоб викласти підзагляди у вікні прокрутки, переконуючись, що обмеження прив’язані до всіх чотирьох країв подання прокрутки і не покладаються на вигляд прокрутки, щоб отримати їх розмір.
Джерело: https://developer.apple.com/library/ios/technotes/tn2154/_index.html
Я додав це до відповіді Еспуза та СКК. Він використовує 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;
на початку та self.scrollView.showsHorizontalScrollIndicator = YES;
self.scrollView.showsVerticalScrollIndicator = YES;
в кінці методу?
Ось прийнята відповідь в найкоротші терміни для тих, хто лінивий її конвертувати :)
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. Просто переклад на швидкий, використовуючи FP (функціональне програмування) підхід.
self.scrollView.contentSize = self.scrollView.subviews.reduce(CGRect(), {
CGRectUnion($0, $1.frame)
}.size
self.contentSize = self.subviews.reduce(CGRect(), { $0.union($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 може мати інше scrollViews або інше дерево 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 голосів за цей коментар я вирішив додати це рішення як формальну відповідь на користь громади!)
Для swift4 з використанням зменшення:
self.scrollView.contentSize = self.scrollView.subviews.reduce(CGRect.zero, {
return $0.union($1.frame)
}).size
Розмір залежить від вмісту, завантаженого всередині нього, та варіантів відсікання. Якщо це текстове перегляд, то це також залежить від обгортки, скільки рядків тексту, розміру шрифту тощо. Майже неможливо для вас обчислити себе. Хороша новина в тому, що вона обчислюється після завантаження перегляду і в viewWillAppear. До цього все невідомо, а розмір вмісту буде таким самим, як і розмір кадру. Але в методі viewWillAppear і після (наприклад, viewDidAppear) розмір вмісту буде фактичним.
Обгортаючи код Річі, я створив спеціальний клас 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
Як користуватися:
Просто імпортуйте .h файл у свій контролер перегляду та оголосіть екземпляр SBScrollView замість звичайного UIScrollView.
Встановіть такий динамічний розмір вмісту.
self.scroll_view.contentSize = CGSizeMake(screen_width,CGRectGetMaxY(self.controlname.frame)+20);
Я також знайшов відповідь левіафана, щоб він працював найкраще. Однак він обчислював дивну висоту. Якщо циклічно проглядати підпрогляди, якщо параметр прокрутки встановлений для відображення індикаторів прокрутки, вони будуть знаходитись у масиві підпрезентацій. У цьому випадку рішення полягає в тимчасовому відключенні індикаторів прокрутки перед циклом, а потім відновлення їх попереднього налаштування видимості.
-(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
}
}
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
запускав це, щоб автозапуск закінчився, в iOS7 він працював добре, але тестування OS iOS6 автолайн чомусь не закінчило роботу, тому у мене були неправильні значення висоти, тому я перейшов наviewDidAppear
теперішній час працює добре .. просто зазначити, можливо, комусь це знадобиться. дякую